2009-03-19 20:55:50 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2015-01-03 12:14:58 +01:00
* Copyright ( C ) 2007 - 2015 Daniel Marjamäki and 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"
2011-01-16 19:57:29 +01:00
# include "symboldatabase.h"
2009-03-19 20:55:50 +01:00
# include <string>
//---------------------------------------------------------------------------
// Register this check class into cppcheck by creating a static instance of it..
2011-10-13 20:53:06 +02:00
namespace {
static CheckAutoVariables instance ;
2009-03-19 20:55:50 +01:00
}
2013-02-18 17:52:49 +01:00
bool CheckAutoVariables : : isPtrArg ( const Token * tok )
{
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
}
2015-08-25 21:19:19 +02:00
bool CheckAutoVariables : : isArrayArg ( const Token * tok )
{
const Variable * var = tok - > variable ( ) ;
return ( var & & var - > isArgument ( ) & & var - > isArray ( ) ) ;
}
2013-01-31 20:08:48 +01:00
bool CheckAutoVariables : : 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 ( ) ;
2011-04-23 15:50:56 +02:00
2013-08-07 16:27:37 +02:00
return ( var & & var - > isArgument ( ) & & var - > isReference ( ) & & var - > isPointer ( ) ) ;
2012-03-01 18:38:20 +01:00
}
2013-02-18 17:52:49 +01:00
bool CheckAutoVariables : : 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 ( ) ;
2009-03-19 20:55:50 +01:00
2013-08-07 16:27:37 +02:00
return ( var & & var - > isArgument ( ) & & ! var - > isReference ( ) & & ( var - > isPointer ( ) | | var - > typeStartToken ( ) - > isStandardType ( ) | | var - > type ( ) ) ) ;
2009-03-19 20:55:50 +01:00
}
2009-07-27 19:34:17 +02:00
2013-01-31 20:08:48 +01:00
bool CheckAutoVariables : : 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 ;
}
2011-04-23 15:50:56 +02:00
return true ;
2009-08-09 15:40:04 +02:00
}
2013-01-31 20:08:48 +01:00
bool CheckAutoVariables : : isAutoVarArray ( const Token * tok )
2009-03-21 18:36:41 +01:00
{
2013-01-31 20:08:48 +01:00
const Variable * var = tok - > variable ( ) ;
2009-07-27 19:34:17 +02:00
2014-04-27 10:56:55 +02:00
return ( var & & var - > isLocal ( ) & & ! var - > isStatic ( ) & & var - > isArray ( ) & & ! var - > isPointer ( ) ) ;
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
2014-03-22 11:14:11 +01:00
for ( const Token * tok = start ; tok & & tok ! = scope - > classEnd ; 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
{
2015-04-10 14:18:52 +02:00
const bool printStyle = _settings - > isEnabled ( " style " ) ;
const bool printWarning = _settings - > isEnabled ( " warning " ) ;
if ( ! printStyle & & ! printWarning )
2013-10-06 16:07:27 +02:00
return ;
2014-08-04 11:45:24 +02:00
2011-02-08 01:26:34 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2013-10-06 16:07:27 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; tok = tok - > next ( ) ) {
2014-08-04 11:45:24 +02:00
if ( Token : : Match ( tok , " [;{}] %var% =|++|-- " ) & &
2013-10-06 16:07:27 +02:00
isNonReferenceArg ( tok - > next ( ) ) & &
2015-08-09 14:51:23 +02:00
! Token : : Match ( tok - > tokAt ( 2 ) , " = %varid% ; " , tok - > next ( ) - > varId ( ) ) & &
2014-10-21 16:21:33 +02:00
! variableIsUsedInScope ( Token : : findsimplematch ( tok - > tokAt ( 2 ) , " ; " ) , tok - > next ( ) - > varId ( ) , scope ) & &
! Token : : findsimplematch ( tok , " goto " , scope - > classEnd ) ) {
2015-04-10 14:18:52 +02:00
if ( tok - > next ( ) - > variable ( ) - > isPointer ( ) & & printWarning )
2014-08-04 11:45:24 +02:00
errorUselessAssignmentPtrArg ( tok - > next ( ) ) ;
2015-04-10 14:18:52 +02:00
else if ( printStyle )
2014-08-04 11:45:24 +02:00
errorUselessAssignmentArg ( tok - > next ( ) ) ;
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 ( )
{
2015-04-10 14:18:52 +02:00
const bool printInconclusive = _settings - > inconclusive ;
2013-10-06 16:07:27 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-10-12 06:15:46 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
2012-01-08 15:32:22 +01:00
for ( const Token * tok = scope - > classStart ; tok & & tok ! = scope - > classEnd ; 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 ) ;
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-04-10 14:18:52 +02:00
if ( printInconclusive ) {
2015-07-05 17:15:13 +02:00
if ( isPtrArg ( tok - > next ( ) ) ) {
2013-06-13 16:19:19 +02:00
const Token * const var2tok = tok - > tokAt ( 6 ) ;
if ( isAutoVar ( var2tok ) & & checkRvalueExpression ( var2tok ) )
2012-03-01 18:38:20 +01:00
errorAutoVariableAssignment ( tok - > next ( ) , true ) ;
2011-08-09 18:24:39 +02:00
}
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-04-10 14:18:52 +02:00
if ( printInconclusive ) {
2015-07-05 17:15:13 +02:00
if ( isPtrArg ( tok - > next ( ) ) ) {
2013-01-31 20:08:48 +01:00
if ( isAutoVarArray ( tok - > tokAt ( 5 ) ) )
2012-03-01 18:38:20 +01:00
errorAutoVariableAssignment ( tok - > next ( ) , true ) ;
2011-08-09 18:24:39 +02:00
}
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-25 21:19:19 +02:00
} else if ( Token : : Match ( tok , " [;{}] %var% [ " ) & & Token : : Match ( tok - > linkAt ( 2 ) , " ] = & %var% " ) & & 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
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-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok , " return & %var% [ " ) & &
2011-11-20 14:22:39 +01:00
Token : : simpleMatch ( tok - > linkAt ( 3 ) , " ] ; " ) & &
2013-01-31 20:08:48 +01:00
isAutoVarArray ( tok - > tokAt ( 2 ) ) ) {
2011-08-20 21:08:30 +02:00
errorReturnAddressToAutoVariable ( tok ) ;
2011-09-01 03:36:31 +02:00
}
2011-02-08 01:26:34 +01:00
// Invalid pointer deallocation
2015-06-20 21:00:54 +02:00
else if ( ( Token : : Match ( tok , " %name% ( %var% ) ; " ) && _settings->library.dealloc(tok)) ||
( _tokenizer - > isCPP ( ) & & Token : : Match ( tok , " delete [| ]| (| %var% !![ " ) ) ) {
2012-04-26 16:44:33 +02:00
tok = Token : : findmatch ( tok - > next ( ) , " %var% " ) ;
2013-01-31 20:08:48 +01:00
if ( isAutoVarArray ( tok ) )
2012-04-26 16:44:33 +02:00
errorInvalidDeallocation ( tok ) ;
2015-06-20 21:00:54 +02:00
} else if ( ( Token : : Match ( tok , " %name% ( & %var% ) ; " ) && _settings->library.dealloc(tok)) ||
( _tokenizer - > 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 ) )
2014-03-06 06:32:30 +01:00
errorInvalidDeallocation ( tok ) ;
}
2009-06-09 19:45:58 +02:00
}
2011-02-08 01:26:34 +01:00
}
}
//---------------------------------------------------------------------------
void CheckAutoVariables : : returnPointerToLocalArray ( )
{
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-10-12 06:15:46 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
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 ( ) = = " * " ) {
2012-10-12 06:15:46 +02:00
for ( const Token * tok2 = scope - > classStart - > next ( ) ; tok2 & & tok2 ! = scope - > classEnd ; tok2 = tok2 - > next ( ) ) {
2011-02-08 01:26:34 +01:00
// Return pointer to local array variable..
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " return %var% ; " ) ) {
2013-01-31 20:08:48 +01:00
if ( isAutoVarArray ( tok2 - > next ( ) ) ) {
2011-02-08 01:26:34 +01:00
errorReturnPointerToLocalArray ( tok2 ) ;
}
}
}
}
2009-06-09 19:45:58 +02:00
}
}
2011-07-21 14:50:38 +02:00
void CheckAutoVariables : : errorReturnAddressToAutoVariable ( const Token * tok )
{
2012-07-07 20:31:18 +02:00
reportError ( tok , Severity : : error , " returnAddressOfAutoVariable " , " Address of an auto-variable returned. " ) ;
2011-07-21 14:50:38 +02:00
}
2009-06-09 19:45:58 +02:00
void CheckAutoVariables : : errorReturnPointerToLocalArray ( const Token * tok )
{
2012-07-07 20:31:18 +02:00
reportError ( tok , Severity : : error , " returnLocalVariable " , " Pointer to local array variable returned. " ) ;
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 "
2011-08-09 18:24:39 +02:00
" is invalid after the function ends. " ) ;
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. " ,
0U ,
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
2011-09-01 03:36:31 +02:00
void CheckAutoVariables : : errorReturnAddressOfFunctionParameter ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " returnAddressOfFunctionParameter " ,
2012-07-07 20:31:18 +02:00
" Address of function parameter ' " + varname + " ' returned. \n "
" Address of the function parameter ' " + varname + " ' becomes invalid after the function exits because "
" function parameters are stored on the stack which is freed when the function exits. Thus the returned "
" value is invalid. " ) ;
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 " ,
" Assignment of function parameter has no effect outside the function. " ) ;
}
2013-02-01 19:16:17 +01:00
void CheckAutoVariables : : errorUselessAssignmentPtrArg ( const Token * tok )
{
reportError ( tok ,
Severity : : warning ,
" uselessAssignmentPtrArg " ,
2014-08-04 11:45:24 +02:00
" Assignment of function parameter has no effect outside the function. Did you forget dereferencing it? " ) ;
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?
2013-01-28 06:47:48 +01:00
bool CheckAutoVariables : : returnTemporary ( const Token * tok ) const
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
return bool ( ! 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 ( ) ) {
if ( ( tok - > str ( ) = = " << " | | tok - > str ( ) = = " >> " ) & & tok - > astOperand1 ( ) ) {
const Token * tok2 = tok - > astOperand1 ( ) ;
while ( tok2 & & tok2 - > str ( ) = = " * " & & ! tok2 - > astOperand2 ( ) )
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 ( )
{
2014-09-01 17:01:05 +02:00
if ( _tokenizer - > isC ( ) )
return ;
2011-02-08 01:26:34 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2012-10-12 06:15:46 +02:00
const std : : size_t functions = symbolDatabase - > functionScopes . size ( ) ;
for ( std : : size_t i = 0 ; i < functions ; + + i ) {
const Scope * scope = symbolDatabase - > functionScopes [ i ] ;
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 ( ) = = " & " ) {
2012-10-12 06:15:46 +02:00
for ( const Token * tok2 = scope - > classStart - > next ( ) ; tok2 & & tok2 ! = scope - > classEnd ; tok2 = tok2 - > next ( ) ) {
2015-08-26 13:31:51 +02:00
if ( ! tok2 - > scope ( ) - > isExecutable ( ) ) {
tok2 = tok2 - > scope ( ) - > classEnd ;
continue ;
}
2015-08-14 13:03:07 +02:00
// Skip over lambdas
if ( tok2 - > str ( ) = = " [ " & & tok2 - > link ( ) - > strAt ( 1 ) = = " ( " & & tok2 - > link ( ) - > linkAt ( 1 ) - > strAt ( 1 ) = = " { " )
tok2 = tok2 - > link ( ) - > linkAt ( 1 ) - > linkAt ( 1 ) ;
2014-05-22 11:39:11 +02:00
if ( tok2 - > str ( ) ! = " return " )
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 )
{
2012-07-07 20:31:18 +02:00
reportError ( tok , Severity : : error , " returnReference " , " Reference to auto variable returned. " ) ;
2010-01-23 20:39:12 +01:00
}
2010-01-27 19:16:32 +01:00
void CheckAutoVariables : : errorReturnTempReference ( const Token * tok )
{
2012-07-07 20:31:18 +02:00
reportError ( tok , Severity : : error , " returnTempReference " , " Reference to temporary returned. " ) ;
2010-01-27 19:16:32 +01:00
}
2011-07-21 14:50:38 +02:00
void CheckAutoVariables : : errorInvalidDeallocation ( const Token * tok )
{
2011-12-30 10:32:55 +01:00
reportError ( tok ,
Severity : : error ,
" autovarInvalidDeallocation " ,
2012-07-07 20:31:18 +02:00
" Deallocation of an auto-variable results in undefined behaviour. \n "
2012-07-08 11:38:58 +02:00
" The deallocation of an auto-variable results in undefined behaviour. You should only free memory "
2011-12-30 10:32:55 +01:00
" that has been allocated dynamically. " ) ;
2011-07-21 14:50:38 +02:00
}