2009-03-19 20:55:50 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2018-01-14 15:37:52 +01:00
* Copyright ( C ) 2007 - 2018 Cppcheck team .
2009-03-19 20:55:50 +01: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
2009-09-27 17:08:31 +02:00
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
2009-03-19 20:55:50 +01:00
*/
//---------------------------------------------------------------------------
2009-05-22 07:51:30 +02:00
// Auto variables checks
2009-03-19 20:55:50 +01:00
//---------------------------------------------------------------------------
# include "checkautovariables.h"
2017-05-27 04:33:47 +02:00
2017-08-29 22:35:55 +02:00
# include "astutils.h"
2017-05-27 04:33:47 +02:00
# include "errorlogger.h"
# include "library.h"
# include "settings.h"
2011-01-16 19:57:29 +01:00
# include "symboldatabase.h"
2017-05-27 04:33:47 +02:00
# include "token.h"
# include "tokenize.h"
# include "valueflow.h"
2009-03-19 20:55:50 +01:00
2017-05-27 04:33:47 +02:00
# include <cstddef>
# include <list>
2009-03-19 20:55:50 +01:00
//---------------------------------------------------------------------------
// Register this check class into cppcheck by creating a static instance of it..
2011-10-13 20:53:06 +02:00
namespace {
2017-09-07 13:01:07 +02:00
CheckAutoVariables instance ;
2009-03-19 20:55:50 +01:00
}
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
static const CWE CWE398 ( 398U ) ; // Indicator of Poor Code Quality
static const CWE CWE562 ( 562U ) ; // Return of Stack Variable Address
static const CWE CWE590 ( 590U ) ; // Free of Memory not on the Heap
2009-03-19 20:55:50 +01:00
2018-01-24 21:33:58 +01:00
static bool isPtrArg ( const Token * tok )
2013-02-18 17:52:49 +01:00
{
const Variable * var = tok - > variable ( ) ;
2013-08-07 16:27:37 +02:00
return ( var & & var - > isArgument ( ) & & var - > isPointer ( ) ) ;
2013-02-18 17:52:49 +01:00
}
2018-01-24 21:33:58 +01:00
static bool isGlobalPtr ( const Token * tok )
2015-08-25 21:19:19 +02:00
{
const Variable * var = tok - > variable ( ) ;
2018-01-24 21:33:58 +01:00
return ( var & & var - > isGlobal ( ) & & var - > isPointer ( ) ) ;
}
2015-08-25 21:19:19 +02:00
2018-01-24 21:33:58 +01:00
static bool isArrayArg ( const Token * tok )
{
const Variable * var = tok - > variable ( ) ;
2015-08-25 21:19:19 +02:00
return ( var & & var - > isArgument ( ) & & var - > isArray ( ) ) ;
}
2018-11-03 18:55:12 +01:00
static bool isArrayVar ( const Token * tok )
{
const Variable * var = tok - > variable ( ) ;
return ( var & & var - > isArray ( ) ) ;
}
2018-01-24 21:33:58 +01:00
static bool isRefPtrArg ( const Token * tok )
2009-03-19 20:55:50 +01:00
{
2013-01-31 20:08:48 +01:00
const Variable * var = tok - > variable ( ) ;
2013-08-07 16:27:37 +02:00
return ( var & & var - > isArgument ( ) & & var - > isReference ( ) & & var - > isPointer ( ) ) ;
2012-03-01 18:38:20 +01:00
}
2018-01-24 21:33:58 +01:00
static bool isNonReferenceArg ( const Token * tok )
2012-03-01 18:38:20 +01:00
{
2013-01-31 20:08:48 +01:00
const Variable * var = tok - > variable ( ) ;
2018-06-24 08:25:19 +02:00
return ( var & & var - > isArgument ( ) & & ! var - > isReference ( ) & & ( var - > isPointer ( ) | | var - > valueType ( ) - > type > = ValueType : : Type : : CONTAINER | | var - > type ( ) ) ) ;
2009-03-19 20:55:50 +01:00
}
2009-07-27 19:34:17 +02:00
2018-01-24 21:33:58 +01:00
static bool isAutoVar ( const Token * tok )
2009-03-19 20:55:50 +01:00
{
2013-01-31 20:08:48 +01:00
const Variable * var = tok - > variable ( ) ;
2009-08-16 11:43:04 +02:00
2012-03-01 18:38:20 +01:00
if ( ! var | | ! var - > isLocal ( ) | | var - > isStatic ( ) )
2009-08-16 11:43:04 +02:00
return false ;
2012-01-28 12:32:28 +01:00
if ( var - > isReference ( ) ) {
2011-08-10 18:16:31 +02:00
// address of reference variable can be taken if the address
// of the variable it points at is not a auto-var
// TODO: check what the reference variable references.
return false ;
}
2015-11-11 16:59:13 +01:00
if ( Token : : Match ( tok , " %name% .|:: " ) ) {
do {
tok = tok - > tokAt ( 2 ) ;
} while ( Token : : Match ( tok , " %name% .|:: " ) ) ;
if ( Token : : Match ( tok , " %name% ( " ) )
return false ;
}
2011-04-23 15:50:56 +02:00
return true ;
2009-08-09 15:40:04 +02:00
}
2018-01-24 21:33:58 +01:00
static bool isAutoVarArray ( const Token * tok )
2009-03-21 18:36:41 +01:00
{
2015-11-15 14:48:13 +01:00
if ( ! tok )
return false ;
// &x[..]
2018-07-13 23:02:52 +02:00
if ( tok - > isUnaryOp ( " & " ) & & Token : : simpleMatch ( tok - > astOperand1 ( ) , " [ " ) )
2015-11-15 14:48:13 +01:00
return isAutoVarArray ( tok - > astOperand1 ( ) - > astOperand1 ( ) ) ;
// x+y
if ( tok - > str ( ) = = " + " )
return isAutoVarArray ( tok - > astOperand1 ( ) ) | | isAutoVarArray ( tok - > astOperand2 ( ) ) ;
2015-11-15 19:34:36 +01:00
// x-intexpr
if ( tok - > str ( ) = = " - " )
return isAutoVarArray ( tok - > astOperand1 ( ) ) & &
tok - > astOperand2 ( ) & &
tok - > astOperand2 ( ) - > valueType ( ) & &
tok - > astOperand2 ( ) - > valueType ( ) - > isIntegral ( ) ;
2013-01-31 20:08:48 +01:00
const Variable * var = tok - > variable ( ) ;
2015-11-15 14:48:13 +01:00
if ( ! var )
return false ;
// Variable
if ( var - > isLocal ( ) & & ! var - > isStatic ( ) & & var - > isArray ( ) & & ! var - > isPointer ( ) )
2015-11-15 12:10:35 +01:00
return true ;
// ValueFlow
2016-01-30 20:02:39 +01:00
if ( var - > isPointer ( ) & & ! var - > isArgument ( ) ) {
2017-03-27 18:48:34 +02:00
for ( std : : list < ValueFlow : : Value > : : const_iterator it = tok - > values ( ) . begin ( ) ; it ! = tok - > values ( ) . end ( ) ; + + it ) {
2015-11-15 12:10:35 +01:00
const ValueFlow : : Value & val = * it ;
2016-11-13 22:33:39 +01:00
if ( val . isTokValue ( ) & & isAutoVarArray ( val . tokvalue ) )
2015-11-15 12:10:35 +01:00
return true ;
}
}
2009-07-27 19:34:17 +02:00
2015-11-15 12:10:35 +01:00
return false ;
2012-03-01 18:38:20 +01:00
}
2009-07-27 19:34:17 +02:00
2012-03-01 18:38:20 +01:00
// Verification that we really take the address of a local variable
2013-06-13 16:19:19 +02:00
static bool checkRvalueExpression ( const Token * const vartok )
2012-03-01 18:38:20 +01:00
{
2013-06-13 16:19:19 +02:00
const Variable * const var = vartok - > variable ( ) ;
2014-02-16 10:32:10 +01:00
if ( var = = nullptr )
2013-06-13 16:19:19 +02:00
return false ;
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok - > previous ( ) , " & %name% [ " ) & & var - > isPointer ( ) )
2013-10-06 14:23:26 +02:00
return false ;
2014-09-01 08:05:59 +02:00
const Token * const next = vartok - > next ( ) ;
2013-06-13 16:19:19 +02:00
// &a.b[0]
2015-01-31 10:50:39 +01:00
if ( Token : : Match ( vartok , " %name% . %var% [ " ) & & ! var - > isPointer ( ) ) {
2013-06-13 16:19:19 +02:00
const Variable * var2 = next - > next ( ) - > variable ( ) ;
return var2 & & ! var2 - > isPointer ( ) ;
}
2013-08-07 16:27:37 +02:00
return ( ( next - > str ( ) ! = " . " | | ( ! var - > isPointer ( ) & & ( ! var - > isClass ( ) | | var - > type ( ) ) ) ) & & next - > strAt ( 2 ) ! = " . " ) ;
2009-08-09 15:40:04 +02:00
}
2013-02-18 17:52:49 +01:00
static bool variableIsUsedInScope ( const Token * start , unsigned int varId , const Scope * scope )
2013-02-01 19:16:17 +01:00
{
2013-09-28 09:32:41 +02:00
if ( ! start ) // Ticket #5024
2013-09-28 00:14:12 +02:00
return false ;
2013-09-28 09:32:41 +02:00
2018-04-27 22:36:30 +02:00
for ( const Token * tok = start ; tok & & tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
2013-02-18 17:52:49 +01:00
if ( tok - > varId ( ) = = varId )
return true ;
2014-07-17 08:44:19 +02:00
const Scope : : ScopeType scopeType = tok - > scope ( ) - > type ;
if ( scopeType = = Scope : : eFor | | scopeType = = Scope : : eDo | | scopeType = = Scope : : eWhile ) // In case of loops, better checking would be necessary
2013-02-18 17:52:49 +01:00
return true ;
if ( Token : : simpleMatch ( tok , " asm ( " ) )
2013-02-01 19:16:17 +01:00
return true ;
}
return false ;
}
2013-10-06 16:07:27 +02:00
void CheckAutoVariables : : assignFunctionArg ( )
2009-03-19 20:55:50 +01:00
{
2018-06-16 16:10:28 +02:00
const bool printStyle = mSettings - > isEnabled ( Settings : : STYLE ) ;
const bool printWarning = mSettings - > isEnabled ( Settings : : WARNING ) ;
2015-04-10 14:18:52 +02:00
if ( ! printStyle & & ! printWarning )
2013-10-06 16:07:27 +02:00
return ;
2014-08-04 11:45:24 +02:00
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2018-04-20 22:13:05 +02:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2018-04-27 22:36:30 +02:00
for ( const Token * tok = scope - > bodyStart ; tok & & tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
2016-12-19 15:25:36 +01:00
// TODO: What happens if this is removed?
if ( tok - > astParent ( ) )
continue ;
2018-08-17 19:56:36 +02:00
if ( ! ( tok - > isAssignmentOp ( ) | | Token : : Match ( tok , " ++|-- " ) ) | | ! Token : : Match ( tok - > astOperand1 ( ) , " %var% " ) )
2016-12-19 15:25:36 +01:00
continue ;
const Token * const vartok = tok - > astOperand1 ( ) ;
if ( isNonReferenceArg ( vartok ) & &
! Token : : Match ( vartok - > next ( ) , " = %varid% ; " , vartok - > varId ( ) ) & &
! variableIsUsedInScope ( Token : : findsimplematch ( vartok - > next ( ) , " ; " ) , vartok - > varId ( ) , scope ) & &
2018-04-27 22:36:30 +02:00
! Token : : findsimplematch ( vartok , " goto " , scope - > bodyEnd ) ) {
2016-12-19 15:25:36 +01:00
if ( vartok - > variable ( ) - > isPointer ( ) & & printWarning )
errorUselessAssignmentPtrArg ( vartok ) ;
else if ( printStyle )
errorUselessAssignmentArg ( vartok ) ;
2013-10-06 16:07:27 +02:00
}
}
}
}
2009-03-19 20:55:50 +01:00
2018-06-24 08:55:23 +02:00
static bool reassignedGlobalPointer ( const Token * vartok , unsigned int pointerVarId , const Settings * settings , bool cpp )
2018-01-25 22:50:41 +01:00
{
2018-06-24 08:55:23 +02:00
return isVariableChanged ( vartok ,
vartok - > variable ( ) - > scope ( ) - > bodyEnd ,
pointerVarId ,
true ,
settings ,
cpp ) ;
2018-01-25 22:50:41 +01:00
}
2013-10-06 16:07:27 +02:00
void CheckAutoVariables : : autoVariables ( )
{
2018-06-16 16:10:28 +02:00
const bool printInconclusive = mSettings - > inconclusive ;
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2018-04-20 22:13:05 +02:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2018-04-27 22:36:30 +02:00
for ( const Token * tok = scope - > bodyStart ; tok & & tok ! = scope - > bodyEnd ; tok = tok - > next ( ) ) {
2012-03-01 18:38:20 +01:00
// Critical assignment
2013-01-31 20:08:48 +01:00
if ( Token : : Match ( tok , " [;{}] %var% = & %var% " ) & & isRefPtrArg ( tok - > next ( ) ) & & isAutoVar ( tok - > tokAt ( 4 ) ) ) {
2013-06-13 16:19:19 +02:00
if ( checkRvalueExpression ( tok - > tokAt ( 4 ) ) )
2012-03-01 18:38:20 +01:00
errorAutoVariableAssignment ( tok - > next ( ) , false ) ;
2013-01-31 20:08:48 +01:00
} else if ( Token : : Match ( tok , " [;{}] * %var% = & %var% " ) & & isPtrArg ( tok - > tokAt ( 2 ) ) & & isAutoVar ( tok - > tokAt ( 5 ) ) ) {
2013-06-13 16:19:19 +02:00
if ( checkRvalueExpression ( tok - > tokAt ( 5 ) ) )
2011-09-02 02:34:31 +02:00
errorAutoVariableAssignment ( tok - > next ( ) , false ) ;
2018-06-16 16:10:28 +02:00
} else if ( mSettings - > isEnabled ( Settings : : WARNING ) & & Token : : Match ( tok , " [ ; { } ] % var % = & | % var % ; " ) && isGlobalPtr(tok->next())) {
2018-01-24 21:33:58 +01:00
const Token * const pointer = tok - > next ( ) ;
2018-01-25 22:50:41 +01:00
if ( isAutoVarArray ( tok - > tokAt ( 3 ) ) ) {
const Token * const array = tok - > tokAt ( 3 ) ;
2018-06-24 08:55:23 +02:00
if ( ! reassignedGlobalPointer ( array , pointer - > varId ( ) , mSettings , mTokenizer - > isCPP ( ) ) )
2018-01-25 22:50:41 +01:00
errorAssignAddressOfLocalArrayToGlobalPointer ( pointer , array ) ;
} else if ( isAutoVar ( tok - > tokAt ( 4 ) ) ) {
const Token * const variable = tok - > tokAt ( 4 ) ;
2018-06-24 08:55:23 +02:00
if ( ! reassignedGlobalPointer ( variable , pointer - > varId ( ) , mSettings , mTokenizer - > isCPP ( ) ) )
2018-01-25 22:50:41 +01:00
errorAssignAddressOfLocalVariableToGlobalPointer ( pointer , variable ) ;
2018-01-24 21:33:58 +01:00
}
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " [;{}] %var% . %var% = & %var% " ) ) {
2011-08-09 18:24:39 +02:00
// TODO: check if the parameter is only changed temporarily (#2969)
2015-09-09 10:08:37 +02:00
if ( printInconclusive & & isPtrArg ( tok - > next ( ) ) ) {
const Token * const var2tok = tok - > tokAt ( 6 ) ;
if ( isAutoVar ( var2tok ) & & checkRvalueExpression ( var2tok ) )
errorAutoVariableAssignment ( tok - > next ( ) , true ) ;
2011-07-22 04:26:42 +02:00
}
2011-07-22 04:37:36 +02:00
tok = tok - > tokAt ( 6 ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " [;{}] %var% . %var% = %var% ; " ) ) {
2011-08-09 18:24:39 +02:00
// TODO: check if the parameter is only changed temporarily (#2969)
2015-09-09 10:08:37 +02:00
if ( printInconclusive & & isPtrArg ( tok - > next ( ) ) ) {
if ( isAutoVarArray ( tok - > tokAt ( 5 ) ) )
errorAutoVariableAssignment ( tok - > next ( ) , true ) ;
2011-07-22 14:31:31 +02:00
}
tok = tok - > tokAt ( 5 ) ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " [;{}] * %var% = %var% ; " ) ) {
2013-01-31 20:08:48 +01:00
const Variable * var1 = tok - > tokAt ( 2 ) - > variable ( ) ;
2011-10-13 20:53:06 +02:00
if ( var1 & & var1 - > isArgument ( ) & & Token : : Match ( var1 - > nameToken ( ) - > tokAt ( - 3 ) , " %type% * * " ) ) {
2013-01-31 20:08:48 +01:00
if ( isAutoVarArray ( tok - > tokAt ( 4 ) ) )
2011-09-02 02:34:31 +02:00
errorAutoVariableAssignment ( tok - > next ( ) , false ) ;
2011-07-21 01:02:54 +02:00
}
tok = tok - > tokAt ( 4 ) ;
2015-08-28 20:29:51 +02:00
} else if ( Token : : Match ( tok , " [;{}] %var% [ " ) & & Token : : Match ( tok - > linkAt ( 2 ) , " ] = & %var% " ) & &
( isPtrArg ( tok - > next ( ) ) | | isArrayArg ( tok - > next ( ) ) ) & & isAutoVar ( tok - > linkAt ( 2 ) - > tokAt ( 3 ) ) ) {
2012-03-01 18:38:20 +01:00
const Token * const varTok = tok - > linkAt ( 2 ) - > tokAt ( 3 ) ;
2013-06-13 16:19:19 +02:00
if ( checkRvalueExpression ( varTok ) )
2012-03-01 18:38:20 +01:00
errorAutoVariableAssignment ( tok - > next ( ) , false ) ;
2011-02-08 01:26:34 +01:00
}
// Critical return
2018-01-27 14:48:45 +01:00
else if ( Token : : Match ( tok , " return %var% ; " ) & & isAutoVar ( tok - > next ( ) ) ) {
const std : : list < ValueFlow : : Value > & values = tok - > next ( ) - > values ( ) ;
const ValueFlow : : Value * value = nullptr ;
for ( std : : list < ValueFlow : : Value > : : const_iterator it = values . begin ( ) ; it ! = values . end ( ) ; + + it ) {
if ( ! it - > isTokValue ( ) )
continue ;
2018-06-16 16:10:28 +02:00
if ( ! mSettings - > inconclusive & & it - > isInconclusive ( ) )
2018-01-27 14:48:45 +01:00
continue ;
if ( ! Token : : Match ( it - > tokvalue - > previous ( ) , " = & %var% " ) )
continue ;
if ( ! isAutoVar ( it - > tokvalue - > next ( ) ) )
continue ;
if ( ! value | | value - > isInconclusive ( ) )
value = & ( * it ) ;
}
if ( value )
errorReturnAddressToAutoVariable ( tok , value ) ;
}
2015-08-26 09:43:15 +02:00
else if ( Token : : Match ( tok , " return & %var% ; " ) ) {
const Token * varTok = tok - > tokAt ( 2 ) ;
if ( isAutoVar ( varTok ) )
errorReturnAddressToAutoVariable ( tok ) ;
else if ( varTok - > varId ( ) ) {
const Variable * var1 = varTok - > variable ( ) ;
if ( var1 & & var1 - > isArgument ( ) & & var1 - > typeEndToken ( ) - > str ( ) ! = " & " )
errorReturnAddressOfFunctionParameter ( tok , varTok - > str ( ) ) ;
}
2011-09-01 03:36:31 +02:00
}
2011-02-08 01:26:34 +01:00
// Invalid pointer deallocation
2018-06-16 16:10:28 +02:00
else if ( ( Token : : Match ( tok , " %name% ( %var% ) ; " ) && mSettings->library.dealloc(tok)) ||
( mTokenizer - > isCPP ( ) & & Token : : Match ( tok , " delete [| ]| (| %var% !![ " ) ) ) {
2012-04-26 16:44:33 +02:00
tok = Token : : findmatch ( tok - > next ( ) , " %var% " ) ;
2018-11-03 18:55:12 +01:00
if ( isArrayVar ( tok ) )
errorInvalidDeallocation ( tok , nullptr ) ;
else if ( tok & & tok - > variable ( ) & & tok - > variable ( ) - > isPointer ( ) ) {
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
if ( v . isTokValue ( ) & & isArrayVar ( v . tokvalue ) ) {
errorInvalidDeallocation ( tok , & v ) ;
break ;
}
}
}
2018-06-16 16:10:28 +02:00
} else if ( ( Token : : Match ( tok , " %name% ( & %var% ) ; " ) && mSettings->library.dealloc(tok)) ||
( mTokenizer - > isCPP ( ) & & Token : : Match ( tok , " delete [| ]| (| & %var% !![ " ) ) ) {
2014-03-06 06:32:30 +01:00
tok = Token : : findmatch ( tok - > next ( ) , " %var% " ) ;
2014-05-12 19:53:49 +02:00
if ( isAutoVar ( tok ) )
2018-11-03 18:55:12 +01:00
errorInvalidDeallocation ( tok , nullptr ) ;
2014-03-06 06:32:30 +01:00
}
2009-06-09 19:45:58 +02:00
}
2011-02-08 01:26:34 +01:00
}
}
//---------------------------------------------------------------------------
void CheckAutoVariables : : returnPointerToLocalArray ( )
{
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2011-02-08 01:26:34 +01:00
2018-04-20 22:13:05 +02:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2012-10-12 06:15:46 +02:00
if ( ! scope - > function )
2011-02-08 01:26:34 +01:00
continue ;
2012-03-01 18:38:20 +01:00
const Token * tok = scope - > function - > tokenDef ;
2011-02-08 01:26:34 +01:00
// have we reached a function that returns a pointer
2012-01-08 15:32:22 +01:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > str ( ) = = " * " ) {
2018-04-27 22:36:30 +02:00
for ( const Token * tok2 = scope - > bodyStart - > next ( ) ; tok2 & & tok2 ! = scope - > bodyEnd ; tok2 = tok2 - > next ( ) ) {
2011-02-08 01:26:34 +01:00
// Return pointer to local array variable..
2015-11-15 14:48:13 +01:00
if ( tok2 - > str ( ) = = " return " & & isAutoVarArray ( tok2 - > astOperand1 ( ) ) ) {
errorReturnPointerToLocalArray ( tok2 ) ;
2011-02-08 01:26:34 +01:00
}
}
}
2009-06-09 19:45:58 +02:00
}
}
2011-07-21 14:50:38 +02:00
void CheckAutoVariables : : errorReturnAddressToAutoVariable ( const Token * tok )
{
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : error , " returnAddressOfAutoVariable " , " Address of an auto-variable returned. " , CWE562 , false ) ;
2011-07-21 14:50:38 +02:00
}
2018-01-27 14:48:45 +01:00
void CheckAutoVariables : : errorReturnAddressToAutoVariable ( const Token * tok , const ValueFlow : : Value * value )
{
reportError ( tok , Severity : : error , " returnAddressOfAutoVariable " , " Address of auto-variable ' " + value - > tokvalue - > astOperand1 ( ) - > expressionString ( ) + " ' returned " , CWE562 , false ) ;
}
2009-06-09 19:45:58 +02:00
void CheckAutoVariables : : errorReturnPointerToLocalArray ( const Token * tok )
{
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : error , " returnLocalVariable " , " Pointer to local array variable returned. " , CWE562 , false ) ;
2009-06-09 19:45:58 +02:00
}
2011-08-09 18:24:39 +02:00
void CheckAutoVariables : : errorAutoVariableAssignment ( const Token * tok , bool inconclusive )
2009-10-04 11:45:45 +02:00
{
2011-10-13 20:53:06 +02:00
if ( ! inconclusive ) {
2011-08-09 18:24:39 +02:00
reportError ( tok , Severity : : error , " autoVariables " ,
2012-07-07 20:31:18 +02:00
" Address of local auto-variable assigned to a function parameter. \n "
2012-07-08 11:38:58 +02:00
" Dangerous assignment - the function parameter is assigned the address of a local "
2012-07-07 20:31:18 +02:00
" auto-variable. Local auto-variables are reserved from the stack which "
" is freed when the function ends. So the pointer to a local variable "
2016-01-25 20:01:48 +01:00
" is invalid after the function ends. " , CWE562 , false ) ;
2011-10-13 20:53:06 +02:00
} else {
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : error , " autoVariables " ,
2012-07-07 20:31:18 +02:00
" Address of local auto-variable assigned to a function parameter. \n "
" Function parameter is assigned the address of a local auto-variable. "
" Local auto-variables are reserved from the stack which is freed when "
2012-05-06 19:37:41 +02:00
" the function ends. The address is invalid after the function ends and it "
2015-04-25 17:48:11 +02:00
" might 'leak' from the function through the parameter. " ,
2016-01-25 20:01:48 +01:00
CWE562 ,
2015-04-25 17:48:11 +02:00
true ) ;
2011-08-09 18:24:39 +02:00
}
2009-10-04 11:45:45 +02:00
}
2009-03-19 20:55:50 +01:00
2018-01-24 21:33:58 +01:00
void CheckAutoVariables : : errorAssignAddressOfLocalArrayToGlobalPointer ( const Token * pointer , const Token * array )
{
const std : : string pointerName = pointer ? pointer - > str ( ) : std : : string ( " pointer " ) ;
const std : : string arrayName = array ? array - > str ( ) : std : : string ( " array " ) ;
reportError ( pointer , Severity : : warning , " autoVariablesAssignGlobalPointer " ,
2018-04-09 06:43:48 +02:00
" $symbol: " + arrayName + " \n Address of local array $symbol is assigned to global pointer " + pointerName + " and not reassigned before $symbol goes out of scope. " , CWE562 , false ) ;
2018-01-24 21:33:58 +01:00
}
2018-01-25 22:50:41 +01:00
void CheckAutoVariables : : errorAssignAddressOfLocalVariableToGlobalPointer ( const Token * pointer , const Token * variable )
{
const std : : string pointerName = pointer ? pointer - > str ( ) : std : : string ( " pointer " ) ;
const std : : string variableName = variable ? variable - > str ( ) : std : : string ( " variable " ) ;
reportError ( pointer , Severity : : warning , " autoVariablesAssignGlobalPointer " ,
2018-04-09 06:43:48 +02:00
" $symbol: " + variableName + " \n Address of local variable $symbol is assigned to global pointer " + pointerName + " and not reassigned before $symbol goes out of scope. " , CWE562 , false ) ;
2018-01-25 22:50:41 +01:00
}
2011-09-01 03:36:31 +02:00
void CheckAutoVariables : : errorReturnAddressOfFunctionParameter ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " returnAddressOfFunctionParameter " ,
2018-04-09 06:43:48 +02:00
" $symbol: " + varname + " \n "
" Address of function parameter '$symbol' returned. \n "
" Address of the function parameter '$symbol' becomes invalid after the function exits because "
2012-07-07 20:31:18 +02:00
" function parameters are stored on the stack which is freed when the function exits. Thus the returned "
2016-01-25 20:01:48 +01:00
" value is invalid. " , CWE562 , false ) ;
2011-09-01 03:36:31 +02:00
}
2014-08-04 11:45:24 +02:00
void CheckAutoVariables : : errorUselessAssignmentArg ( const Token * tok )
{
reportError ( tok ,
Severity : : style ,
" uselessAssignmentArg " ,
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
" Assignment of function parameter has no effect outside the function. " , CWE398 , false ) ;
2014-08-04 11:45:24 +02:00
}
2013-02-01 19:16:17 +01:00
void CheckAutoVariables : : errorUselessAssignmentPtrArg ( const Token * tok )
{
reportError ( tok ,
Severity : : warning ,
" uselessAssignmentPtrArg " ,
Mapped toomanyconfigs ,AssignmentAddressToInteger
,AssignmentIntegerToAddress ,CastIntegerToAddressAtReturn
,CastAddressToIntegerAtReturn ,assertWithSideEffect ,assignmentInAssert
,uselessAssignmentArg ,uselessAssignmentPtrArg
,comparisonOfFuncReturningBoolError
,comparisonOfTwoFuncsReturningBoolError ,comparisonOfBoolWithBoolError
,incrementboolean ,comparisonOfBoolWithInt ,compareBoolExpressionWithInt
,negativeIndex ,pointerOutOfBounds ,arrayIndexThenCheck
,possibleBufferAccessOutOfBounds ,argumentSize
,arrayIndexOutOfBoundsCond ,noConstructor ,copyCtorPointerCopying
,noCopyConstructor ,uninitMemberVar ,operatorEqVarError
,unusedPrivateFunction ,memsetClassFloat ,mallocOnClassWarning
,operatorEq ,thisSubtraction ,operatorEqRetRefThis ,operatorEqToSelf
,useInitializationList ,duplInheritedMember ,assignIfError
,comparisonError ,multiCondition ,mismatchingBitAnd
,oppositeInnerCondition ,incorrectLogicOperator ,redundantCondition
,moduloAlwaysTrueFalse to their CWEs ids.
2016-02-20 23:56:36 +01:00
" Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? " , CWE398 , false ) ;
2013-02-01 19:16:17 +01:00
}
2011-02-08 01:26:34 +01:00
//---------------------------------------------------------------------------
2010-01-27 19:16:32 +01:00
// return temporary?
2015-11-14 18:43:07 +01:00
bool CheckAutoVariables : : returnTemporary ( const Token * tok )
2010-01-27 19:16:32 +01:00
{
2012-08-22 13:08:32 +02:00
bool func = false ; // Might it be a function call?
2012-07-19 16:42:56 +02:00
bool retref = false ; // is there such a function that returns a reference?
bool retvalue = false ; // is there such a function that returns a value?
2013-01-31 06:41:18 +01:00
const Function * function = tok - > function ( ) ;
2012-10-14 17:30:37 +02:00
if ( function ) {
2014-03-01 16:30:59 +01:00
// Ticket #5478: Only functions or operator equal might return a temporary
if ( function - > type ! = Function : : eOperatorEqual & & function - > type ! = Function : : eFunction )
return false ;
2012-10-14 17:30:37 +02:00
retref = function - > tokenDef - > strAt ( - 1 ) = = " & " ;
if ( ! retref ) {
2013-09-03 11:40:43 +02:00
const Token * start = function - > retDef ;
2012-10-14 17:30:37 +02:00
if ( start - > str ( ) = = " const " )
start = start - > next ( ) ;
if ( start - > str ( ) = = " :: " )
start = start - > next ( ) ;
if ( Token : : simpleMatch ( start , " std :: " ) ) {
if ( start - > strAt ( 3 ) ! = " < " | | ! Token : : simpleMatch ( start - > linkAt ( 3 ) , " > :: " ) )
retvalue = true ;
else
retref = true ; // Assume that a reference is returned
} else {
2015-08-14 20:46:13 +02:00
if ( start - > type ( ) )
2012-10-14 17:30:37 +02:00
retvalue = true ;
else
retref = true ;
2012-07-19 16:42:56 +02:00
}
}
2012-10-14 17:30:37 +02:00
func = true ;
2012-07-19 16:42:56 +02:00
}
2015-08-14 20:46:13 +02:00
if ( ! func & & tok - > type ( ) )
2012-08-22 13:08:32 +02:00
return true ;
2012-07-19 16:42:56 +02:00
2017-06-01 00:49:40 +02:00
return ( ! retref & & retvalue ) ;
2010-01-27 19:16:32 +01:00
}
2011-02-08 01:26:34 +01:00
//---------------------------------------------------------------------------
2010-01-27 19:16:32 +01:00
2014-05-24 12:32:44 +02:00
static bool astHasAutoResult ( const Token * tok )
{
if ( tok - > astOperand1 ( ) & & ! astHasAutoResult ( tok - > astOperand1 ( ) ) )
return false ;
if ( tok - > astOperand2 ( ) & & ! astHasAutoResult ( tok - > astOperand2 ( ) ) )
return false ;
2015-01-31 10:12:20 +01:00
if ( tok - > isOp ( ) ) {
2016-12-22 11:49:59 +01:00
if ( tok - > tokType ( ) = = Token : : eIncDecOp )
return false ;
2015-01-31 10:12:20 +01:00
if ( ( tok - > str ( ) = = " << " | | tok - > str ( ) = = " >> " ) & & tok - > astOperand1 ( ) ) {
const Token * tok2 = tok - > astOperand1 ( ) ;
2018-07-13 23:02:52 +02:00
while ( tok2 & & tok2 - > isUnaryOp ( " * " ) )
2015-01-31 10:12:20 +01:00
tok2 = tok2 - > astOperand1 ( ) ;
return tok2 & & tok2 - > variable ( ) & & ! tok2 - > variable ( ) - > isClass ( ) & & ! tok2 - > variable ( ) - > isStlType ( ) ; // Class or unknown type on LHS: Assume it is a stream
}
2014-05-24 12:32:44 +02:00
return true ;
2015-01-31 10:12:20 +01:00
}
2014-05-24 12:32:44 +02:00
if ( tok - > isLiteral ( ) )
return true ;
if ( tok - > isName ( ) ) {
// TODO: check function calls, struct members, arrays, etc also
if ( ! tok - > variable ( ) )
return false ;
2015-01-31 10:12:20 +01:00
if ( tok - > variable ( ) - > isStlType ( ) )
2014-05-24 12:32:44 +02:00
return true ;
if ( tok - > variable ( ) - > isClass ( ) | | tok - > variable ( ) - > isPointer ( ) | | tok - > variable ( ) - > isReference ( ) ) // TODO: Properly handle pointers/references to classes in symbol database
return false ;
return true ;
}
return false ;
}
2010-01-23 20:39:12 +01:00
void CheckAutoVariables : : returnReference ( )
{
2018-06-16 16:10:28 +02:00
if ( mTokenizer - > isC ( ) )
2014-09-01 17:01:05 +02:00
return ;
2018-06-16 16:10:28 +02:00
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
2011-02-08 01:26:34 +01:00
2018-04-20 22:13:05 +02:00
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
2012-10-12 06:15:46 +02:00
if ( ! scope - > function )
2010-01-23 20:39:12 +01:00
continue ;
2011-02-08 01:26:34 +01:00
2012-03-01 18:38:20 +01:00
const Token * tok = scope - > function - > tokenDef ;
2010-01-23 20:39:12 +01:00
// have we reached a function that returns a reference?
2012-01-08 15:32:22 +01:00
if ( tok - > previous ( ) & & tok - > previous ( ) - > str ( ) = = " & " ) {
2018-04-27 22:36:30 +02:00
for ( const Token * tok2 = scope - > bodyStart - > next ( ) ; tok2 & & tok2 ! = scope - > bodyEnd ; tok2 = tok2 - > next ( ) ) {
2015-08-26 13:31:51 +02:00
if ( ! tok2 - > scope ( ) - > isExecutable ( ) ) {
2018-04-27 22:36:30 +02:00
tok2 = tok2 - > scope ( ) - > bodyEnd ;
2018-01-07 12:52:28 +01:00
if ( ! tok2 )
break ;
2015-08-26 13:31:51 +02:00
continue ;
}
2015-08-14 13:03:07 +02:00
// Skip over lambdas
2017-08-29 22:35:55 +02:00
const Token * lambdaEndToken = findLambdaEndToken ( tok2 ) ;
if ( lambdaEndToken )
tok2 = lambdaEndToken - > next ( ) ;
2015-08-14 13:03:07 +02:00
2017-02-26 13:41:49 +01:00
if ( tok2 - > str ( ) = = " ( " )
tok2 = tok2 - > link ( ) ;
if ( tok2 - > str ( ) ! = " return " )
2014-05-22 11:39:11 +02:00
continue ;
2011-02-08 01:26:34 +01:00
// return..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " return %var% ; " ) ) {
2011-02-08 01:26:34 +01:00
// is the returned variable a local variable?
2013-01-31 20:08:48 +01:00
if ( isAutoVar ( tok2 - > next ( ) ) ) {
const Variable * var1 = tok2 - > next ( ) - > variable ( ) ;
2011-12-26 07:44:16 +01:00
// If reference variable is used, check what it references
2012-03-28 18:21:06 +02:00
if ( Token : : Match ( var1 - > nameToken ( ) , " %var% [=(] " ) ) {
2011-12-26 07:44:16 +01:00
const Token * tok3 = var1 - > nameToken ( ) - > tokAt ( 2 ) ;
2012-03-28 18:21:06 +02:00
if ( ! Token : : Match ( tok3 , " %var% [);.] " ) )
2011-12-26 07:44:16 +01:00
continue ;
// Only report error if variable that is referenced is
// a auto variable
2013-01-31 20:08:48 +01:00
if ( ! isAutoVar ( tok3 ) )
2011-12-26 07:44:16 +01:00
continue ;
}
2011-12-26 07:58:02 +01:00
2010-01-27 19:16:32 +01:00
// report error..
2011-02-08 01:26:34 +01:00
errorReturnReference ( tok2 ) ;
2010-01-27 19:16:32 +01:00
}
2010-01-23 20:39:12 +01:00
}
2011-02-08 01:26:34 +01:00
// return reference to temporary..
2015-01-31 10:50:39 +01:00
else if ( Token : : Match ( tok2 , " return %name% ( " ) & &
2012-10-14 17:30:37 +02:00
Token : : simpleMatch ( tok2 - > linkAt ( 2 ) , " ) ; " ) ) {
2013-01-28 06:47:48 +01:00
if ( returnTemporary ( tok2 - > next ( ) ) ) {
2012-10-14 17:30:37 +02:00
// report error..
errorReturnTempReference ( tok2 ) ;
}
2011-02-08 01:26:34 +01:00
}
2014-05-22 11:39:11 +02:00
// Return reference to a literal or the result of a calculation
2014-05-24 12:32:44 +02:00
else if ( tok2 - > astOperand1 ( ) & & ( tok2 - > astOperand1 ( ) - > isCalculation ( ) | | tok2 - > next ( ) - > isLiteral ( ) ) & & astHasAutoResult ( tok2 - > astOperand1 ( ) ) ) {
2014-05-22 11:39:11 +02:00
errorReturnTempReference ( tok2 ) ;
}
2010-01-23 20:39:12 +01:00
}
}
}
}
void CheckAutoVariables : : errorReturnReference ( const Token * tok )
{
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : error , " returnReference " , " Reference to auto variable returned. " , CWE562 , false ) ;
2010-01-23 20:39:12 +01:00
}
2010-01-27 19:16:32 +01:00
void CheckAutoVariables : : errorReturnTempReference ( const Token * tok )
{
2016-01-25 20:01:48 +01:00
reportError ( tok , Severity : : error , " returnTempReference " , " Reference to temporary returned. " , CWE562 , false ) ;
2010-01-27 19:16:32 +01:00
}
2018-11-03 18:55:12 +01:00
void CheckAutoVariables : : errorInvalidDeallocation ( const Token * tok , const ValueFlow : : Value * val )
2011-07-21 14:50:38 +02:00
{
2018-11-03 18:59:55 +01:00
const Variable * var = val ? val - > tokvalue - > variable ( ) : ( tok ? tok - > variable ( ) : nullptr ) ;
2018-11-03 18:55:12 +01:00
std : : string type = " auto-variable " ;
if ( var ) {
if ( var - > isGlobal ( ) )
type = " global variable " ;
else if ( var - > isStatic ( ) )
type = " static variable " ;
}
if ( val )
type + = " ( " + val - > tokvalue - > str ( ) + " ) " ;
reportError ( getErrorPath ( tok , val , " Deallocating memory that was not dynamically allocated " ) ,
2011-12-30 10:32:55 +01:00
Severity : : error ,
" autovarInvalidDeallocation " ,
2018-11-03 18:55:12 +01:00
" Deallocation of an " + type + " results in undefined behaviour. \n "
" The deallocation of an " + type + " results in undefined behaviour. You should only free memory "
2016-01-25 20:01:48 +01:00
" that has been allocated dynamically. " , CWE590 , false ) ;
2011-07-21 14:50:38 +02:00
}