2014-09-11 18:10:19 +02:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2023-01-28 10:16:34 +01:00
* Copyright ( C ) 2007 - 2023 Cppcheck team .
2014-09-11 18:10:19 +02:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checktype.h"
2017-05-27 04:33:47 +02:00
2022-01-27 19:03:20 +01:00
# include "errortypes.h"
2014-09-11 18:10:19 +02:00
# include "mathlib.h"
2017-05-27 04:33:47 +02:00
# include "platform.h"
# include "settings.h"
2022-01-27 19:03:20 +01:00
# include "standards.h"
2014-09-11 18:10:19 +02:00
# include "symboldatabase.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
# include "tokenize.h"
2023-01-26 22:23:22 +01:00
# include "valueflow.h"
2014-09-11 18:10:19 +02:00
2023-10-09 10:07:20 +02:00
# include <algorithm>
2020-12-20 08:09:39 +01:00
# include <cmath>
2023-10-09 10:07:20 +02:00
# include <cstddef>
# include <iterator>
2017-05-27 04:33:47 +02:00
# include <list>
2022-08-19 10:16:23 +02:00
# include <sstream>
2023-10-09 10:07:20 +02:00
# include <utility>
2022-01-27 19:03:20 +01:00
# include <vector>
2014-09-11 18:10:19 +02:00
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
namespace {
CheckType instance ;
}
//---------------------------------------------------------------------------
// Checking for shift by too many bits
//---------------------------------------------------------------------------
Mapped error ids stlBoundaries, stlcstr, useAutoPointerContainer, useAutoPointerArray, sprintfOverlappingData, strPlusChar, shiftTooManyBits, integerOverflow, uninitstring, uninitdata, uninitvar, uninitStructMember, deadpointer, va_start_referencePassed, va_end_missing, va_list_usedBeforeStarted, va_start_subsequentCalls to their CWEs.
2016-02-03 13:53:23 +01:00
//
// CWE ids used:
2023-10-08 09:10:17 +02:00
static const CWE CWE195 ( 195U ) ; // Signed to Unsigned Conversion Error
static const CWE CWE197 ( 197U ) ; // Numeric Truncation Error
static const CWE CWE758 ( 758U ) ; // Reliance on Undefined, Unspecified, or Implementation-Defined Behavior
static const CWE CWE190 ( 190U ) ; // Integer Overflow or Wraparound
Mapped error ids stlBoundaries, stlcstr, useAutoPointerContainer, useAutoPointerArray, sprintfOverlappingData, strPlusChar, shiftTooManyBits, integerOverflow, uninitstring, uninitdata, uninitvar, uninitStructMember, deadpointer, va_start_referencePassed, va_end_missing, va_list_usedBeforeStarted, va_start_subsequentCalls to their CWEs.
2016-02-03 13:53:23 +01:00
2014-09-11 18:10:19 +02:00
void CheckType : : checkTooBigBitwiseShift ( )
{
// unknown sizeof(int) => can't run this checker
2023-10-13 16:02:04 +02:00
if ( mSettings - > platform . type = = Platform : : Type : : Unspecified )
2014-09-11 18:10:19 +02:00
return ;
2023-08-29 12:00:52 +02:00
logChecker ( " CheckType::checkTooBigBitwiseShift " ) ; // platform
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2017-09-19 08:50:19 +02:00
// C++ and macro: OUT(x<<y)
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isCPP ( ) & & Token : : Match ( tok , " [;{}] %name% ( " ) & & Token : : simpleMatch ( tok - > linkAt ( 2 ) , " ) ; " ) & & tok - > next ( ) - > isUpperCaseName ( ) & & ! tok - > next ( ) - > function ( ) )
2017-09-19 08:50:19 +02:00
tok = tok - > linkAt ( 2 ) ;
if ( ! tok - > astOperand1 ( ) | | ! tok - > astOperand2 ( ) )
continue ;
if ( ! Token : : Match ( tok , " <<|>>|<<=|>>= " ) )
continue ;
// get number of bits of lhs
2018-02-18 14:28:48 +01:00
const ValueType * const lhstype = tok - > astOperand1 ( ) - > valueType ( ) ;
2019-08-05 12:41:08 +02:00
if ( ! lhstype | | ! lhstype - > isIntegral ( ) | | lhstype - > pointer > = 1 )
2017-09-19 08:50:19 +02:00
continue ;
2018-02-19 23:55:38 +01:00
// C11 Standard, section 6.5.7 Bitwise shift operators, states:
// The integer promotions are performed on each of the operands.
// The type of the result is that of the promoted left operand.
int lhsbits ;
if ( ( lhstype - > type = = ValueType : : Type : : CHAR ) | |
( lhstype - > type = = ValueType : : Type : : SHORT ) | |
2019-05-01 16:34:28 +02:00
( lhstype - > type = = ValueType : : Type : : WCHAR_T ) | |
2018-02-19 23:55:38 +01:00
( lhstype - > type = = ValueType : : Type : : BOOL ) | |
( lhstype - > type = = ValueType : : Type : : INT ) )
2023-03-03 18:36:27 +01:00
lhsbits = mSettings - > platform . int_bit ;
2017-09-19 08:50:19 +02:00
else if ( lhstype - > type = = ValueType : : Type : : LONG )
2023-03-03 18:36:27 +01:00
lhsbits = mSettings - > platform . long_bit ;
2017-09-19 08:50:19 +02:00
else if ( lhstype - > type = = ValueType : : Type : : LONGLONG )
2023-03-03 18:36:27 +01:00
lhsbits = mSettings - > platform . long_long_bit ;
2017-09-19 08:50:19 +02:00
else
continue ;
// Get biggest rhs value. preferably a value which doesn't have 'condition'.
2018-06-16 16:10:28 +02:00
const ValueFlow : : Value * value = tok - > astOperand2 ( ) - > getValueGE ( lhsbits , mSettings ) ;
2019-09-25 20:16:04 +02:00
if ( value & & mSettings - > isEnabled ( value , false ) )
2017-09-19 08:50:19 +02:00
tooBigBitwiseShiftError ( tok , lhsbits , * value ) ;
2017-09-19 09:21:20 +02:00
else if ( lhstype - > sign = = ValueType : : Sign : : SIGNED ) {
2018-06-16 16:10:28 +02:00
value = tok - > astOperand2 ( ) - > getValueGE ( lhsbits - 1 , mSettings ) ;
if ( value & & mSettings - > isEnabled ( value , false ) )
2017-09-19 09:21:20 +02:00
tooBigSignedBitwiseShiftError ( tok , lhsbits , * value ) ;
}
2014-09-11 18:10:19 +02:00
}
}
void CheckType : : tooBigBitwiseShiftError ( const Token * tok , int lhsbits , const ValueFlow : : Value & rhsbits )
{
2017-09-19 09:21:20 +02:00
const char id [ ] = " shiftTooManyBits " ;
2017-05-22 07:58:56 +02:00
if ( ! tok ) {
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : error , id , " Shifting 32-bit value by 40 bits is undefined behaviour " , CWE758 , Certainty : : normal ) ;
2017-05-22 07:58:56 +02:00
return ;
}
const ErrorPath errorPath = getErrorPath ( tok , & rhsbits , " Shift " ) ;
2014-09-11 18:10:19 +02:00
std : : ostringstream errmsg ;
errmsg < < " Shifting " < < lhsbits < < " -bit value by " < < rhsbits . intvalue < < " bits is undefined behaviour " ;
if ( rhsbits . condition )
errmsg < < " . See condition at line " < < rhsbits . condition - > linenr ( ) < < " . " ;
2017-05-22 07:58:56 +02:00
2021-02-24 22:00:06 +01:00
reportError ( errorPath , rhsbits . errorSeverity ( ) ? Severity : : error : Severity : : warning , id , errmsg . str ( ) , CWE758 , rhsbits . isInconclusive ( ) ? Certainty : : inconclusive : Certainty : : normal ) ;
2017-09-19 09:21:20 +02:00
}
void CheckType : : tooBigSignedBitwiseShiftError ( const Token * tok , int lhsbits , const ValueFlow : : Value & rhsbits )
{
const char id [ ] = " shiftTooManyBitsSigned " ;
2019-08-31 07:40:57 +02:00
const bool cpp14 = mSettings - > standards . cpp > = Standards : : CPP14 ;
std : : string behaviour = " undefined " ;
if ( cpp14 )
behaviour = " implementation-defined " ;
2017-09-19 09:21:20 +02:00
if ( ! tok ) {
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : error , id , " Shifting signed 32-bit value by 31 bits is " + behaviour + " behaviour " , CWE758 , Certainty : : normal ) ;
2017-09-19 09:21:20 +02:00
return ;
}
2023-10-12 11:58:39 +02:00
Severity severity = rhsbits . errorSeverity ( ) ? Severity : : error : Severity : : warning ;
2019-08-31 07:40:57 +02:00
if ( cpp14 )
severity = Severity : : portability ;
2021-02-24 22:00:06 +01:00
if ( ( severity = = Severity : : portability ) & & ! mSettings - > severity . isEnabled ( Severity : : portability ) )
2019-09-25 20:16:04 +02:00
return ;
2023-04-28 12:42:51 +02:00
const ErrorPath errorPath = getErrorPath ( tok , & rhsbits , " Shift " ) ;
std : : ostringstream errmsg ;
errmsg < < " Shifting signed " < < lhsbits < < " -bit value by " < < rhsbits . intvalue < < " bits is " + behaviour + " behaviour " ;
if ( rhsbits . condition )
errmsg < < " . See condition at line " < < rhsbits . condition - > linenr ( ) < < " . " ;
2021-02-24 22:00:06 +01:00
reportError ( errorPath , severity , id , errmsg . str ( ) , CWE758 , rhsbits . isInconclusive ( ) ? Certainty : : inconclusive : Certainty : : normal ) ;
2014-09-11 18:10:19 +02:00
}
//---------------------------------------------------------------------------
// Checking for integer overflow
//---------------------------------------------------------------------------
void CheckType : : checkIntegerOverflow ( )
{
// unknown sizeof(int) => can't run this checker
2023-10-13 16:02:04 +02:00
if ( mSettings - > platform . type = = Platform : : Type : : Unspecified | | mSettings - > platform . int_bit > = MathLib : : bigint_bits )
2014-09-11 18:10:19 +02:00
return ;
2023-08-29 12:00:52 +02:00
logChecker ( " CheckType::checkIntegerOverflow " ) ; // platform
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2017-09-19 14:43:48 +02:00
if ( ! tok - > isArithmeticalOp ( ) )
continue ;
// is result signed integer?
const ValueType * vt = tok - > valueType ( ) ;
2017-09-19 19:14:29 +02:00
if ( ! vt | | ! vt - > isIntegral ( ) | | vt - > sign ! = ValueType : : Sign : : SIGNED )
continue ;
unsigned int bits ;
if ( vt - > type = = ValueType : : Type : : INT )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . int_bit ;
2017-09-19 19:14:29 +02:00
else if ( vt - > type = = ValueType : : Type : : LONG )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . long_bit ;
2017-09-19 19:14:29 +02:00
else if ( vt - > type = = ValueType : : Type : : LONGLONG )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . long_long_bit ;
2017-09-19 19:14:29 +02:00
else
2017-09-19 14:43:48 +02:00
continue ;
2017-10-21 22:08:34 +02:00
if ( bits > = MathLib : : bigint_bits )
2017-09-19 19:14:29 +02:00
continue ;
// max value according to platform settings.
2021-01-03 17:44:46 +01:00
const MathLib : : bigint maxvalue = ( ( ( MathLib : : biguint ) 1 ) < < ( bits - 1 ) ) - 1 ;
2017-09-19 19:14:29 +02:00
2017-09-19 14:43:48 +02:00
// is there a overflow result value
2018-06-16 16:10:28 +02:00
const ValueFlow : : Value * value = tok - > getValueGE ( maxvalue + 1 , mSettings ) ;
2017-09-19 14:43:48 +02:00
if ( ! value )
2018-06-16 16:10:28 +02:00
value = tok - > getValueLE ( - maxvalue - 2 , mSettings ) ;
if ( ! value | | ! mSettings - > isEnabled ( value , false ) )
2017-09-19 14:43:48 +02:00
continue ;
// For left shift, it's common practice to shift into the sign bit
2023-10-28 16:47:57 +02:00
if ( tok - > str ( ) = = " << " & & value - > intvalue > 0 & & value - > intvalue < ( ( ( MathLib : : bigint ) 1 ) < < bits ) )
continue ;
2017-09-19 14:43:48 +02:00
integerOverflowError ( tok , * value ) ;
2014-09-11 18:10:19 +02:00
}
}
void CheckType : : integerOverflowError ( const Token * tok , const ValueFlow : : Value & value )
{
const std : : string expr ( tok ? tok - > expressionString ( ) : " " ) ;
2015-12-31 12:05:23 +01:00
std : : string msg ;
if ( value . condition )
msg = ValueFlow : : eitherTheConditionIsRedundant ( value . condition ) +
" or there is signed integer overflow for expression ' " + expr + " '. " ;
else
msg = " Signed integer overflow for expression ' " + expr + " '. " ;
2014-09-11 18:10:19 +02:00
2019-07-25 17:19:51 +02:00
if ( value . safe )
msg = " Safe checks: " + msg ;
2017-05-22 10:10:56 +02:00
reportError ( getErrorPath ( tok , & value , " Integer overflow " ) ,
2017-05-23 11:43:56 +02:00
value . errorSeverity ( ) ? Severity : : error : Severity : : warning ,
2019-07-25 17:19:51 +02:00
getMessageId ( value , " integerOverflow " ) . c_str ( ) ,
2015-12-31 12:05:23 +01:00
msg ,
Mapped error ids stlBoundaries, stlcstr, useAutoPointerContainer, useAutoPointerArray, sprintfOverlappingData, strPlusChar, shiftTooManyBits, integerOverflow, uninitstring, uninitdata, uninitvar, uninitStructMember, deadpointer, va_start_referencePassed, va_end_missing, va_list_usedBeforeStarted, va_start_subsequentCalls to their CWEs.
2016-02-03 13:53:23 +01:00
CWE190 ,
2021-02-24 22:00:06 +01:00
value . isInconclusive ( ) ? Certainty : : inconclusive : Certainty : : normal ) ;
2014-09-11 18:10:19 +02:00
}
//---------------------------------------------------------------------------
// Checking for sign conversion when operand can be negative
//---------------------------------------------------------------------------
void CheckType : : checkSignConversion ( )
{
2021-02-24 22:00:06 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : warning ) )
2014-09-11 18:10:19 +02:00
return ;
2014-09-11 19:45:52 +02:00
2023-08-29 12:00:52 +02:00
logChecker ( " CheckType::checkSignConversion " ) ; // warning
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2017-09-19 19:25:33 +02:00
if ( ! tok - > isArithmeticalOp ( ) | | Token : : Match ( tok , " +|- " ) )
continue ;
2014-09-11 18:10:19 +02:00
2017-09-19 19:25:33 +02:00
// Is result unsigned?
if ( ! ( tok - > valueType ( ) & & tok - > valueType ( ) - > sign = = ValueType : : Sign : : UNSIGNED ) )
continue ;
2014-09-11 19:45:52 +02:00
2017-09-19 19:25:33 +02:00
// Check if an operand can be negative..
2020-07-20 11:15:18 +02:00
const Token * astOperands [ ] = { tok - > astOperand1 ( ) , tok - > astOperand2 ( ) } ;
for ( const Token * tok1 : astOperands ) {
2017-09-19 19:25:33 +02:00
if ( ! tok1 )
continue ;
2021-06-04 17:17:41 +02:00
const ValueFlow : : Value * negativeValue =
2021-08-07 20:51:18 +02:00
ValueFlow : : findValue ( tok1 - > values ( ) , mSettings , [ & ] ( const ValueFlow : : Value & v ) {
2021-06-05 08:53:15 +02:00
return ! v . isImpossible ( ) & & v . isIntValue ( ) & & ( v . intvalue < = - 1 | | v . wideintvalue < = - 1 ) ;
} ) ;
2019-08-05 12:41:08 +02:00
if ( ! negativeValue )
2017-09-19 19:25:33 +02:00
continue ;
if ( tok1 - > valueType ( ) & & tok1 - > valueType ( ) - > sign ! = ValueType : : Sign : : UNSIGNED )
2019-08-05 12:41:08 +02:00
signConversionError ( tok1 , negativeValue , tok1 - > isNumber ( ) ) ;
2014-09-11 18:10:19 +02:00
}
}
}
2019-08-05 12:41:08 +02:00
void CheckType : : signConversionError ( const Token * tok , const ValueFlow : : Value * negativeValue , const bool constvalue )
2014-09-11 18:10:19 +02:00
{
2018-12-23 12:42:18 +01:00
const std : : string expr ( tok ? tok - > expressionString ( ) : " var " ) ;
std : : ostringstream msg ;
if ( tok & & tok - > isName ( ) )
msg < < " $symbol: " < < expr < < " \n " ;
if ( constvalue )
2019-07-17 22:41:24 +02:00
msg < < " Expression ' " < < expr < < " ' has a negative value. That is converted to an unsigned value and used in an unsigned calculation. " ;
2018-12-23 12:42:18 +01:00
else
2019-07-17 22:41:24 +02:00
msg < < " Expression ' " < < expr < < " ' can have a negative value. That is converted to an unsigned value and used in an unsigned calculation. " ;
2018-12-23 12:42:18 +01:00
2019-08-05 12:41:08 +02:00
if ( ! negativeValue )
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : warning , " signConversion " , msg . str ( ) , CWE195 , Certainty : : normal ) ;
2019-08-05 12:41:08 +02:00
else {
const ErrorPath & errorPath = getErrorPath ( tok , negativeValue , " Negative value is converted to an unsigned value " ) ;
reportError ( errorPath ,
Severity : : warning ,
Check : : getMessageId ( * negativeValue , " signConversion " ) . c_str ( ) ,
msg . str ( ) ,
CWE195 ,
2021-02-24 22:00:06 +01:00
negativeValue - > isInconclusive ( ) ? Certainty : : inconclusive : Certainty : : normal ) ;
2019-08-05 12:41:08 +02:00
}
2014-09-11 18:10:19 +02:00
}
2015-05-25 10:02:17 +02:00
//---------------------------------------------------------------------------
// Checking for long cast of int result const long x = var1 * var2;
//---------------------------------------------------------------------------
2023-08-02 12:27:29 +02:00
static bool checkTypeCombination ( const ValueType & src , const ValueType & tgt , const Settings * settings )
{
static const std : : pair < ValueType : : Type , ValueType : : Type > typeCombinations [ ] = {
{ ValueType : : Type : : INT , ValueType : : Type : : LONG } ,
{ ValueType : : Type : : INT , ValueType : : Type : : LONGLONG } ,
{ ValueType : : Type : : LONG , ValueType : : Type : : LONGLONG } ,
{ ValueType : : Type : : FLOAT , ValueType : : Type : : DOUBLE } ,
{ ValueType : : Type : : FLOAT , ValueType : : Type : : LONGDOUBLE } ,
{ ValueType : : Type : : DOUBLE , ValueType : : Type : : LONGDOUBLE } ,
} ;
const std : : size_t sizeSrc = ValueFlow : : getSizeOf ( src , settings ) ;
const std : : size_t sizeTgt = ValueFlow : : getSizeOf ( tgt , settings ) ;
if ( ! ( sizeSrc > 0 & & sizeTgt > 0 & & sizeSrc < sizeTgt ) )
return false ;
return std : : any_of ( std : : begin ( typeCombinations ) , std : : end ( typeCombinations ) , [ & ] ( const std : : pair < ValueType : : Type , ValueType : : Type > & p ) {
return src . type = = p . first & & tgt . type = = p . second ;
} ) ;
}
2015-05-25 10:02:17 +02:00
void CheckType : : checkLongCast ( )
{
2021-02-24 22:00:06 +01:00
if ( ! mSettings - > severity . isEnabled ( Severity : : style ) )
2015-05-25 10:02:17 +02:00
return ;
2023-08-29 12:00:52 +02:00
logChecker ( " CheckType::checkLongCast " ) ; // style
2015-05-25 10:02:17 +02:00
// Assignments..
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2023-08-03 13:49:11 +02:00
if ( tok - > str ( ) ! = " = " | | ! Token : : Match ( tok - > astOperand2 ( ) , " *|<< " ) | | tok - > astOperand2 ( ) - > isUnaryOp ( " * " ) )
2015-05-25 18:19:40 +02:00
continue ;
2015-12-31 12:05:23 +01:00
2018-06-04 22:51:21 +02:00
if ( tok - > astOperand2 ( ) - > hasKnownIntValue ( ) ) {
const ValueFlow : : Value & v = tok - > astOperand2 ( ) - > values ( ) . front ( ) ;
2023-03-03 18:36:27 +01:00
if ( mSettings - > platform . isIntValue ( v . intvalue ) )
2018-06-04 22:51:21 +02:00
continue ;
}
2015-12-31 12:05:23 +01:00
const ValueType * lhstype = tok - > astOperand1 ( ) ? tok - > astOperand1 ( ) - > valueType ( ) : nullptr ;
const ValueType * rhstype = tok - > astOperand2 ( ) - > valueType ( ) ;
if ( ! lhstype | | ! rhstype )
2015-05-25 10:02:17 +02:00
continue ;
2023-08-02 12:27:29 +02:00
if ( ! checkTypeCombination ( * rhstype , * lhstype , mSettings ) )
continue ;
2015-12-31 12:05:23 +01:00
// assign int result to long/longlong const nonpointer?
2023-08-02 12:27:29 +02:00
if ( rhstype - > pointer = = 0U & &
2015-12-31 12:05:23 +01:00
rhstype - > originalTypeName . empty ( ) & &
lhstype - > pointer = = 0U & &
lhstype - > originalTypeName . empty ( ) )
2023-08-02 12:27:29 +02:00
longCastAssignError ( tok , rhstype , lhstype ) ;
2015-05-25 10:02:17 +02:00
}
// Return..
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2018-07-13 16:57:17 +02:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2015-05-25 10:02:17 +02:00
// function must return long data
const Token * def = scope - > classDef ;
2023-08-02 12:27:29 +02:00
if ( ! Token : : Match ( def , " %name% ( " ) | | ! def - > next ( ) - > valueType ( ) )
2015-05-25 10:02:17 +02:00
continue ;
2023-08-02 12:27:29 +02:00
const ValueType * retVt = def - > next ( ) - > valueType ( ) ;
2015-05-25 10:02:17 +02:00
2015-12-31 12:05:23 +01:00
// return statements
2015-05-25 10:02:17 +02:00
const Token * ret = nullptr ;
2018-04-27 22:36:30 +02:00
for ( const Token * tok = scope - > bodyStart ; tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
2015-05-25 10:02:17 +02:00
if ( tok - > str ( ) = = " return " ) {
2015-12-31 12:05:23 +01:00
if ( Token : : Match ( tok - > astOperand1 ( ) , " <<|* " ) ) {
const ValueType * type = tok - > astOperand1 ( ) - > valueType ( ) ;
2023-08-02 12:27:29 +02:00
if ( type & & checkTypeCombination ( * type , * retVt , mSettings ) & &
type - > pointer = = 0U & &
type - > originalTypeName . empty ( ) )
2015-12-31 12:05:23 +01:00
ret = tok ;
}
// All return statements must have problem otherwise no warning
if ( ret ! = tok ) {
ret = nullptr ;
2015-05-25 10:02:17 +02:00
break ;
}
}
}
2015-12-31 12:05:23 +01:00
if ( ret )
2023-08-02 12:27:29 +02:00
longCastReturnError ( ret , ret - > astOperand1 ( ) - > valueType ( ) , retVt ) ;
2015-05-25 10:02:17 +02:00
}
}
2023-08-02 12:27:29 +02:00
static void makeBaseTypeString ( std : : string & typeStr )
{
const auto pos = typeStr . find ( " signed " ) ;
if ( pos ! = std : : string : : npos )
typeStr . erase ( typeStr . begin ( ) , typeStr . begin ( ) + pos + 6 + 1 ) ;
}
void CheckType : : longCastAssignError ( const Token * tok , const ValueType * src , const ValueType * tgt )
2015-05-25 10:02:17 +02:00
{
2023-08-02 12:27:29 +02:00
std : : string srcStr = src ? src - > str ( ) : " int " ;
makeBaseTypeString ( srcStr ) ;
std : : string tgtStr = tgt ? tgt - > str ( ) : " long " ;
makeBaseTypeString ( tgtStr ) ;
2015-05-25 10:02:17 +02:00
reportError ( tok ,
Severity : : style ,
" truncLongCastAssignment " ,
2023-08-02 12:27:29 +02:00
srcStr + " result is assigned to " + tgtStr + " variable. If the variable is " + tgtStr + " to avoid loss of information, then you have loss of information. \n " +
srcStr + " result is assigned to " + tgtStr + " variable. If the variable is " + tgtStr + " to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to " + tgtStr + " , for example 'l = a * b;' => 'l = ( " + tgtStr + " )a * b;'. " , CWE197 , Certainty : : normal ) ;
2015-05-25 10:02:17 +02:00
}
2023-08-02 12:27:29 +02:00
void CheckType : : longCastReturnError ( const Token * tok , const ValueType * src , const ValueType * tgt )
2015-05-25 10:02:17 +02:00
{
2023-08-02 12:27:29 +02:00
std : : string srcStr = src ? src - > str ( ) : " int " ;
makeBaseTypeString ( srcStr ) ;
std : : string tgtStr = tgt ? tgt - > str ( ) : " long " ;
makeBaseTypeString ( tgtStr ) ;
2015-05-25 10:02:17 +02:00
reportError ( tok ,
Severity : : style ,
" truncLongCastReturn " ,
2023-08-02 12:27:29 +02:00
srcStr + " result is returned as " + tgtStr + " value. If the return value is " + tgtStr + " to avoid loss of information, then you have loss of information. \n " +
srcStr + " result is returned as " + tgtStr + " value. If the return value is " + tgtStr + " to avoid loss of information, then there is loss of information. To avoid loss of information you must cast a calculation operand to long, for example 'return a*b;' => 'return (long)a*b'. " , CWE197 , Certainty : : normal ) ;
2015-05-25 10:02:17 +02:00
}
2016-11-22 22:37:13 +01:00
//---------------------------------------------------------------------------
// Checking for float to integer overflow
//---------------------------------------------------------------------------
void CheckType : : checkFloatToIntegerOverflow ( )
{
2023-08-29 12:00:52 +02:00
logChecker ( " CheckType::checkFloatToIntegerOverflow " ) ;
2018-06-16 16:10:28 +02:00
for ( const Token * tok = mTokenizer - > tokens ( ) ; tok ; tok = tok - > next ( ) ) {
2017-09-19 19:30:24 +02:00
const ValueType * vtint , * vtfloat ;
// Explicit cast
if ( Token : : Match ( tok , " ( %name% " ) & & tok - > astOperand1 ( ) & & ! tok - > astOperand2 ( ) ) {
vtint = tok - > valueType ( ) ;
vtfloat = tok - > astOperand1 ( ) - > valueType ( ) ;
2023-03-02 22:05:41 +01:00
checkFloatToIntegerOverflow ( tok , vtint , vtfloat , tok - > astOperand1 ( ) - > values ( ) ) ;
2017-09-19 19:30:24 +02:00
}
2016-11-22 22:37:13 +01:00
2017-09-19 19:30:24 +02:00
// Assignment
else if ( tok - > str ( ) = = " = " & & tok - > astOperand1 ( ) & & tok - > astOperand2 ( ) ) {
vtint = tok - > astOperand1 ( ) - > valueType ( ) ;
vtfloat = tok - > astOperand2 ( ) - > valueType ( ) ;
2023-03-02 22:05:41 +01:00
checkFloatToIntegerOverflow ( tok , vtint , vtfloat , tok - > astOperand2 ( ) - > values ( ) ) ;
2017-09-19 19:30:24 +02:00
}
2016-11-22 22:37:13 +01:00
2019-07-24 16:17:52 +02:00
else if ( tok - > str ( ) = = " return " & & tok - > astOperand1 ( ) & & tok - > astOperand1 ( ) - > valueType ( ) & & tok - > astOperand1 ( ) - > valueType ( ) - > isFloat ( ) ) {
const Scope * scope = tok - > scope ( ) ;
while ( scope & & scope - > type ! = Scope : : ScopeType : : eLambda & & scope - > type ! = Scope : : ScopeType : : eFunction )
scope = scope - > nestedIn ;
if ( scope & & scope - > type = = Scope : : ScopeType : : eFunction & & scope - > function & & scope - > function - > retDef ) {
2023-08-18 22:48:24 +02:00
const ValueType & valueType = ValueType : : parseDecl ( scope - > function - > retDef , * mSettings ) ;
2019-07-24 16:17:52 +02:00
vtfloat = tok - > astOperand1 ( ) - > valueType ( ) ;
2023-03-02 22:05:41 +01:00
checkFloatToIntegerOverflow ( tok , & valueType , vtfloat , tok - > astOperand1 ( ) - > values ( ) ) ;
2019-07-24 16:17:52 +02:00
}
}
}
}
2017-08-23 05:34:47 +02:00
2023-03-02 22:05:41 +01:00
void CheckType : : checkFloatToIntegerOverflow ( const Token * tok , const ValueType * vtint , const ValueType * vtfloat , const std : : list < ValueFlow : : Value > & floatValues )
2019-07-24 16:17:52 +02:00
{
// Conversion of float to integer?
if ( ! vtint | | ! vtint - > isIntegral ( ) )
return ;
if ( ! vtfloat | | ! vtfloat - > isFloat ( ) )
return ;
2017-09-19 19:30:24 +02:00
2023-03-02 22:05:41 +01:00
for ( const ValueFlow : : Value & f : floatValues ) {
2019-07-24 16:17:52 +02:00
if ( f . valueType ! = ValueFlow : : Value : : ValueType : : FLOAT )
2017-09-19 19:30:24 +02:00
continue ;
2019-07-24 16:17:52 +02:00
if ( ! mSettings - > isEnabled ( & f , false ) )
2017-09-19 19:30:24 +02:00
continue ;
2023-03-03 18:36:27 +01:00
if ( f . floatValue > = std : : exp2 ( mSettings - > platform . long_long_bit ) )
2019-07-24 16:17:52 +02:00
floatToIntegerOverflowError ( tok , f ) ;
2023-03-03 18:36:27 +01:00
else if ( ( - f . floatValue ) > std : : exp2 ( mSettings - > platform . long_long_bit - 1 ) )
2019-07-24 16:17:52 +02:00
floatToIntegerOverflowError ( tok , f ) ;
2023-10-13 16:02:04 +02:00
else if ( mSettings - > platform . type ! = Platform : : Type : : Unspecified ) {
2019-07-24 16:17:52 +02:00
int bits = 0 ;
if ( vtint - > type = = ValueType : : Type : : CHAR )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . char_bit ;
2019-07-24 16:17:52 +02:00
else if ( vtint - > type = = ValueType : : Type : : SHORT )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . short_bit ;
2019-07-24 16:17:52 +02:00
else if ( vtint - > type = = ValueType : : Type : : INT )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . int_bit ;
2019-07-24 16:17:52 +02:00
else if ( vtint - > type = = ValueType : : Type : : LONG )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . long_bit ;
2019-07-24 16:17:52 +02:00
else if ( vtint - > type = = ValueType : : Type : : LONGLONG )
2023-03-03 18:36:27 +01:00
bits = mSettings - > platform . long_long_bit ;
2019-07-24 16:17:52 +02:00
else
2017-08-23 05:34:47 +02:00
continue ;
2019-07-24 16:17:52 +02:00
if ( bits < MathLib : : bigint_bits & & f . floatValue > = ( ( ( MathLib : : biguint ) 1 ) < < bits ) )
2018-07-13 16:57:17 +02:00
floatToIntegerOverflowError ( tok , f ) ;
2016-11-22 22:37:13 +01:00
}
}
}
void CheckType : : floatToIntegerOverflowError ( const Token * tok , const ValueFlow : : Value & value )
{
std : : ostringstream errmsg ;
2017-05-22 11:04:24 +02:00
errmsg < < " Undefined behaviour: float ( " < < value . floatValue < < " ) to integer conversion overflow. " ;
reportError ( getErrorPath ( tok , & value , " float to integer conversion " ) ,
2017-05-23 11:43:56 +02:00
value . errorSeverity ( ) ? Severity : : error : Severity : : warning ,
2016-11-22 22:37:13 +01:00
" floatConversionOverflow " ,
2021-02-24 22:00:06 +01:00
errmsg . str ( ) , CWE190 , value . isInconclusive ( ) ? Certainty : : inconclusive : Certainty : : normal ) ;
2016-11-22 22:37:13 +01:00
}