2009-03-19 20:55:50 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2019-02-09 07:24:06 +01:00
* Copyright ( C ) 2007 - 2019 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>
2018-11-10 16:40:40 +01:00
# include <functional>
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
}
2018-12-01 10:11:02 +01:00
static bool isAddressOfLocalVariableRecursive ( const Token * expr )
{
if ( ! expr )
return false ;
if ( Token : : Match ( expr , " +|- " ) )
return isAddressOfLocalVariableRecursive ( expr - > astOperand1 ( ) ) | | isAddressOfLocalVariableRecursive ( expr - > astOperand2 ( ) ) ;
if ( expr - > str ( ) = = " ( " & & ! expr - > astOperand2 ( ) )
return isAddressOfLocalVariableRecursive ( expr - > astOperand1 ( ) ) ;
if ( expr - > str ( ) = = " & " & & ! expr - > astOperand2 ( ) ) {
const Token * op = expr - > astOperand1 ( ) ;
bool deref = false ;
while ( Token : : Match ( op , " .|[ " ) ) {
2019-02-18 09:35:07 +01:00
if ( op - > str ( ) = = " [ " | | op - > originalName ( ) = = " -> " )
2018-12-01 10:11:02 +01:00
deref = true ;
op = op - > astOperand1 ( ) ;
}
return op & & isAutoVar ( op ) & & ( ! deref | | ! op - > variable ( ) - > isPointer ( ) ) ;
}
return false ;
}
static bool isAddressOfLocalVariable ( const Token * expr )
{
if ( ! expr | | ! expr - > valueType ( ) | | expr - > valueType ( ) - > pointer = = 0 )
return false ;
return isAddressOfLocalVariableRecursive ( expr ) ;
}
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 ( ) ) {
2018-11-11 07:52:38 +01:00
// Skip lambda..
if ( const Token * lambdaEndToken = findLambdaEndToken ( tok ) ) {
tok = lambdaEndToken ;
continue ;
}
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 ) ;
2018-12-01 10:11:02 +01:00
} else if ( Token : : Match ( tok , " [;{}] * %var% = " ) & & isPtrArg ( tok - > tokAt ( 2 ) ) & & isAddressOfLocalVariable ( tok - > tokAt ( 3 ) - > astOperand2 ( ) ) ) {
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
}
// 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
}
}
//---------------------------------------------------------------------------
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 reference to temporary..
2019-01-23 07:29:16 +01:00
if ( Token : : Match ( tok2 , " return %name% ( " ) & & 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
2019-01-23 07:29:16 +01: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
}
}
}
}
2018-11-10 16:40:40 +01:00
static bool isInScope ( const Token * tok , const Scope * scope )
{
2018-11-10 21:30:01 +01:00
if ( ! tok )
2018-11-10 16:40:40 +01:00
return false ;
2018-11-10 21:30:01 +01:00
if ( ! scope )
2018-11-10 16:40:40 +01:00
return false ;
const Variable * var = tok - > variable ( ) ;
2018-11-10 21:30:01 +01:00
if ( var & & ( var - > isGlobal ( ) | | var - > isStatic ( ) | | var - > isExtern ( ) ) )
2018-11-10 16:40:40 +01:00
return false ;
2018-11-10 21:30:01 +01:00
if ( tok - > scope ( ) & & tok - > scope ( ) - > isNestedIn ( scope ) )
2018-11-10 16:40:40 +01:00
return true ;
2018-11-10 21:30:01 +01:00
if ( ! var )
2018-11-10 16:40:40 +01:00
return false ;
2018-11-10 21:30:01 +01:00
if ( var - > isArgument ( ) & & ! var - > isReference ( ) ) {
2018-11-10 16:40:40 +01:00
const Scope * tokScope = tok - > scope ( ) ;
2018-11-10 21:30:01 +01:00
if ( ! tokScope )
2018-11-10 16:40:40 +01:00
return false ;
2018-11-10 21:30:01 +01:00
for ( const Scope * argScope : tokScope - > nestedList ) {
if ( argScope & & argScope - > isNestedIn ( scope ) )
2018-11-10 16:40:40 +01:00
return true ;
}
}
return false ;
}
2018-11-11 16:43:54 +01:00
static bool isDeadScope ( const Token * tok , const Scope * scope )
{
if ( ! tok )
return false ;
if ( ! scope )
return false ;
const Variable * var = tok - > variable ( ) ;
if ( var & & ( ! var - > isLocal ( ) | | var - > isStatic ( ) | | var - > isExtern ( ) ) )
return false ;
if ( tok - > scope ( ) & & tok - > scope ( ) - > bodyEnd ! = scope - > bodyEnd & & precedes ( tok - > scope ( ) - > bodyEnd , scope - > bodyEnd ) )
return true ;
return false ;
}
2018-11-17 09:41:59 +01:00
static int getPointerDepth ( const Token * tok )
{
if ( ! tok )
return 0 ;
return tok - > valueType ( ) ? tok - > valueType ( ) - > pointer : 0 ;
}
2018-11-10 16:40:40 +01:00
void CheckAutoVariables : : checkVarLifetimeScope ( const Token * start , const Token * end )
{
2018-11-10 21:30:01 +01:00
if ( ! start )
2018-11-10 16:40:40 +01:00
return ;
const Scope * scope = start - > scope ( ) ;
2018-11-10 21:30:01 +01:00
if ( ! scope )
2018-11-10 16:40:40 +01:00
return ;
// If the scope is not set correctly then skip checking it
2018-11-10 21:30:01 +01:00
if ( scope - > bodyStart ! = start )
2018-11-10 16:40:40 +01:00
return ;
2019-01-23 07:29:16 +01:00
bool returnRef = Function : : returnsReference ( scope - > function ) ;
2018-11-10 16:40:40 +01:00
for ( const Token * tok = start ; tok & & tok ! = end ; tok = tok - > next ( ) ) {
2019-02-22 06:38:56 +01:00
// Return reference form function
2019-01-23 07:29:16 +01:00
if ( returnRef & & Token : : simpleMatch ( tok - > astParent ( ) , " return " ) ) {
ErrorPath errorPath ;
const Variable * var = getLifetimeVariable ( tok , errorPath ) ;
2019-01-26 11:03:57 +01:00
if ( var & & ! var - > isGlobal ( ) & & ! var - > isStatic ( ) & & ! var - > isReference ( ) & & ! var - > isRValueReference ( ) & &
isInScope ( var - > nameToken ( ) , tok - > scope ( ) ) ) {
2019-01-23 07:29:16 +01:00
errorReturnReference ( tok , errorPath ) ;
continue ;
}
2019-02-22 06:38:56 +01:00
// Assign reference to non-local variable
2019-03-09 19:09:15 +01:00
} else if ( Token : : Match ( tok - > previous ( ) , " &|&& %var% = " ) & & tok - > astParent ( ) = = tok - > next ( ) & &
tok - > variable ( ) & & tok - > variable ( ) - > nameToken ( ) = = tok & &
tok - > variable ( ) - > declarationId ( ) = = tok - > varId ( ) & & tok - > variable ( ) - > isStatic ( ) & &
2019-01-23 07:29:16 +01:00
! tok - > variable ( ) - > isArgument ( ) ) {
ErrorPath errorPath ;
const Variable * var = getLifetimeVariable ( tok , errorPath ) ;
if ( var & & isInScope ( var - > nameToken ( ) , tok - > scope ( ) ) ) {
errorDanglingReference ( tok , var , errorPath ) ;
continue ;
}
}
2018-11-10 21:30:01 +01:00
for ( const ValueFlow : : Value & val : tok - > values ( ) ) {
2019-01-29 09:47:52 +01:00
if ( ! val . isLocalLifetimeValue ( ) )
2018-11-10 16:40:40 +01:00
continue ;
2019-02-22 06:38:56 +01:00
if ( ! val . tokvalue - > variable ( ) )
2018-11-14 06:59:25 +01:00
continue ;
2018-11-10 21:30:01 +01:00
if ( Token : : Match ( tok - > astParent ( ) , " return|throw " ) ) {
2018-11-21 08:43:57 +01:00
if ( getPointerDepth ( tok ) < getPointerDepth ( val . tokvalue ) )
continue ;
if ( tok - > astParent ( ) - > str ( ) = = " return " & & ! astIsContainer ( tok ) & & scope - > function & &
mSettings - > library . detectContainer ( scope - > function - > retDef ) )
continue ;
2019-02-22 06:38:56 +01:00
if ( isInScope ( val . tokvalue - > variable ( ) - > nameToken ( ) , scope ) ) {
2018-11-10 16:40:40 +01:00
errorReturnDanglingLifetime ( tok , & val ) ;
break ;
}
2019-02-22 06:38:56 +01:00
} else if ( isDeadScope ( val . tokvalue - > variable ( ) - > nameToken ( ) , tok - > scope ( ) ) ) {
2018-11-11 16:43:54 +01:00
errorInvalidLifetime ( tok , & val ) ;
break ;
2018-12-01 19:07:46 +01:00
} else if ( tok - > variable ( ) & & tok - > variable ( ) - > declarationId ( ) = = tok - > varId ( ) & &
! tok - > variable ( ) - > isLocal ( ) & & ! tok - > variable ( ) - > isArgument ( ) & &
2018-11-21 08:43:57 +01:00
isInScope ( val . tokvalue , tok - > scope ( ) ) ) {
errorDanglngLifetime ( tok , & val ) ;
break ;
2018-11-10 16:40:40 +01:00
}
}
const Token * lambdaEndToken = findLambdaEndToken ( tok ) ;
2018-11-10 21:30:01 +01:00
if ( lambdaEndToken ) {
2018-11-10 16:40:40 +01:00
checkVarLifetimeScope ( lambdaEndToken - > link ( ) , lambdaEndToken ) ;
tok = lambdaEndToken ;
}
2019-01-11 09:51:02 +01:00
if ( tok - > str ( ) = = " { " & & tok - > scope ( ) ) {
// Check functions in local classes
2019-01-11 12:56:31 +01:00
if ( tok - > scope ( ) - > type = = Scope : : eClass | |
tok - > scope ( ) - > type = = Scope : : eStruct | |
2019-01-11 09:51:02 +01:00
tok - > scope ( ) - > type = = Scope : : eUnion ) {
2019-01-11 12:56:31 +01:00
for ( const Function & f : tok - > scope ( ) - > functionList ) {
2019-01-11 09:51:02 +01:00
if ( f . functionScope )
checkVarLifetimeScope ( f . functionScope - > bodyStart , f . functionScope - > bodyEnd ) ;
}
tok = tok - > link ( ) ;
}
}
2018-11-10 16:40:40 +01:00
}
}
void CheckAutoVariables : : checkVarLifetime ( )
{
const SymbolDatabase * symbolDatabase = mTokenizer - > getSymbolDatabase ( ) ;
for ( const Scope * scope : symbolDatabase - > functionScopes ) {
if ( ! scope - > function )
continue ;
checkVarLifetimeScope ( scope - > bodyStart , scope - > bodyEnd ) ;
}
}
2018-11-21 08:43:57 +01:00
static std : : string lifetimeMessage ( const Token * tok , const ValueFlow : : Value * val , ErrorPath & errorPath )
2018-11-12 10:08:17 +01:00
{
2019-02-22 06:38:56 +01:00
const Token * tokvalue = val ? val - > tokvalue : nullptr ;
const Variable * tokvar = tokvalue ? tokvalue - > variable ( ) : nullptr ;
const Token * vartok = tokvar ? tokvar - > nameToken ( ) : nullptr ;
2018-11-12 10:08:17 +01:00
std : : string type = lifetimeType ( tok , val ) ;
2018-11-21 08:43:57 +01:00
std : : string msg = type ;
2018-11-10 21:30:01 +01:00
if ( vartok ) {
2018-11-10 16:40:40 +01:00
errorPath . emplace_back ( vartok , " Variable created here. " ) ;
const Variable * var = vartok - > variable ( ) ;
2018-11-10 21:30:01 +01:00
if ( var ) {
switch ( val - > lifetimeKind ) {
case ValueFlow : : Value : : Object :
2018-11-12 10:08:57 +01:00
if ( type = = " pointer " )
2018-11-12 10:08:17 +01:00
msg + = " to local variable " ;
else
msg + = " that points to local variable " ;
2018-11-10 21:30:01 +01:00
break ;
case ValueFlow : : Value : : Lambda :
msg + = " that captures local variable " ;
break ;
case ValueFlow : : Value : : Iterator :
msg + = " to local container " ;
break ;
2018-11-10 16:40:40 +01:00
}
msg + = " ' " + var - > name ( ) + " ' " ;
}
}
2018-11-21 08:43:57 +01:00
return msg ;
}
void CheckAutoVariables : : errorReturnDanglingLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
ErrorPath errorPath = val ? val - > errorPath : ErrorPath ( ) ;
std : : string msg = " Returning " + lifetimeMessage ( tok , val , errorPath ) ;
2018-11-10 16:40:40 +01:00
errorPath . emplace_back ( tok , " " ) ;
reportError ( errorPath , Severity : : error , " returnDanglingLifetime " , msg + " that will be invalid when returning. " , CWE562 , false ) ;
}
2018-11-11 16:43:54 +01:00
void CheckAutoVariables : : errorInvalidLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
2018-11-12 10:08:17 +01:00
ErrorPath errorPath = val ? val - > errorPath : ErrorPath ( ) ;
2018-11-21 08:43:57 +01:00
std : : string msg = " Using " + lifetimeMessage ( tok , val , errorPath ) ;
2018-11-11 16:43:54 +01:00
errorPath . emplace_back ( tok , " " ) ;
reportError ( errorPath , Severity : : error , " invalidLifetime " , msg + " that is out of scope. " , CWE562 , false ) ;
}
2018-11-21 08:43:57 +01:00
void CheckAutoVariables : : errorDanglngLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
ErrorPath errorPath = val ? val - > errorPath : ErrorPath ( ) ;
std : : string tokName = tok ? tok - > str ( ) : " x " ;
std : : string msg = " Non-local variable ' " + tokName + " ' will use " + lifetimeMessage ( tok , val , errorPath ) ;
errorPath . emplace_back ( tok , " " ) ;
reportError ( errorPath , Severity : : error , " danglingLifetime " , msg + " . " , CWE562 , false ) ;
}
2019-01-23 07:29:16 +01:00
void CheckAutoVariables : : errorReturnReference ( const Token * tok , ErrorPath errorPath )
{
errorPath . emplace_back ( tok , " " ) ;
reportError ( errorPath , Severity : : error , " returnReference " , " Reference to local variable returned. " , CWE562 , false ) ;
}
void CheckAutoVariables : : errorDanglingReference ( const Token * tok , const Variable * var , ErrorPath errorPath )
2010-01-23 20:39:12 +01:00
{
2019-01-23 07:29:16 +01:00
std : : string tokName = tok ? tok - > str ( ) : " x " ;
std : : string varName = var ? var - > name ( ) : " y " ;
std : : string msg = " Non-local reference variable ' " + tokName + " ' to local variable ' " + varName + " ' " ;
errorPath . emplace_back ( tok , " " ) ;
reportError ( errorPath , Severity : : error , " danglingReference " , msg , 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
}