2009-03-19 20:55:50 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2021-03-21 20:58:32 +01:00
* Copyright ( C ) 2007 - 2021 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 "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"
2022-01-27 19:03:20 +01:00
# include "utils.h"
2017-05-27 04:33:47 +02:00
# include "valueflow.h"
2009-03-19 20:55:50 +01:00
2021-06-04 17:15:39 +02:00
# include <algorithm>
2017-05-27 04:33:47 +02:00
# include <list>
2022-01-27 19:03:20 +01:00
# include <unordered_set>
# include <utility>
# include <vector>
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 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 ( ) ;
2021-12-09 07:16:40 +01:00
return ( var & & var - > isArray ( ) & & ! var - > isArgument ( ) ) ;
2018-11-03 18:55:12 +01:00
}
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 ( ) ;
2020-01-25 16:09:58 +01:00
return ( var & & var - > isArgument ( ) & & ! var - > isReference ( ) & & ( var - > isPointer ( ) | | ( var - > valueType ( ) & & 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
}
2019-03-14 13:51:35 +01:00
static bool isAddressOfLocalVariable ( const Token * expr )
2018-12-01 10:11:02 +01:00
{
if ( ! expr )
return false ;
if ( Token : : Match ( expr , " +|- " ) )
2019-03-14 13:51:35 +01:00
return isAddressOfLocalVariable ( expr - > astOperand1 ( ) ) | | isAddressOfLocalVariable ( expr - > astOperand2 ( ) ) ;
2019-03-14 06:41:11 +01:00
if ( expr - > isCast ( ) )
2019-03-14 13:51:35 +01:00
return isAddressOfLocalVariable ( expr - > astOperand2 ( ) ? expr - > astOperand2 ( ) : expr - > astOperand1 ( ) ) ;
2019-03-14 06:41:11 +01:00
if ( expr - > isUnaryOp ( " & " ) ) {
2018-12-01 10:11:02 +01:00
const Token * op = expr - > astOperand1 ( ) ;
bool deref = false ;
while ( Token : : Match ( op , " .|[ " ) ) {
2019-03-14 06:41:11 +01:00
if ( op - > originalName ( ) = = " -> " )
return false ;
if ( op - > str ( ) = = " [ " )
2018-12-01 10:11:02 +01:00
deref = true ;
op = op - > astOperand1 ( ) ;
}
return op & & isAutoVar ( op ) & & ( ! deref | | ! op - > variable ( ) - > isPointer ( ) ) ;
}
return false ;
}
2019-07-15 13:33:29 +02:00
static bool variableIsUsedInScope ( const Token * start , nonneg 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
{
2021-02-24 22:00:06 +01:00
const bool printStyle = mSettings - > severity . isEnabled ( Severity : : style ) ;
const bool printWarning = mSettings - > severity . isEnabled ( Severity : : 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
2013-10-06 16:07:27 +02:00
void CheckAutoVariables : : autoVariables ( )
{
2021-02-24 22:00:06 +01:00
const bool printInconclusive = mSettings - > certainty . isEnabled ( Certainty : : inconclusive ) ;
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 ( ) ) {
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 ) ) )
2020-09-28 22:48:57 +02:00
checkAutoVariableAssignment ( 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 ( ) ) ) {
2020-09-28 22:48:57 +02:00
checkAutoVariableAssignment ( tok - > next ( ) , false ) ;
2019-03-14 13:51:35 +01:00
} else if ( Token : : Match ( tok , " [;{}] %var% . %var% = " ) & & isPtrArg ( tok - > next ( ) ) & & isAddressOfLocalVariable ( tok - > tokAt ( 4 ) - > astOperand2 ( ) ) ) {
2020-09-28 22:48:57 +02:00
checkAutoVariableAssignment ( tok - > next ( ) , false ) ;
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 ) ) )
2020-09-28 22:48:57 +02:00
checkAutoVariableAssignment ( 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 ) ) )
2020-09-28 22:48:57 +02:00
checkAutoVariableAssignment ( tok - > next ( ) , false ) ;
2011-07-21 01:02:54 +02:00
}
tok = tok - > tokAt ( 4 ) ;
2019-03-14 13:51:35 +01:00
} else if ( Token : : Match ( tok , " [;{}] %var% [ " ) & & Token : : simpleMatch ( tok - > linkAt ( 2 ) , " ] = " ) & &
( isPtrArg ( tok - > next ( ) ) | | isArrayArg ( tok - > next ( ) ) ) & & isAddressOfLocalVariable ( tok - > linkAt ( 2 ) - > next ( ) - > astOperand2 ( ) ) ) {
errorAutoVariableAssignment ( tok - > next ( ) , false ) ;
2011-02-08 01:26:34 +01:00
}
// Invalid pointer deallocation
2021-11-30 07:31:28 +01:00
else if ( ( Token : : Match ( tok , " %name% ( %var%|%str% ) ; " ) && mSettings->library.getDeallocFuncInfo(tok)) ||
( mTokenizer - > isCPP ( ) & & Token : : Match ( tok , " delete [| ]| (| %var%|%str% !![ " ) ) ) {
tok = Token : : findmatch ( tok - > next ( ) , " %var%|%str% " ) ;
if ( isArrayVar ( tok ) | | tok - > tokType ( ) = = Token : : eString )
2018-11-03 18:55:12 +01:00
errorInvalidDeallocation ( tok , nullptr ) ;
2021-04-28 18:05:32 +02:00
else if ( tok - > variable ( ) & & tok - > variable ( ) - > isPointer ( ) ) {
2018-11-03 18:55:12 +01:00
for ( const ValueFlow : : Value & v : tok - > values ( ) ) {
2020-07-20 06:25:35 +02:00
if ( ! ( v . isTokValue ( ) ) )
continue ;
2021-12-05 15:47:21 +01:00
if ( isArrayVar ( v . tokvalue ) | | ( ( v . tokvalue - > tokType ( ) = = Token : : eString ) & & ! v . isImpossible ( ) ) ) {
2018-11-03 18:55:12 +01:00
errorInvalidDeallocation ( tok , & v ) ;
break ;
}
}
}
2019-07-05 12:44:52 +02:00
} else if ( ( Token : : Match ( tok , " %name% ( & %var% ) ; " ) && mSettings->library.getDeallocFuncInfo(tok)) ||
2018-06-16 16:10:28 +02:00
( 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
}
}
2020-09-28 22:48:57 +02:00
bool CheckAutoVariables : : checkAutoVariableAssignment ( const Token * expr , bool inconclusive , const Token * startToken )
{
if ( ! startToken )
startToken = Token : : findsimplematch ( expr , " = " ) - > next ( ) ;
for ( const Token * tok = startToken ; tok ; tok = tok - > next ( ) ) {
if ( tok - > str ( ) = = " } " & & tok - > scope ( ) - > type = = Scope : : ScopeType : : eFunction )
errorAutoVariableAssignment ( expr , inconclusive ) ;
if ( Token : : Match ( tok , " return|throw|break|continue " ) ) {
errorAutoVariableAssignment ( expr , inconclusive ) ;
return true ;
}
if ( Token : : simpleMatch ( tok , " = " ) ) {
const Token * lhs = tok ;
while ( Token : : Match ( lhs - > previous ( ) , " %name%|.|* " ) )
lhs = lhs - > previous ( ) ;
const Token * e = expr ;
while ( e - > str ( ) ! = " = " & & lhs - > str ( ) = = e - > str ( ) ) {
e = e - > next ( ) ;
lhs = lhs - > next ( ) ;
}
if ( lhs - > str ( ) = = " = " )
return false ;
}
if ( Token : : simpleMatch ( tok , " if ( " ) ) {
const Token * ifStart = tok - > linkAt ( 1 ) - > next ( ) ;
return checkAutoVariableAssignment ( expr , inconclusive , ifStart ) | | checkAutoVariableAssignment ( expr , inconclusive , ifStart - > link ( ) - > next ( ) ) ;
}
if ( Token : : simpleMatch ( tok , " } else { " ) )
tok = tok - > linkAt ( 2 ) ;
}
return false ;
}
2011-02-08 01:26:34 +01:00
//---------------------------------------------------------------------------
2011-07-21 14:50:38 +02:00
void CheckAutoVariables : : errorReturnAddressToAutoVariable ( const Token * tok )
{
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : error , " returnAddressOfAutoVariable " , " Address of an auto-variable returned. " , CWE562 , Certainty : : normal ) ;
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 )
{
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : error , " returnAddressOfAutoVariable " , " Address of auto-variable ' " + value - > tokvalue - > astOperand1 ( ) - > expressionString ( ) + " ' returned " , CWE562 , Certainty : : normal ) ;
2018-01-27 14:48:45 +01:00
}
2009-06-09 19:45:58 +02:00
void CheckAutoVariables : : errorReturnPointerToLocalArray ( const Token * tok )
{
2021-02-24 22:00:06 +01:00
reportError ( tok , Severity : : error , " returnLocalVariable " , " Pointer to local array variable returned. " , CWE562 , Certainty : : normal ) ;
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 ) {
2019-03-15 15:13:11 +01: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 "
2021-02-24 22:00:06 +01:00
" is invalid after the function ends. " , CWE562 , Certainty : : normal ) ;
2011-10-13 20:53:06 +02:00
} else {
2019-03-15 15:13:11 +01: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 ,
2021-02-24 22:00:06 +01:00
Certainty : : inconclusive ) ;
2011-08-09 18:24:39 +02:00
}
2009-10-04 11:45:45 +02:00
}
2009-03-19 20:55:50 +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 "
2021-02-24 22:00:06 +01:00
" value is invalid. " , CWE562 , Certainty : : normal ) ;
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 " ,
2021-02-24 22:00:06 +01:00
" Assignment of function parameter has no effect outside the function. " , CWE398 , Certainty : : normal ) ;
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 " ,
2021-02-24 22:00:06 +01:00
" Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? " , CWE398 , Certainty : : normal ) ;
2013-02-01 19:16:17 +01:00
}
2011-02-08 01:26:34 +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 ;
2021-06-04 17:15:39 +02:00
if ( tok - > valueType ( ) )
return tok - > valueType ( ) - > pointer ;
int n = 0 ;
std : : pair < const Token * , const Token * > decl = Token : : typeDecl ( tok ) ;
for ( const Token * tok2 = decl . first ; tok2 ! = decl . second ; tok2 = tok2 - > next ( ) )
if ( Token : : simpleMatch ( tok , " * " ) )
n + + ;
return n ;
2018-11-17 09:41:59 +01:00
}
2019-11-03 22:02:10 +01:00
static bool isDeadTemporary ( bool cpp , const Token * tok , const Token * expr , const Library * library )
2019-10-08 09:28:39 +02:00
{
2019-11-03 22:02:10 +01:00
if ( ! isTemporary ( cpp , tok , library ) )
2019-10-08 09:28:39 +02:00
return false ;
2020-09-01 11:21:29 +02:00
if ( expr ) {
if ( ! precedes ( nextAfterAstRightmostLeaf ( tok - > astTop ( ) ) , nextAfterAstRightmostLeaf ( expr - > astTop ( ) ) ) )
return false ;
const Token * parent = tok - > astParent ( ) ;
// Is in a for loop
if ( astIsRHS ( tok ) & & Token : : simpleMatch ( parent , " : " ) & & Token : : simpleMatch ( parent - > astParent ( ) , " ( " ) & & Token : : simpleMatch ( parent - > astParent ( ) - > previous ( ) , " for ( " ) ) {
const Token * braces = parent - > astParent ( ) - > link ( ) - > next ( ) ;
if ( precedes ( braces , expr ) & & precedes ( expr , braces - > link ( ) ) )
return false ;
}
}
2019-10-08 09:28:39 +02:00
return true ;
}
2020-04-18 09:23:10 +02:00
static bool isEscapedReference ( const Variable * var )
{
if ( ! var )
return false ;
if ( ! var - > isReference ( ) )
return false ;
if ( ! var - > declEndToken ( ) )
return false ;
if ( ! Token : : simpleMatch ( var - > declEndToken ( ) , " = " ) )
return false ;
const Token * vartok = var - > declEndToken ( ) - > astOperand2 ( ) ;
return ! isTemporary ( true , vartok , nullptr , false ) ;
}
2020-09-07 04:58:36 +02:00
static bool isDanglingSubFunction ( const Token * tokvalue , const Token * tok )
{
if ( ! tokvalue )
return false ;
const Variable * var = tokvalue - > variable ( ) ;
if ( ! var - > isLocal ( ) )
return false ;
Function * f = Scope : : nestedInFunction ( tok - > scope ( ) ) ;
if ( ! f )
return false ;
const Token * parent = tokvalue - > astParent ( ) ;
2020-09-07 04:59:21 +02:00
while ( parent & & ! Token : : Match ( parent - > previous ( ) , " %name% ( " ) ) {
2020-09-07 04:58:36 +02:00
parent = parent - > astParent ( ) ;
}
if ( ! Token : : simpleMatch ( parent , " ( " ) )
return false ;
return exprDependsOnThis ( parent ) ;
}
2021-11-01 19:22:21 +01:00
static const Variable * getParentVar ( const Token * tok )
{
if ( ! tok )
return nullptr ;
if ( Token : : simpleMatch ( tok , " . " ) )
return getParentVar ( tok - > astOperand1 ( ) ) ;
return tok - > variable ( ) ;
}
2021-04-19 14:20:29 +02:00
static bool isAssignedToNonLocal ( const Token * tok )
{
if ( ! Token : : simpleMatch ( tok - > astParent ( ) , " = " ) )
return false ;
2021-11-01 19:22:21 +01:00
if ( ! astIsRHS ( tok ) )
2021-04-19 14:20:29 +02:00
return false ;
2021-11-01 19:22:21 +01:00
const Variable * var = getParentVar ( tok - > astParent ( ) - > astOperand1 ( ) ) ;
2021-04-19 14:20:29 +02:00
if ( ! var )
return false ;
return ! var - > isLocal ( ) | | var - > isStatic ( ) ;
}
2021-11-04 09:24:24 +01:00
static std : : vector < const Token * > getParentMembers ( const Token * tok )
{
if ( ! tok )
return { } ;
if ( ! Token : : simpleMatch ( tok - > astParent ( ) , " . " ) )
return { tok } ;
const Token * parent = tok ;
while ( Token : : simpleMatch ( parent - > astParent ( ) , " . " ) )
parent = parent - > astParent ( ) ;
std : : vector < const Token * > result ;
for ( const Token * tok2 : astFlatten ( parent , " . " ) ) {
if ( Token : : simpleMatch ( tok2 , " ( " ) & & Token : : simpleMatch ( tok2 - > astOperand1 ( ) , " . " ) ) {
std : : vector < const Token * > sub = getParentMembers ( tok2 - > astOperand1 ( ) ) ;
result . insert ( result . end ( ) , sub . begin ( ) , sub . end ( ) ) ;
}
result . push_back ( tok2 ) ;
}
return result ;
}
static const Token * getParentLifetime ( bool cpp , const Token * tok , const Library * library )
{
std : : vector < const Token * > members = getParentMembers ( tok ) ;
if ( members . size ( ) < 2 )
return tok ;
// Find the first local variable or temporary
auto it = std : : find_if ( members . rbegin ( ) , members . rend ( ) , [ & ] ( const Token * tok2 ) {
const Variable * var = tok2 - > variable ( ) ;
if ( var ) {
return var - > isLocal ( ) | | var - > isArgument ( ) ;
} else {
return isTemporary ( cpp , tok2 , library ) ;
}
} ) ;
if ( it = = members . rend ( ) )
return tok ;
// If any of the submembers are borrowed types then stop
if ( std : : any_of ( it . base ( ) - 1 , members . end ( ) - 1 , [ & ] ( const Token * tok2 ) {
if ( astIsPointer ( tok2 ) | | astIsContainerView ( tok2 ) | | astIsIterator ( tok2 ) )
return true ;
2021-11-11 08:00:05 +01:00
if ( ! astIsUniqueSmartPointer ( tok2 ) ) {
if ( astIsSmartPointer ( tok2 ) )
return true ;
const Token * dotTok = tok2 - > next ( ) ;
if ( ! Token : : simpleMatch ( dotTok , " . " ) ) {
const Token * endTok = nextAfterAstRightmostLeaf ( tok2 ) ;
2022-01-01 00:14:36 +01:00
if ( ! endTok )
dotTok = tok2 - > next ( ) ;
else if ( Token : : simpleMatch ( endTok , " . " ) )
2021-11-11 08:00:05 +01:00
dotTok = endTok ;
else if ( Token : : simpleMatch ( endTok - > next ( ) , " . " ) )
dotTok = endTok - > next ( ) ;
}
// If we are dereferencing the member variable then treat it as borrowed
if ( Token : : simpleMatch ( dotTok , " . " ) & & dotTok - > originalName ( ) = = " -> " )
return true ;
}
2021-11-04 09:24:24 +01:00
const Variable * var = tok2 - > variable ( ) ;
return var & & var - > isReference ( ) ;
} ) )
return nullptr ;
return * it ;
}
2018-11-10 16:40:40 +01:00
void CheckAutoVariables : : checkVarLifetimeScope ( const Token * start , const Token * end )
{
2021-02-24 22:00:06 +01:00
const bool printInconclusive = mSettings - > certainty . isEnabled ( Certainty : : inconclusive ) ;
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-05-05 11:40:59 +02:00
// Return reference from function
2019-01-23 07:29:16 +01:00
if ( returnRef & & Token : : simpleMatch ( tok - > astParent ( ) , " return " ) ) {
2020-09-07 10:52:54 +02:00
for ( const LifetimeToken & lt : getLifetimeTokens ( tok , true ) ) {
2020-09-20 14:27:09 +02:00
if ( ! printInconclusive & & lt . inconclusive )
continue ;
2019-09-11 19:25:09 +02:00
const Variable * var = lt . token - > variable ( ) ;
2019-10-08 09:28:39 +02:00
if ( var & & ! var - > isGlobal ( ) & & ! var - > isStatic ( ) & & ! var - > isReference ( ) & & ! var - > isRValueReference ( ) & &
2019-09-11 19:25:09 +02:00
isInScope ( var - > nameToken ( ) , tok - > scope ( ) ) ) {
errorReturnReference ( tok , lt . errorPath , lt . inconclusive ) ;
break ;
2019-11-03 22:02:10 +01:00
} else if ( isDeadTemporary ( mTokenizer - > isCPP ( ) , lt . token , nullptr , & mSettings - > library ) ) {
2019-10-08 09:28:39 +02:00
errorReturnTempReference ( tok , lt . errorPath , lt . inconclusive ) ;
break ;
2019-09-11 19:25:09 +02:00
}
2019-01-23 07:29:16 +01:00
}
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 ;
}
2020-09-09 01:30:45 +02:00
// Reference to temporary
} else if ( tok - > variable ( ) & & ( tok - > variable ( ) - > isReference ( ) | | tok - > variable ( ) - > isRValueReference ( ) ) ) {
for ( const LifetimeToken & lt : getLifetimeTokens ( getParentLifetime ( tok ) ) ) {
2020-09-20 14:27:09 +02:00
if ( ! printInconclusive & & lt . inconclusive )
continue ;
2020-09-09 01:30:45 +02:00
const Token * tokvalue = lt . token ;
if ( isDeadTemporary ( mTokenizer - > isCPP ( ) , tokvalue , tok , & mSettings - > library ) ) {
errorDanglingTempReference ( tok , lt . errorPath , lt . inconclusive ) ;
break ;
}
}
2019-01-23 07:29:16 +01:00
}
2021-10-05 08:28:19 +02:00
const bool escape = Token : : Match ( tok - > astParent ( ) , " return|throw " ) ;
2021-11-04 09:24:24 +01:00
std : : unordered_set < const Token * > exprs ;
2018-11-10 21:30:01 +01:00
for ( const ValueFlow : : Value & val : tok - > values ( ) ) {
2020-09-04 18:56:34 +02:00
if ( ! val . isLocalLifetimeValue ( ) & & ! val . isSubFunctionLifetimeValue ( ) )
2018-11-10 16:40:40 +01:00
continue ;
2020-09-20 14:27:09 +02:00
if ( ! printInconclusive & & val . isInconclusive ( ) )
continue ;
2021-11-04 09:24:24 +01:00
const Token * parent = getParentLifetime ( mTokenizer - > isCPP ( ) , val . tokvalue , & mSettings - > library ) ;
if ( ! exprs . insert ( parent ) . second )
continue ;
for ( const LifetimeToken & lt : getLifetimeTokens ( parent , escape | | isAssignedToNonLocal ( tok ) ) ) {
2020-03-23 22:54:53 +01:00
const Token * tokvalue = lt . token ;
2020-09-04 18:56:34 +02:00
if ( val . isLocalLifetimeValue ( ) ) {
2020-09-08 18:00:57 +02:00
if ( escape ) {
2020-09-04 18:56:34 +02:00
if ( getPointerDepth ( tok ) < getPointerDepth ( tokvalue ) )
continue ;
if ( ! isLifetimeBorrowed ( tok , mSettings ) )
continue ;
2021-10-05 08:28:19 +02:00
if ( tokvalue - > exprId ( ) = = tok - > exprId ( ) & & ! ( tok - > variable ( ) & & tok - > variable ( ) - > isArray ( ) ) & &
! astIsContainerView ( tok - > astParent ( ) ) )
2021-02-03 10:22:31 +01:00
continue ;
2020-09-04 18:56:34 +02:00
if ( ( tokvalue - > variable ( ) & & ! isEscapedReference ( tokvalue - > variable ( ) ) & &
isInScope ( tokvalue - > variable ( ) - > nameToken ( ) , scope ) ) | |
2021-11-28 15:25:21 +01:00
isDeadTemporary ( mTokenizer - > isCPP ( ) , tokvalue , nullptr , & mSettings - > library ) ) {
2020-09-04 18:56:34 +02:00
errorReturnDanglingLifetime ( tok , & val ) ;
break ;
}
} else if ( tokvalue - > variable ( ) & & isDeadScope ( tokvalue - > variable ( ) - > nameToken ( ) , tok - > scope ( ) ) ) {
errorInvalidLifetime ( tok , & val ) ;
break ;
2020-09-04 18:59:30 +02:00
} else if ( ! tokvalue - > variable ( ) & &
isDeadTemporary ( mTokenizer - > isCPP ( ) , tokvalue , tok , & mSettings - > library ) ) {
2021-11-01 19:23:15 +01:00
errorDanglingTemporaryLifetime ( tok , & val , tokvalue ) ;
2020-03-23 22:54:53 +01:00
break ;
2019-07-07 10:16:19 +02:00
}
2020-09-04 18:56:34 +02:00
}
2020-09-04 18:59:30 +02:00
if ( tokvalue - > variable ( ) & & ( isInScope ( tokvalue - > variable ( ) - > nameToken ( ) , tok - > scope ( ) ) | |
2020-09-07 04:58:36 +02:00
( val . isSubFunctionLifetimeValue ( ) & & isDanglingSubFunction ( tokvalue , tok ) ) ) ) {
2020-03-23 22:54:53 +01:00
const Variable * var = nullptr ;
const Token * tok2 = tok ;
if ( Token : : simpleMatch ( tok - > astParent ( ) , " = " ) ) {
2021-11-01 19:22:21 +01:00
if ( astIsRHS ( tok ) ) {
var = getParentVar ( tok - > astParent ( ) - > astOperand1 ( ) ) ;
2020-03-23 22:54:53 +01:00
tok2 = tok - > astParent ( ) - > astOperand1 ( ) ;
}
} else if ( tok - > variable ( ) & & tok - > variable ( ) - > declarationId ( ) = = tok - > varId ( ) ) {
var = tok - > variable ( ) ;
}
if ( ! isLifetimeBorrowed ( tok , mSettings ) )
continue ;
2021-04-18 21:42:27 +02:00
const Token * nextTok = nextAfterAstRightmostLeaf ( tok - > astTop ( ) ) ;
if ( ! nextTok )
nextTok = tok - > next ( ) ;
if ( var & & ! var - > isLocal ( ) & & ! var - > isArgument ( ) & &
! isVariableChanged ( nextTok ,
tok - > scope ( ) - > bodyEnd ,
var - > declarationId ( ) ,
var - > isGlobal ( ) ,
mSettings ,
mTokenizer - > isCPP ( ) ) ) {
2020-03-23 22:54:53 +01:00
errorDanglngLifetime ( tok2 , & val ) ;
break ;
}
2019-07-07 10:16:19 +02:00
}
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
void CheckAutoVariables : : errorReturnDanglingLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
2019-09-11 19:25:09 +02:00
const bool inconclusive = val ? val - > isInconclusive ( ) : false ;
2018-11-21 08:43:57 +01:00
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 , " " ) ;
2021-02-24 22:00:06 +01:00
reportError ( errorPath , Severity : : error , " returnDanglingLifetime " , msg + " that will be invalid when returning. " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2018-11-10 16:40:40 +01:00
}
2018-11-11 16:43:54 +01:00
void CheckAutoVariables : : errorInvalidLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
2019-09-11 19:25:09 +02:00
const bool inconclusive = val ? val - > isInconclusive ( ) : false ;
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 , " " ) ;
2021-02-24 22:00:06 +01:00
reportError ( errorPath , Severity : : error , " invalidLifetime " , msg + " that is out of scope. " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2018-11-11 16:43:54 +01:00
}
2021-11-01 19:23:15 +01:00
void CheckAutoVariables : : errorDanglingTemporaryLifetime ( const Token * tok , const ValueFlow : : Value * val , const Token * tempTok )
2019-10-08 09:28:39 +02:00
{
const bool inconclusive = val ? val - > isInconclusive ( ) : false ;
ErrorPath errorPath = val ? val - > errorPath : ErrorPath ( ) ;
std : : string msg = " Using " + lifetimeMessage ( tok , val , errorPath ) ;
2021-11-01 19:23:15 +01:00
errorPath . emplace_back ( tempTok , " Temporary created here. " ) ;
2019-10-08 09:28:39 +02:00
errorPath . emplace_back ( tok , " " ) ;
2021-11-01 19:23:15 +01:00
reportError ( errorPath ,
Severity : : error ,
" danglingTemporaryLifetime " ,
msg + " that is a temporary. " ,
CWE562 ,
inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2019-10-08 09:28:39 +02:00
}
2018-11-21 08:43:57 +01:00
void CheckAutoVariables : : errorDanglngLifetime ( const Token * tok , const ValueFlow : : Value * val )
{
2019-09-11 19:25:09 +02:00
const bool inconclusive = val ? val - > isInconclusive ( ) : false ;
2018-11-21 08:43:57 +01:00
ErrorPath errorPath = val ? val - > errorPath : ErrorPath ( ) ;
2019-07-07 10:16:19 +02:00
std : : string tokName = tok ? tok - > expressionString ( ) : " x " ;
2018-11-21 08:43:57 +01:00
std : : string msg = " Non-local variable ' " + tokName + " ' will use " + lifetimeMessage ( tok , val , errorPath ) ;
errorPath . emplace_back ( tok , " " ) ;
2021-02-24 22:00:06 +01:00
reportError ( errorPath , Severity : : error , " danglingLifetime " , msg + " . " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2018-11-21 08:43:57 +01:00
}
2020-09-09 01:30:45 +02:00
void CheckAutoVariables : : errorDanglingTempReference ( const Token * tok , ErrorPath errorPath , bool inconclusive )
{
errorPath . emplace_back ( tok , " " ) ;
reportError (
2021-02-24 22:00:06 +01:00
errorPath , Severity : : error , " danglingTempReference " , " Using reference to dangling temporary. " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2020-09-09 01:30:45 +02:00
}
2019-09-11 19:25:09 +02:00
void CheckAutoVariables : : errorReturnReference ( const Token * tok , ErrorPath errorPath , bool inconclusive )
2019-01-23 07:29:16 +01:00
{
errorPath . emplace_back ( tok , " " ) ;
2019-09-11 19:25:09 +02:00
reportError (
2021-02-24 22:00:06 +01:00
errorPath , Severity : : error , " returnReference " , " Reference to local variable returned. " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
2019-01-23 07:29:16 +01:00
}
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 , " " ) ;
2021-02-24 22:00:06 +01:00
reportError ( errorPath , Severity : : error , " danglingReference " , msg , CWE562 , Certainty : : normal ) ;
2010-01-23 20:39:12 +01:00
}
2019-10-08 09:28:39 +02:00
void CheckAutoVariables : : errorReturnTempReference ( const Token * tok , ErrorPath errorPath , bool inconclusive )
2010-01-27 19:16:32 +01:00
{
2019-10-08 09:28:39 +02:00
errorPath . emplace_back ( tok , " " ) ;
reportError (
2021-02-24 22:00:06 +01:00
errorPath , Severity : : error , " returnTempReference " , " Reference to temporary returned. " , CWE562 , inconclusive ? Certainty : : inconclusive : Certainty : : normal ) ;
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
2021-12-23 20:09:55 +01:00
std : : string type = " an auto-variable " ;
2021-11-30 07:31:28 +01:00
if ( tok & & tok - > tokType ( ) = = Token : : eString )
2021-12-23 20:09:55 +01:00
type = " a string literal " ;
2021-11-30 07:31:28 +01:00
else if ( val & & val - > tokvalue - > tokType ( ) = = Token : : eString )
2021-12-23 20:09:55 +01:00
type = " a pointer pointing to a string literal " ;
2021-11-30 07:31:28 +01:00
else if ( var ) {
2018-11-03 18:55:12 +01:00
if ( var - > isGlobal ( ) )
2021-12-23 20:09:55 +01:00
type = " a global variable " ;
2018-11-03 18:55:12 +01:00
else if ( var - > isStatic ( ) )
2021-12-23 20:09:55 +01:00
type = " a static variable " ;
2018-11-03 18:55:12 +01:00
}
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 " ,
2021-12-23 20:09:55 +01:00
" Deallocation of " + type + " results in undefined behaviour. \n "
" The deallocation of " + type + " results in undefined behaviour. You should only free memory "
2021-02-24 22:00:06 +01:00
" that has been allocated dynamically. " , CWE590 , Certainty : : normal ) ;
2011-07-21 14:50:38 +02:00
}