2010-10-31 11:51:25 +01:00
/*
* Cppcheck - A tool for static C / C + + code analysis
2012-01-01 00:05:37 +01:00
* Copyright ( C ) 2007 - 2012 Daniel Marjamäki and Cppcheck team .
2010-10-31 11:51:25 +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
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
//---------------------------------------------------------------------------
# include "checknullpointer.h"
# include "executionpath.h"
# include "mathlib.h"
2011-03-06 21:23:33 +01:00
# include "symboldatabase.h"
2011-10-12 22:11:27 +02:00
# include <cctype>
2010-10-31 11:51:25 +01:00
//---------------------------------------------------------------------------
// Register this check class (by creating a static instance of it)
2011-10-13 20:53:06 +02:00
namespace {
CheckNullPointer instance ;
2010-10-31 11:51:25 +01:00
}
//---------------------------------------------------------------------------
2011-01-17 19:23:00 +01:00
/** Is string uppercase? */
bool CheckNullPointer : : isUpper ( const std : : string & str )
{
2011-10-13 20:53:06 +02:00
for ( unsigned int i = 0 ; i < str . length ( ) ; + + i ) {
2012-01-21 19:55:32 +01:00
if ( std : : islower ( str [ i ] ) )
2011-01-17 19:23:00 +01:00
return false ;
}
return true ;
}
2010-10-31 11:51:25 +01:00
/**
* @ brief parse a function call and extract information about variable usage
* @ param tok first token
* @ param var variables that the function read / write .
* @ param value 0 = > invalid with null pointers as parameter .
* 1 - . . = > invalid with uninitialized data .
*/
void CheckNullPointer : : parseFunctionCall ( const Token & tok , std : : list < const Token * > & var , unsigned char value )
{
// standard functions that dereference first parameter..
2011-11-28 21:32:07 +01:00
static std : : set < std : : string > functionNames1_all ;
static std : : set < std : : string > functionNames1_nullptr ;
2012-05-16 09:56:39 +02:00
static std : : set < std : : string > functionNames1_uninit ;
2011-11-28 21:32:07 +01:00
if ( functionNames1_all . empty ( ) ) {
2012-04-26 17:53:21 +02:00
// cstdlib
functionNames1_all . insert ( " atoi " ) ;
functionNames1_all . insert ( " atof " ) ;
functionNames1_all . insert ( " atol " ) ;
functionNames1_all . insert ( " qsort " ) ;
functionNames1_all . insert ( " strtod " ) ;
functionNames1_all . insert ( " strtol " ) ;
functionNames1_all . insert ( " strtoul " ) ;
// cstring
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " memchr " ) ;
functionNames1_all . insert ( " memcmp " ) ;
functionNames1_all . insert ( " strcat " ) ;
functionNames1_all . insert ( " strncat " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " strcoll " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " strchr " ) ;
functionNames1_all . insert ( " strrchr " ) ;
functionNames1_all . insert ( " strcmp " ) ;
functionNames1_all . insert ( " strncmp " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " strcspn " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " strdup " ) ;
functionNames1_all . insert ( " strndup " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " strpbrk " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " strlen " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " strspn " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " strstr " ) ;
2012-04-26 17:53:21 +02:00
// cstdio
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " fclose " ) ;
functionNames1_all . insert ( " feof " ) ;
functionNames1_all . insert ( " fwrite " ) ;
functionNames1_all . insert ( " fseek " ) ;
functionNames1_all . insert ( " ftell " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " fputs " ) ;
functionNames1_all . insert ( " ferror " ) ;
functionNames1_all . insert ( " fgetc " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " fgetpos " ) ;
functionNames1_all . insert ( " fsetpos " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " freopen " ) ;
functionNames1_all . insert ( " fscanf " ) ;
functionNames1_all . insert ( " fprintf " ) ;
functionNames1_all . insert ( " fopen " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_all . insert ( " rewind " ) ;
functionNames1_all . insert ( " printf " ) ;
functionNames1_all . insert ( " scanf " ) ;
functionNames1_all . insert ( " fscanf " ) ;
functionNames1_all . insert ( " sscanf " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_all . insert ( " setbuf " ) ;
functionNames1_all . insert ( " setvbuf " ) ;
functionNames1_all . insert ( " rename " ) ;
functionNames1_all . insert ( " remove " ) ;
functionNames1_all . insert ( " puts " ) ;
functionNames1_all . insert ( " getc " ) ;
functionNames1_all . insert ( " clearerr " ) ;
// ctime
functionNames1_all . insert ( " asctime " ) ;
functionNames1_all . insert ( " ctime " ) ;
functionNames1_all . insert ( " mktime " ) ;
functionNames1_nullptr . insert ( " itoa " ) ;
functionNames1_nullptr . insert ( " mbstowcs " ) ;
functionNames1_nullptr . insert ( " wcstombs " ) ;
2011-11-28 21:32:07 +01:00
functionNames1_nullptr . insert ( " memcpy " ) ;
functionNames1_nullptr . insert ( " memmove " ) ;
functionNames1_nullptr . insert ( " memset " ) ;
functionNames1_nullptr . insert ( " strcpy " ) ;
functionNames1_nullptr . insert ( " sprintf " ) ;
functionNames1_nullptr . insert ( " vsprintf " ) ;
functionNames1_nullptr . insert ( " vprintf " ) ;
functionNames1_nullptr . insert ( " fprintf " ) ;
functionNames1_nullptr . insert ( " vfprintf " ) ;
2012-04-26 17:53:21 +02:00
functionNames1_nullptr . insert ( " tmpnam " ) ;
functionNames1_nullptr . insert ( " fread " ) ;
functionNames1_nullptr . insert ( " gets " ) ;
functionNames1_nullptr . insert ( " gmtime " ) ;
functionNames1_nullptr . insert ( " localtime " ) ;
2012-04-27 10:17:07 +02:00
functionNames1_nullptr . insert ( " strftime " ) ;
2012-05-16 09:56:39 +02:00
functionNames1_uninit . insert ( " perror " ) ;
functionNames1_uninit . insert ( " fflush " ) ;
2010-10-31 11:51:25 +01:00
}
// standard functions that dereference second parameter..
2011-11-28 21:32:07 +01:00
static std : : set < std : : string > functionNames2_all ;
static std : : set < std : : string > functionNames2_nullptr ;
if ( functionNames2_all . empty ( ) ) {
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " mbstowcs " ) ;
functionNames2_all . insert ( " wcstombs " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_all . insert ( " memcmp " ) ;
functionNames2_all . insert ( " memcpy " ) ;
functionNames2_all . insert ( " memmove " ) ;
functionNames2_all . insert ( " strcat " ) ;
functionNames2_all . insert ( " strncat " ) ;
functionNames2_all . insert ( " strcmp " ) ;
functionNames2_all . insert ( " strncmp " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " strcoll " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_all . insert ( " strcpy " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " strcspn " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_all . insert ( " strncpy " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " strpbrk " ) ;
functionNames2_all . insert ( " strspn " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_all . insert ( " strstr " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " strxfrm " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_all . insert ( " sprintf " ) ;
functionNames2_all . insert ( " fprintf " ) ;
functionNames2_all . insert ( " fscanf " ) ;
functionNames2_all . insert ( " sscanf " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_all . insert ( " fputs " ) ;
functionNames2_all . insert ( " fputc " ) ;
functionNames2_all . insert ( " ungetc " ) ;
functionNames2_all . insert ( " rename " ) ;
functionNames2_all . insert ( " putc " ) ;
functionNames2_all . insert ( " freopen " ) ;
2011-11-28 21:32:07 +01:00
functionNames2_nullptr . insert ( " frexp " ) ;
functionNames2_nullptr . insert ( " modf " ) ;
2012-04-26 17:53:21 +02:00
functionNames2_nullptr . insert ( " fgetpos " ) ;
2010-10-31 11:51:25 +01:00
}
2012-02-11 12:26:48 +01:00
if ( Token : : Match ( & tok , " %var% ( ) " ) | | ! tok . tokAt ( 2 ) )
return ;
const Token * firstParam = tok . tokAt ( 2 ) ;
const Token * secondParam = firstParam - > nextArgument ( ) ;
2010-10-31 11:51:25 +01:00
// 1st parameter..
2012-02-11 12:26:48 +01:00
if ( ( Token : : Match ( firstParam , " %var% ,|) " ) & & firstParam - > varId ( ) > 0 ) | |
( value = = 0 & & Token : : Match ( firstParam , " 0 ,|) " ) ) ) {
2011-11-28 21:32:07 +01:00
if ( functionNames1_all . find ( tok . str ( ) ) ! = functionNames1_all . end ( ) )
2012-02-11 12:26:48 +01:00
var . push_back ( firstParam ) ;
2011-11-28 21:32:07 +01:00
else if ( value = = 0 & & functionNames1_nullptr . find ( tok . str ( ) ) ! = functionNames1_nullptr . end ( ) )
2012-02-11 12:26:48 +01:00
var . push_back ( firstParam ) ;
2012-05-16 09:56:39 +02:00
else if ( value ! = 0 & & functionNames1_uninit . find ( tok . str ( ) ) ! = functionNames1_uninit . end ( ) )
2012-02-11 12:26:48 +01:00
var . push_back ( firstParam ) ;
else if ( value = = 0 & & Token : : Match ( & tok , " snprintf|vsnprintf|fnprintf|vfnprintf " ) & & secondParam & & secondParam - > str ( ) ! = " 0 " ) // Only if length (second parameter) is not zero
var . push_back ( firstParam ) ;
2010-10-31 11:51:25 +01:00
}
// 2nd parameter..
2012-02-11 12:26:48 +01:00
if ( secondParam & & ( ( value = = 0 & & secondParam - > str ( ) = = " 0 " ) | | ( Token : : Match ( secondParam , " %var% " ) & & secondParam - > varId ( ) > 0 ) ) ) {
if ( functionNames2_all . find ( tok . str ( ) ) ! = functionNames2_all . end ( ) )
var . push_back ( secondParam ) ;
else if ( value = = 0 & & functionNames2_nullptr . find ( tok . str ( ) ) ! = functionNames2_nullptr . end ( ) )
var . push_back ( secondParam ) ;
2010-10-31 11:51:25 +01:00
}
2011-09-05 20:18:58 +02:00
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " printf|sprintf|snprintf|fprintf|fnprintf|scanf|sscanf|fscanf " ) ) {
2011-10-12 22:11:27 +02:00
const Token * argListTok = 0 ; // Points to first va_list argument
std : : string formatString ;
bool scan = Token : : Match ( & tok , " scanf|sscanf|fscanf " ) ;
2011-10-23 11:23:48 +02:00
if ( Token : : Match ( & tok , " printf|scanf ( %str% " ) ) {
2012-02-11 12:26:48 +01:00
formatString = firstParam - > strValue ( ) ;
argListTok = secondParam ;
} else if ( Token : : Match ( & tok , " sprintf|fprintf|sscanf|fscanf " ) ) {
const Token * formatStringTok = secondParam ; // Find second parameter (format string)
2012-04-25 09:56:07 +02:00
if ( formatStringTok & & formatStringTok - > type ( ) = = Token : : eString ) {
2011-10-23 11:23:48 +02:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find third parameter (first argument of va_args)
2012-02-11 12:26:48 +01:00
formatString = formatStringTok - > strValue ( ) ;
2011-10-23 11:23:48 +02:00
}
2012-05-11 19:38:19 +02:00
} else if ( Token : : Match ( & tok , " snprintf|fnprintf " ) & & secondParam ) {
const Token * formatStringTok = secondParam - > nextArgument ( ) ; // Find third parameter (format string)
2012-04-25 09:56:07 +02:00
if ( formatStringTok & & formatStringTok - > type ( ) = = Token : : eString ) {
2011-10-23 11:23:48 +02:00
argListTok = formatStringTok - > nextArgument ( ) ; // Find fourth parameter (first argument of va_args)
2012-02-11 12:26:48 +01:00
formatString = formatStringTok - > strValue ( ) ;
2011-10-23 11:23:48 +02:00
}
2011-10-12 22:11:27 +02:00
}
2011-10-23 11:23:48 +02:00
2011-10-13 20:53:06 +02:00
if ( argListTok ) {
2011-10-12 22:11:27 +02:00
bool percent = false ;
2011-10-13 20:53:06 +02:00
for ( std : : string : : iterator i = formatString . begin ( ) ; i ! = formatString . end ( ) ; + + i ) {
if ( * i = = ' % ' ) {
2011-10-12 22:11:27 +02:00
percent = ! percent ;
2011-11-28 21:32:07 +01:00
} else if ( percent ) {
2011-12-02 17:09:32 +01:00
percent = false ;
bool _continue = false ;
2011-11-28 21:32:07 +01:00
while ( ! std : : isalpha ( * i ) ) {
2011-12-02 17:09:32 +01:00
if ( * i = = ' * ' ) {
if ( scan )
_continue = true ;
else
argListTok = argListTok - > nextArgument ( ) ;
}
2011-11-28 21:32:07 +01:00
+ + i ;
2011-11-30 20:23:29 +01:00
if ( ! argListTok | | i = = formatString . end ( ) )
return ;
2011-11-28 21:32:07 +01:00
}
2011-12-02 17:09:32 +01:00
if ( _continue )
continue ;
2011-11-28 21:32:07 +01:00
2011-10-16 07:06:18 +02:00
if ( ( * i = = ' n ' | | * i = = ' s ' | | scan ) & & ( ! scan | | value = = 0 ) ) {
2012-02-11 12:26:48 +01:00
if ( ( value = = 0 & & argListTok - > str ( ) = = " 0 " ) | | ( argListTok - > varId ( ) > 0 ) ) {
2011-10-12 22:11:27 +02:00
var . push_back ( argListTok ) ;
}
}
2011-11-28 21:32:07 +01:00
if ( * i ! = ' m ' ) // %m is a non-standard glibc extension that requires no parameter
argListTok = argListTok - > nextArgument ( ) ; // Find next argument
2011-10-16 07:50:34 +02:00
if ( ! argListTok )
2011-10-16 07:06:18 +02:00
break ;
2011-10-12 22:11:27 +02:00
}
}
}
2011-09-05 20:18:58 +02:00
}
2010-10-31 11:51:25 +01:00
}
2010-10-31 15:32:19 +01:00
/**
* Is there a pointer dereference ? Everything that should result in
* a nullpointer dereference error message will result in a true
* return value . If it ' s unknown if the pointer is dereferenced false
* is returned .
* @ param tok token for the pointer
* @ param unknown it is not known if there is a pointer dereference ( could be reported as a debug message )
* @ return true = > there is a dereference
*/
2012-01-25 15:16:22 +01:00
bool CheckNullPointer : : isPointerDeRef ( const Token * tok , bool & unknown , const SymbolDatabase * symbolDatabase )
2010-10-31 15:32:19 +01:00
{
2011-12-12 07:35:53 +01:00
const bool inconclusive = unknown ;
2010-10-31 15:32:19 +01:00
unknown = false ;
// Dereferencing pointer..
2012-01-25 15:16:22 +01:00
if ( tok - > strAt ( - 1 ) = = " * " & & ( Token : : Match ( tok - > tokAt ( - 2 ) , " return|throw|;|{|}|:|[|(|, " ) | | tok - > tokAt ( - 2 ) - > isOp ( ) | | tok - > tokAt ( - 2 ) - > isAssignmentOp ( ) ) & & ! Token : : Match ( tok - > tokAt ( - 3 ) , " sizeof|decltype " ) )
2010-10-31 15:32:19 +01:00
return true ;
2011-10-18 19:34:14 +02:00
// read/write member variable
if ( ! Token : : simpleMatch ( tok - > tokAt ( - 2 ) , " & ( " ) & & ! Token : : Match ( tok - > tokAt ( - 2 ) , " sizeof|decltype ( " ) & & tok - > strAt ( - 1 ) ! = " & " & & tok - > strAt ( - 1 ) ! = " && " & & Token : : Match ( tok - > next ( ) , " . %var% " ) ) {
if ( tok - > strAt ( 3 ) ! = " ( " )
return true ;
unknown = true ;
return false ;
}
2010-10-31 15:32:19 +01:00
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok , " %var% [ " ) & & ( tok - > previous ( ) - > str ( ) ! = " & " | | Token : : Match ( tok - > next ( ) - > link ( ) - > next ( ) , " [.(] " ) ) )
2010-10-31 15:32:19 +01:00
return true ;
if ( Token : : Match ( tok , " %var% ( " ) )
return true ;
2010-10-31 15:46:08 +01:00
if ( Token : : Match ( tok , " %var% = %var% . " ) & &
tok - > varId ( ) > 0 & &
tok - > varId ( ) = = tok - > tokAt ( 2 ) - > varId ( ) )
return true ;
2012-01-25 15:16:22 +01:00
// std::string dereferences nullpointers
if ( Token : : Match ( tok - > tokAt ( - 4 ) , " std :: string ( %var% ) " ) )
return true ;
2012-01-26 16:50:59 +01:00
if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %var% ( %var% ) " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( - 2 ) - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & Token : : Match ( var - > typeStartToken ( ) , " std :: string !!:: " ) )
2012-01-26 16:50:59 +01:00
return true ;
}
2012-01-25 15:16:22 +01:00
2012-03-16 17:24:03 +01:00
// streams dereference nullpointers
if ( Token : : Match ( tok - > previous ( ) , " <<|>> %var% " ) ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & var - > isPointer ( ) & & var - > typeStartToken ( ) - > str ( ) = = " char " ) { // Only outputing or reading to char* can cause problems
2012-03-16 17:24:03 +01:00
const Token * tok2 = tok - > previous ( ) ; // Find start of statement
for ( ; tok2 ; tok2 = tok2 - > previous ( ) ) {
if ( Token : : Match ( tok2 - > previous ( ) , " ;|{|}|: " ) )
break ;
}
if ( Token : : Match ( tok2 , " std :: cout|cin|cerr " ) )
return true ;
if ( tok2 & & tok2 - > varId ( ) ! = 0 ) {
const Variable * var2 = symbolDatabase - > getVariableFromVarId ( tok2 - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var2 & & Token : : Match ( var2 - > typeStartToken ( ) , " std :: istream|ifstream|istringstream|ostream|ofstream|ostringstream|stringstream|fstream|iostream " ) )
2012-03-16 17:24:03 +01:00
return true ;
}
}
}
2012-01-25 15:16:22 +01:00
unsigned int ovarid = 0 ;
if ( Token : : Match ( tok , " %var% ==|!= %var% " ) )
ovarid = tok - > tokAt ( 2 ) - > varId ( ) ;
2012-04-02 12:12:02 +02:00
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %var% ==|!= %var% " ) )
ovarid = tok - > tokAt ( - 2 ) - > varId ( ) ;
else if ( Token : : Match ( tok - > tokAt ( - 2 ) , " %var% =|+=|+ %var% )|]|,| ; | + " ))
2012-01-25 15:16:22 +01:00
ovarid = tok - > tokAt ( - 2 ) - > varId ( ) ;
if ( ovarid ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( ovarid ) ;
2012-06-08 18:05:02 +02:00
if ( var & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & Token : : Match ( var - > typeStartToken ( ) , " std :: string !!:: " ) )
2012-01-25 15:16:22 +01:00
return true ;
}
2011-12-12 07:35:53 +01:00
// Check if it's NOT a pointer dereference.
// This is most useful in inconclusive checking
if ( inconclusive ) {
// Not a dereference..
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( tok , " %var% = " ) )
2011-12-12 07:35:53 +01:00
return false ;
2010-10-31 15:32:19 +01:00
2011-12-12 07:35:53 +01:00
// OK to delete a null
if ( Token : : Match ( tok - > previous ( ) , " delete %var% " ) | | Token : : Match ( tok - > tokAt ( - 3 ) , " delete [ ] %var% " ) )
return false ;
2011-11-13 22:35:13 +01:00
2011-12-12 07:35:53 +01:00
// OK to check if pointer is null
// OK to take address of pointer
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( tok - > previous ( ) , " !|& %var% " ) )
2011-12-12 07:35:53 +01:00
return false ;
2011-12-11 08:48:55 +01:00
2011-12-12 07:35:53 +01:00
// OK to pass pointer to function
2011-12-15 17:01:39 +01:00
if ( Token : : Match ( tok - > previous ( ) , " [(,] %var% [,)] " ) )
return false ;
// Compare pointer
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( tok - > previous ( ) , " (|&&|%oror%|==|!= %var% " ) )
return false ;
if ( Token : : Match ( tok , " %var% &&|%oror%|==|!=|) " ) )
2011-12-15 17:01:39 +01:00
return false ;
// Taking address
if ( Token : : Match ( tok - > previous ( ) , " return|= %var% ; " ) )
2011-12-12 07:35:53 +01:00
return false ;
2011-12-11 08:48:55 +01:00
2012-04-30 12:36:41 +02:00
// (void)var
if ( Token : : Match ( tok - > previous ( ) , " [{;}] %var% ; " ) )
return false ;
2011-12-12 07:35:53 +01:00
// unknown if it's a dereference
2012-01-21 19:55:32 +01:00
unknown = true ;
2011-12-12 07:35:53 +01:00
}
2010-10-31 15:32:19 +01:00
// assume that it's not a dereference (no false positives)
return false ;
}
2011-12-25 17:01:45 +01:00
// check if function can assign pointer
bool CheckNullPointer : : CanFunctionAssignPointer ( const Token * functiontoken , unsigned int varid ) const
{
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( functiontoken , " if|while|for|switch|sizeof|catch " ) )
2011-12-25 17:01:45 +01:00
return false ;
int argumentNumber = 0 ;
for ( const Token * arg = functiontoken - > tokAt ( 2 ) ; arg ; arg = arg - > nextArgument ( ) ) {
+ + argumentNumber ;
if ( Token : : Match ( arg , " %varid% [,)] " , varid ) ) {
const Token * ftok = _tokenizer - > getFunctionTokenByName ( functiontoken - > str ( ) . c_str ( ) ) ;
if ( ! Token : : Match ( ftok , " %type% ( " ) ) {
// assume that the function might assign the pointer
return true ;
}
ftok = ftok - > tokAt ( 2 ) ;
while ( ftok & & argumentNumber > 1 ) {
ftok = ftok - > nextArgument ( ) ;
- - argumentNumber ;
}
// check if it's a pointer parameter..
while ( ftok & & ftok - > isName ( ) )
ftok = ftok - > next ( ) ;
if ( Token : : Match ( ftok , " * *| const| %var% [,)] " ) )
// parameter is passed by value
return false ;
}
}
// pointer is not passed
return false ;
}
2010-10-31 11:51:25 +01:00
void CheckNullPointer : : nullPointerAfterLoop ( )
{
2011-12-09 22:28:10 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-10-31 11:51:25 +01:00
// Locate insufficient null-pointer handling after loop
2011-12-09 22:28:10 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
2010-12-31 14:17:10 +01:00
// only interested in while ( %var% )
// TODO: Aren't there false negatives. Shouldn't other loops be handled such as:
// - while ( ! %var% )
2011-12-09 22:28:10 +01:00
const Token * const tok = i - > classDef ;
if ( i - > type ! = Scope : : eWhile | | ! Token : : Match ( tok , " while ( %var% )|&& " ) )
2010-10-31 11:51:25 +01:00
continue ;
2010-12-31 14:17:10 +01:00
// Get variable id for the loop variable
2011-12-17 19:04:03 +01:00
const Variable * var ( symbolDatabase - > getVariableFromVarId ( tok - > tokAt ( 2 ) - > varId ( ) ) ) ;
2010-10-31 11:51:25 +01:00
2011-03-28 18:44:25 +02:00
// Is variable a pointer?
2011-12-17 19:04:03 +01:00
if ( ! var | | ! var - > isPointer ( ) )
2011-03-28 18:44:25 +02:00
continue ;
2010-12-31 14:17:10 +01:00
// Get variable name for the loop variable
2012-05-25 12:09:41 +02:00
const std : : string & varname ( tok - > strAt ( 2 ) ) ;
2010-10-31 11:51:25 +01:00
2010-12-31 14:17:10 +01:00
// Locate the end of the while loop body..
2011-07-25 15:45:00 +02:00
const Token * tok2 = tok - > next ( ) - > link ( ) - > next ( ) - > link ( ) ;
2010-10-31 11:51:25 +01:00
2011-10-09 15:09:02 +02:00
// Is this checking inconclusive?
bool inconclusive = false ;
2011-12-01 10:48:14 +01:00
if ( ! tok2 )
continue ;
2010-12-31 14:17:10 +01:00
// Check if the variable is dereferenced after the while loop
2011-12-01 10:48:14 +01:00
while ( NULL ! = ( tok2 = tok2 - > next ( ) ) ) {
2011-10-09 15:09:02 +02:00
// inner and outer scopes
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " { " | | tok2 - > str ( ) = = " } " ) {
2011-10-09 15:09:02 +02:00
// Not inconclusive: bail out
if ( ! _settings - > inconclusive )
break ;
inconclusive = true ;
2011-10-13 20:53:06 +02:00
if ( tok2 - > str ( ) = = " } " ) {
2011-10-09 15:09:02 +02:00
// "}" => leaving function? then break.
const Token * tok3 = tok2 - > link ( ) - > previous ( ) ;
if ( ! tok3 | | ! Token : : Match ( tok3 , " [);] " ) )
break ;
if ( tok3 - > str ( ) = = " ) " & & ! Token : : Match ( tok3 - > link ( ) - > previous ( ) , " if|for|while " ) )
break ;
}
}
// Stop checking if "break" is found
else if ( tok2 - > str ( ) = = " break " )
2010-10-31 11:51:25 +01:00
break ;
2010-12-31 14:17:10 +01:00
// loop variable is found..
2011-12-17 19:04:03 +01:00
else if ( tok2 - > varId ( ) = = var - > varId ( ) ) {
2010-12-31 14:17:10 +01:00
// dummy variable.. is it unknown if pointer is dereferenced or not?
2011-12-12 07:35:53 +01:00
bool unknown = _settings - > inconclusive ;
2010-12-31 14:17:10 +01:00
// Is the loop variable dereferenced?
2012-01-25 15:16:22 +01:00
if ( CheckNullPointer : : isPointerDeRef ( tok2 , unknown , symbolDatabase ) ) {
2011-10-09 15:09:02 +02:00
nullPointerError ( tok2 , varname , tok - > linenr ( ) , inconclusive ) ;
2010-10-31 11:51:25 +01:00
}
2011-10-18 19:34:14 +02:00
else if ( unknown & & _settings - > inconclusive ) {
nullPointerError ( tok2 , varname , tok - > linenr ( ) , true ) ;
}
2010-10-31 11:51:25 +01:00
break ;
}
}
}
}
void CheckNullPointer : : nullPointerLinkedList ( )
{
2011-12-09 22:28:10 +01:00
const SymbolDatabase * const symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-12-31 14:37:34 +01:00
// looping through items in a linked list in a inner loop.
// Here is an example:
// for (const Token *tok = tokens; tok; tok = tok->next) {
// if (tok->str() == "hello")
// tok = tok->next; // <- tok might become a null pointer!
// }
2011-12-09 22:28:10 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
const Token * const tok1 = i - > classDef ;
// search for a "for" scope..
if ( i - > type ! = Scope : : eFor | | ! tok1 )
2010-10-31 11:51:25 +01:00
continue ;
2010-12-31 14:37:34 +01:00
// is there any dereferencing occurring in the for statement
2011-11-27 07:30:58 +01:00
const Token * end2 = tok1 - > linkAt ( 1 ) ;
2011-11-26 21:02:04 +01:00
for ( const Token * tok2 = tok1 - > tokAt ( 2 ) ; tok2 ! = end2 ; tok2 = tok2 - > next ( ) ) {
2010-12-15 18:45:53 +01:00
// Dereferencing a variable inside the "for" parentheses..
2011-11-26 21:02:04 +01:00
if ( Token : : Match ( tok2 , " %var% . %var% " ) ) {
2010-12-31 14:37:34 +01:00
// Variable id for dereferenced variable
2010-10-31 11:51:25 +01:00
const unsigned int varid ( tok2 - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
2012-01-25 15:16:22 +01:00
// Is this variable a pointer?
const Variable * var = symbolDatabase - > getVariableFromVarId ( varid ) ;
if ( ! var | | ! var - > isPointer ( ) )
2010-10-31 11:51:25 +01:00
continue ;
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " %varid% ? " , varid ) )
continue ;
2010-10-31 11:51:25 +01:00
// Check usage of dereferenced variable in the loop..
2012-01-25 15:16:22 +01:00
for ( std : : list < Scope * > : : const_iterator j = i - > nestedList . begin ( ) ; j ! = i - > nestedList . end ( ) ; + + j ) {
Scope * scope = * j ;
if ( scope - > type ! = Scope : : eWhile )
continue ;
2010-12-31 14:37:34 +01:00
// TODO: are there false negatives for "while ( %varid% ||"
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( scope - > classDef - > next ( ) , " ( %varid% &&|) " , varid ) ) {
2010-12-31 14:37:34 +01:00
// Make sure there is a "break" or "return" inside the loop.
// Without the "break" a null pointer could be dereferenced in the
// for statement.
// indentlevel4 is a counter for { and }. When scanning the code with tok4
2012-01-15 12:31:49 +01:00
unsigned int indentlevel4 = 1 ;
2012-01-25 15:16:22 +01:00
for ( const Token * tok4 = scope - > classStart ; tok4 ; tok4 = tok4 - > next ( ) ) {
2010-10-31 11:51:25 +01:00
if ( tok4 - > str ( ) = = " { " )
+ + indentlevel4 ;
2011-10-13 20:53:06 +02:00
else if ( tok4 - > str ( ) = = " } " ) {
if ( indentlevel4 < = 1 ) {
2012-01-25 15:16:22 +01:00
nullPointerError ( tok1 , var - > name ( ) , scope - > classDef - > linenr ( ) ) ;
2010-10-31 11:51:25 +01:00
break ;
}
- - indentlevel4 ;
}
2010-12-31 14:37:34 +01:00
// There is a "break" or "return" inside the loop.
// TODO: there can be false negatives. There could still be
// execution paths that are not properly terminated
2010-10-31 11:51:25 +01:00
else if ( tok4 - > str ( ) = = " break " | | tok4 - > str ( ) = = " return " )
break ;
}
}
}
}
}
}
}
void CheckNullPointer : : nullPointerStructByDeRefAndChec ( )
{
2010-12-31 15:56:41 +01:00
// Dereferencing a struct pointer and then checking if it's NULL..
2010-12-31 15:57:08 +01:00
2010-12-31 15:56:41 +01:00
// skipvar: don't check vars that has been tested against null already
2010-10-31 11:51:25 +01:00
std : : set < unsigned int > skipvar ;
skipvar . insert ( 0 ) ;
2010-12-31 15:56:41 +01:00
// Scan through all tokens
2011-10-13 20:53:06 +02:00
for ( const Token * tok1 = _tokenizer - > tokens ( ) ; tok1 ; tok1 = tok1 - > next ( ) ) {
2010-12-31 15:56:41 +01:00
// Checking if some pointer is null.
// then add the pointer to skipvar => is it known that it isn't NULL
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok1 , " if|while ( !| %var% ) " ) ) {
2010-10-31 11:51:25 +01:00
tok1 = tok1 - > tokAt ( 2 ) ;
if ( tok1 - > str ( ) = = " ! " )
tok1 = tok1 - > next ( ) ;
skipvar . insert ( tok1 - > varId ( ) ) ;
continue ;
2012-03-16 17:24:03 +01:00
} else if ( Token : : Match ( tok1 , " ( ! %var% %oror% " ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( tok1 , " ( %var% && " ) ) {
2011-10-08 07:39:20 +02:00
// TODO: there are false negatives caused by this. The
// variable should be removed from skipvar after the
// condition
2011-10-07 21:08:21 +02:00
tok1 = tok1 - > next ( ) ;
if ( tok1 - > str ( ) = = " ! " )
tok1 = tok1 - > next ( ) ;
skipvar . insert ( tok1 - > varId ( ) ) ;
continue ;
}
2010-10-31 11:51:25 +01:00
2011-10-30 17:59:38 +01:00
bool inconclusive = false ;
2011-02-19 21:01:38 +01:00
/**
* @ todo There are lots of false negatives here . A dereference
* is only investigated if a few specific conditions are met .
*/
// dereference in assignment
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok1 , " [;{}] %var% . %var% " ) ) {
2011-02-19 21:01:38 +01:00
tok1 = tok1 - > next ( ) ;
2011-10-30 17:59:38 +01:00
if ( tok1 - > strAt ( 3 ) = = " ( " ) {
if ( ! _settings - > inconclusive )
continue ;
inconclusive = true ;
}
2011-02-19 21:01:38 +01:00
}
2010-10-31 11:51:25 +01:00
// dereference in assignment
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok1 , " [{};] %var% = %var% . %var% " ) ) {
2011-12-08 19:30:14 +01:00
if ( tok1 - > strAt ( 1 ) = = tok1 - > strAt ( 3 ) )
2010-10-31 11:51:25 +01:00
continue ;
tok1 = tok1 - > tokAt ( 3 ) ;
}
2011-07-30 19:51:06 +02:00
// dereference in condition
2011-10-13 20:53:06 +02:00
else if ( Token : : Match ( tok1 , " if ( !| %var% . " ) ) {
2011-07-30 19:51:06 +02:00
tok1 = tok1 - > tokAt ( 2 ) ;
2011-08-01 21:57:23 +02:00
if ( tok1 - > str ( ) = = " ! " )
tok1 = tok1 - > next ( ) ;
2011-07-30 19:51:06 +02:00
}
2011-04-03 21:06:42 +02:00
// dereference in function call (but not sizeof|decltype)
else if ( ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " %var% ( %var% . %var% " ) & & ! Token : : Match ( tok1 - > tokAt ( - 2 ) , " sizeof|decltype ( %var% . %var% " ) ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( tok1 - > previous ( ) , " , %var% . %var% " ) ) {
2010-12-17 21:09:12 +01:00
// Is the function return value taken by the pointer?
bool assignment = false ;
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
2010-12-19 21:27:28 +01:00
if ( varid1 = = 0 )
continue ;
2010-12-17 21:09:12 +01:00
const Token * tok2 = tok1 - > previous ( ) ;
2011-10-13 20:53:06 +02:00
while ( tok2 & & ! Token : : Match ( tok2 , " [;{}] " ) ) {
if ( Token : : Match ( tok2 , " %varid% = " , varid1 ) ) {
2010-12-17 21:09:12 +01:00
assignment = true ;
break ;
}
tok2 = tok2 - > previous ( ) ;
}
if ( assignment )
continue ;
2011-12-02 06:11:55 +01:00
// Is the dereference checked with a previous &&
bool checked = false ;
for ( tok2 = tok1 - > tokAt ( - 2 ) ; tok2 ; tok2 = tok2 - > previous ( ) ) {
if ( Token : : Match ( tok2 , " [,(;{}] " ) )
break ;
else if ( tok2 - > str ( ) = = " ) " )
tok2 = tok2 - > link ( ) ;
else if ( Token : : Match ( tok2 , " %varid% && " , varid1 ) ) {
checked = true ;
break ;
}
}
if ( checked )
continue ;
2010-10-31 11:51:25 +01:00
}
// Goto next token
2011-10-13 20:53:06 +02:00
else {
2010-10-31 11:51:25 +01:00
continue ;
}
// struct dereference was found - investigate if it is later
// checked that it is not NULL
const unsigned int varid1 ( tok1 - > varId ( ) ) ;
if ( skipvar . find ( varid1 ) ! = skipvar . end ( ) )
continue ;
2010-12-31 15:56:41 +01:00
// name of struct pointer
2012-04-25 09:56:07 +02:00
const std : : string & varname ( tok1 - > str ( ) ) ;
2010-10-31 11:51:25 +01:00
2011-03-12 17:42:58 +01:00
// is pointer local?
bool isLocal = false ;
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( tok1 - > varId ( ) ) ;
2011-12-17 19:04:03 +01:00
if ( ! var )
continue ;
if ( var - > isLocal ( ) | | var - > isArgument ( ) )
2011-03-12 17:42:58 +01:00
isLocal = true ;
2011-03-12 20:57:19 +01:00
// member function may or may not nullify the pointer if it's global (#2647)
2011-10-13 20:53:06 +02:00
if ( ! isLocal ) {
2011-03-12 20:57:19 +01:00
const Token * tok2 = tok1 ;
while ( Token : : Match ( tok2 , " %var% . " ) )
tok2 = tok2 - > tokAt ( 2 ) ;
if ( Token : : Match ( tok2 , " %var% ( " ) )
continue ;
}
2010-12-31 15:56:41 +01:00
// count { and } using tok2
2010-10-31 11:51:25 +01:00
unsigned int indentlevel2 = 0 ;
2011-10-13 20:53:06 +02:00
for ( const Token * tok2 = tok1 - > tokAt ( 3 ) ; tok2 ; tok2 = tok2 - > next ( ) ) {
2010-10-31 11:51:25 +01:00
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel2 ;
2011-10-13 20:53:06 +02:00
else if ( tok2 - > str ( ) = = " } " ) {
2011-07-30 19:51:06 +02:00
if ( indentlevel2 = = 0 )
2010-10-31 11:51:25 +01:00
break ;
- - indentlevel2 ;
}
2011-03-29 18:45:32 +02:00
// label / ?:
else if ( tok2 - > str ( ) = = " : " )
2010-10-31 11:51:25 +01:00
break ;
2011-12-25 17:01:45 +01:00
// function call..
2011-12-26 07:13:10 +01:00
else if ( Token : : Match ( tok2 , " [;{}] %var% ( " ) & & CanFunctionAssignPointer ( tok2 - > next ( ) , varid1 ) ) {
if ( ! _settings - > inconclusive )
break ;
inconclusive = true ;
}
2011-12-25 17:01:45 +01:00
2010-10-31 11:51:25 +01:00
// Reassignment of the struct
2011-10-13 20:53:06 +02:00
else if ( tok2 - > varId ( ) = = varid1 ) {
if ( tok2 - > next ( ) - > str ( ) = = " = " ) {
2011-07-30 19:51:06 +02:00
// Avoid false positives when there is 'else if'
// TODO: can this be handled better?
if ( tok1 - > strAt ( - 2 ) = = " if " )
skipvar . insert ( varid1 ) ;
2010-10-31 11:51:25 +01:00
break ;
2011-07-30 19:51:06 +02:00
}
2010-10-31 11:51:25 +01:00
if ( Token : : Match ( tok2 - > tokAt ( - 2 ) , " [,(] & " ) )
break ;
}
// Loop..
/** @todo don't bail out if the variable is not used in the loop */
else if ( tok2 - > str ( ) = = " do " )
break ;
2011-03-28 17:28:21 +02:00
// return/break at base level => stop checking
else if ( indentlevel2 = = 0 & & ( tok2 - > str ( ) = = " return " | | tok2 - > str ( ) = = " break " ) )
2010-10-31 11:51:25 +01:00
break ;
2011-03-12 17:42:58 +01:00
// Function call: If the pointer is not a local variable it
2011-03-12 15:02:06 +01:00
// might be changed by the call.
else if ( Token : : Match ( tok2 , " [;{}] %var% ( " ) & &
2011-11-20 14:22:39 +01:00
Token : : simpleMatch ( tok2 - > linkAt ( 2 ) , " ) ; " ) & & ! isLocal ) {
2011-03-12 15:02:06 +01:00
break ;
}
2010-12-31 15:56:41 +01:00
// Check if pointer is null.
2011-02-19 21:10:31 +01:00
// TODO: false negatives for "if (!p || .."
2011-12-18 13:33:23 +01:00
else if ( ! tok2 - > isExpandedMacro ( ) & & Token : : Match ( tok2 , " if ( !| %varid% )|&& " , varid1 ) ) {
2010-10-31 11:51:25 +01:00
// Is this variable a pointer?
2011-12-17 19:04:03 +01:00
if ( var - > isPointer ( ) )
2011-10-30 17:59:38 +01:00
nullPointerError ( tok1 , varname , tok2 - > linenr ( ) , inconclusive ) ;
2010-10-31 11:51:25 +01:00
break ;
}
}
}
}
void CheckNullPointer : : nullPointerByDeRefAndChec ( )
{
2011-08-14 16:53:09 +02:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-10-31 11:51:25 +01:00
// Dereferencing a pointer and then checking if it's NULL..
2011-01-06 13:18:49 +01:00
// This check will first scan for the check. And then scan backwards
// from the check, searching for dereferencing.
2011-12-09 22:28:10 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
2011-01-06 13:18:49 +01:00
// TODO: false negatives.
// - logical operators
// - while
2011-12-09 22:28:10 +01:00
const Token * const tok = i - > classDef ;
2012-01-26 16:50:59 +01:00
if ( i - > type = = Scope : : eIf & & tok & & ! tok - > isExpandedMacro ( ) & & Token : : Match ( tok , " if ( !| %var% )|%oror%|&& " ) ) {
2011-08-02 11:20:09 +02:00
const Token * vartok = tok - > tokAt ( 2 ) ;
if ( vartok - > str ( ) = = " ! " )
vartok = vartok - > next ( ) ;
2011-01-06 13:18:49 +01:00
// Variable id for pointer
2011-08-02 11:20:09 +02:00
const unsigned int varid ( vartok - > varId ( ) ) ;
2010-10-31 11:51:25 +01:00
if ( varid = = 0 )
continue ;
2011-01-06 13:18:49 +01:00
// Name of pointer
2012-05-25 12:09:41 +02:00
const std : : string & varname ( vartok - > str ( ) ) ;
2010-10-31 11:51:25 +01:00
2011-12-17 19:04:03 +01:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( varid ) ;
2010-10-31 11:51:25 +01:00
// Check that variable is a pointer..
2011-12-17 19:04:03 +01:00
if ( ! var | | ! var - > isPointer ( ) )
2011-08-14 16:53:09 +02:00
continue ;
const Token * const decltok = var - > nameToken ( ) ;
2011-12-26 07:13:10 +01:00
bool inconclusive = false ;
2010-12-31 18:30:04 +01:00
2011-10-13 20:53:06 +02:00
for ( const Token * tok1 = tok - > previous ( ) ; tok1 & & tok1 ! = decltok ; tok1 = tok1 - > previous ( ) ) {
if ( tok1 - > str ( ) = = " ) " & & Token : : Match ( tok1 - > link ( ) - > previous ( ) , " %var% ( " ) ) {
2011-06-21 18:45:30 +02:00
const Token * tok2 = tok1 - > link ( ) ;
2011-08-02 11:20:09 +02:00
while ( tok2 & & ! Token : : Match ( tok2 , " [;{}?:] " ) )
2011-06-21 18:45:30 +02:00
tok2 = tok2 - > previous ( ) ;
2011-08-02 11:20:09 +02:00
if ( Token : : Match ( tok2 , " [?:] " ) )
break ;
2011-06-21 18:45:30 +02:00
if ( Token : : Match ( tok2 , " [;{}] %varid% = %var% " , varid ) )
break ;
2010-12-17 21:09:12 +01:00
2011-07-31 14:07:35 +02:00
if ( Token : : Match ( tok1 - > link ( ) - > previous ( ) , " while ( %varid% " , varid ) )
break ;
2011-01-10 19:57:26 +01:00
2012-03-16 17:24:03 +01:00
if ( Token : : Match ( tok1 - > link ( ) , " ( ! %varid% %oror% " , varid ) | |
2011-10-13 20:53:06 +02:00
Token : : Match ( tok1 - > link ( ) , " ( %varid% && " , varid ) ) {
2011-10-08 12:58:10 +02:00
tok1 = tok1 - > link ( ) ;
continue ;
}
2011-10-07 21:08:21 +02:00
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( tok1 - > link ( ) - > previous ( ) , " sizeof ( " ) ) {
2011-07-31 14:07:35 +02:00
tok1 = tok1 - > link ( ) - > previous ( ) ;
continue ;
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( tok2 , " [;{}] %var% ( %varid% , " , varid ) ) {
2011-08-14 16:53:09 +02:00
std : : list < const Token * > varlist ;
parseFunctionCall ( * ( tok2 - > next ( ) ) , varlist , 0 ) ;
2011-10-13 20:53:06 +02:00
if ( ! varlist . empty ( ) & & varlist . front ( ) = = tok2 - > tokAt ( 3 ) ) {
2011-12-26 07:13:10 +01:00
nullPointerError ( tok2 - > tokAt ( 3 ) , varname , tok - > linenr ( ) , inconclusive ) ;
2011-07-31 14:07:35 +02:00
break ;
}
}
2011-08-02 11:20:09 +02:00
2011-12-25 17:01:45 +01:00
// Passing pointer as parameter..
if ( Token : : Match ( tok2 , " [;{}] %type% ( " ) ) {
2011-12-26 07:13:10 +01:00
if ( CanFunctionAssignPointer ( tok2 - > next ( ) , varid ) ) {
if ( ! _settings - > inconclusive )
break ;
inconclusive = true ;
}
2011-12-25 17:01:45 +01:00
}
2011-08-02 11:20:09 +02:00
// calling unknown function => it might initialize the pointer
2011-08-14 16:53:09 +02:00
if ( ! ( var - > isLocal ( ) | | var - > isArgument ( ) ) )
2011-08-02 11:20:09 +02:00
break ;
2011-01-31 17:30:27 +01:00
}
2011-01-15 12:09:36 +01:00
if ( tok1 - > str ( ) = = " break " )
break ;
2011-10-13 20:53:06 +02:00
if ( tok1 - > varId ( ) = = varid ) {
2011-10-02 19:27:18 +02:00
// Don't write warning if the dereferencing is
2011-12-02 06:11:55 +01:00
// guarded by ?: or &&
2011-10-02 19:27:18 +02:00
const Token * tok2 = tok1 - > previous ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok2 & & ( tok2 - > isArithmeticalOp ( ) | | tok2 - > str ( ) = = " ( " ) ) {
while ( tok2 & & ! Token : : Match ( tok2 , " [;{}?:] " ) ) {
2011-10-02 19:27:18 +02:00
if ( tok2 - > str ( ) = = " ) " )
tok2 = tok2 - > link ( ) ;
2011-12-02 06:11:55 +01:00
// guarded by &&
if ( tok2 - > varId ( ) = = varid & & tok2 - > next ( ) - > str ( ) = = " && " )
break ;
2011-10-02 19:27:18 +02:00
tok2 = tok2 - > previous ( ) ;
}
}
2011-12-02 06:11:55 +01:00
if ( Token : : Match ( tok2 , " [?:] " ) | | tok2 - > varId ( ) = = varid )
2011-10-02 19:27:18 +02:00
continue ;
2011-01-06 13:18:49 +01:00
// unknown : this is set by isPointerDeRef if it is
// uncertain
2012-01-25 15:16:22 +01:00
bool unknown = _settings - > inconclusive ;
2011-01-06 13:18:49 +01:00
2012-05-01 07:06:14 +02:00
// reassign : is the pointer reassigned like this:
// tok = tok->next();
bool reassign = false ;
if ( Token : : Match ( tok1 - > previous ( ) , " = %varid% . " , varid ) ) {
const Token * back = tok1 - > tokAt ( - 2 ) ;
while ( back ) {
if ( back - > varId ( ) = = varid ) {
reassign = true ;
break ;
}
if ( Token : : Match ( back , " [{};,(] " ) ) {
break ;
}
back = back - > previous ( ) ;
}
}
if ( reassign ) {
2010-11-04 18:18:19 +01:00
break ;
2011-12-08 19:30:14 +01:00
} else if ( Token : : simpleMatch ( tok1 - > tokAt ( - 2 ) , " * ) " ) & &
Token : : Match ( tok1 - > linkAt ( - 1 ) - > tokAt ( - 2 ) , " %varid% = ( " , tok1 - > varId ( ) ) ) {
break ;
} else if ( Token : : simpleMatch ( tok1 - > tokAt ( - 3 ) , " * ) ( " ) & &
Token : : Match ( tok1 - > linkAt ( - 2 ) - > tokAt ( - 2 ) , " %varid% = ( " , tok1 - > varId ( ) ) ) {
break ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok1 - > previous ( ) , " &&|%oror% " ) ) {
2011-08-20 09:47:55 +02:00
break ;
2011-10-13 20:53:06 +02:00
} else if ( Token : : Match ( tok1 - > tokAt ( - 2 ) , " &&|%oror% ! " ) ) {
2011-08-20 09:47:55 +02:00
break ;
2012-01-25 15:16:22 +01:00
} else if ( CheckNullPointer : : isPointerDeRef ( tok1 , unknown , symbolDatabase ) ) {
2011-12-26 07:13:10 +01:00
nullPointerError ( tok1 , varname , tok - > linenr ( ) , inconclusive ) ;
2010-10-31 11:51:25 +01:00
break ;
2012-03-16 17:24:03 +01:00
} else if ( tok1 - > strAt ( - 1 ) = = " & " ) {
2010-10-31 11:51:25 +01:00
break ;
2012-03-16 17:24:03 +01:00
} else if ( tok1 - > strAt ( 1 ) = = " = " ) {
2010-10-31 11:51:25 +01:00
break ;
}
}
else if ( tok1 - > str ( ) = = " { " ||
tok1 - > str ( ) = = " } " )
break ;
// label..
else if ( Token : : Match ( tok1 , " %type% : " ) )
break ;
}
}
}
}
void CheckNullPointer : : nullPointerByCheckAndDeRef ( )
{
2012-01-21 19:55:32 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2011-01-06 13:18:49 +01:00
2012-01-21 19:55:32 +01:00
// Check if pointer is NULL and then dereference it..
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
if ( i - > type ! = Scope : : eIf & & i - > type ! = Scope : : eElseIf & & i - > type ! = Scope : : eWhile )
continue ;
if ( ! i - > classDef | | i - > classDef - > isExpandedMacro ( ) )
continue ;
2011-01-17 19:23:00 +01:00
2012-01-26 16:50:59 +01:00
const Token * const tok = i - > type ! = Scope : : eElseIf ? i - > classDef - > next ( ) : i - > classDef - > tokAt ( 2 ) ;
2012-01-21 19:55:32 +01:00
// TODO: investigate false negatives:
// - handle "while"?
// - if there are logical operators
// - if (x) { } else { ... }
2010-11-04 21:22:29 +01:00
2012-01-21 19:55:32 +01:00
// If the if-body ends with a unknown macro then bailout
if ( Token : : Match ( i - > classEnd - > tokAt ( - 3 ) , " [;{}] %var% ; " ) & & isUpper ( i - > classEnd - > strAt ( - 2 ) ) )
continue ;
2011-01-06 13:18:49 +01:00
2012-01-21 19:55:32 +01:00
// vartok : token for the variable
const Token * vartok = 0 ;
2012-02-11 16:15:38 +01:00
const Token * checkConditionStart = 0 ;
if ( Token : : Match ( tok , " ( ! %var% )|&& " ) ) {
2012-01-21 19:55:32 +01:00
vartok = tok - > tokAt ( 2 ) ;
2012-02-11 16:15:38 +01:00
checkConditionStart = vartok - > next ( ) ;
} else if ( Token : : Match ( tok , " ( %var% ) | & & " )) {
2012-01-26 16:50:59 +01:00
vartok = tok - > next ( ) ;
2012-02-11 16:15:38 +01:00
} else if ( Token : : Match ( tok , " ( ! ( %var% = " ) ) {
2012-01-26 16:50:59 +01:00
vartok = tok - > tokAt ( 3 ) ;
2012-03-16 17:24:03 +01:00
if ( Token : : simpleMatch ( tok - > tokAt ( 2 ) - > link ( ) , " ) && " ) )
2012-02-11 16:15:38 +01:00
checkConditionStart = tok - > tokAt ( 2 ) - > link ( ) ;
} else
2012-01-21 19:55:32 +01:00
continue ;
2011-03-28 18:48:27 +02:00
2012-01-21 19:55:32 +01:00
// variable id for pointer
const unsigned int varid ( vartok - > varId ( ) ) ;
if ( varid = = 0 )
continue ;
2010-11-04 21:22:29 +01:00
2012-01-21 19:55:32 +01:00
// Check if variable is a pointer
2012-02-11 16:15:38 +01:00
const Variable * var = _tokenizer - > getSymbolDatabase ( ) - > getVariableFromVarId ( varid ) ;
2012-01-21 19:55:32 +01:00
if ( ! var | | ! var - > isPointer ( ) )
continue ;
2011-01-06 13:18:49 +01:00
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( vartok - > next ( ) , " && ( %varid% = " , varid ) )
continue ;
2011-01-09 20:16:16 +01:00
2012-02-11 16:15:38 +01:00
// Name and line of the pointer
const std : : string & pointerName = vartok - > str ( ) ;
const unsigned int linenr = vartok - > linenr ( ) ;
2012-01-21 19:55:32 +01:00
// if this is true then it is known that the pointer is null
bool null = true ;
2011-03-27 11:04:58 +02:00
2012-02-11 16:15:38 +01:00
// Check the condition (eg. ( !x && x->i )
if ( checkConditionStart ) {
const Token * const conditionEnd = tok - > link ( ) ;
for ( const Token * tok2 = checkConditionStart ; tok2 ! = conditionEnd ; tok2 = tok2 - > next ( ) ) {
// If we hit a || operator, abort
2012-03-16 17:24:03 +01:00
if ( tok2 - > str ( ) = = " || " ) {
2012-02-11 16:15:38 +01:00
break ;
}
// Pointer is used
else if ( Token : : Match ( tok2 , " * %varid% " , varid ) ) {
nullPointerError ( tok2 - > tokAt ( 2 ) , pointerName , linenr , false ) ;
break ;
}
// Pointer is used
else if ( Token : : Match ( tok2 , " %varid% . " , varid ) ) {
nullPointerError ( tok2 , pointerName , linenr , false ) ;
break ;
}
}
}
2012-01-21 19:55:32 +01:00
// start token = inside the if-body
const Token * tok1 = i - > classStart ;
2011-01-09 20:16:16 +01:00
2012-01-26 16:50:59 +01:00
if ( Token : : Match ( tok , " ( %var% )|&& " ) ) {
2012-01-21 19:55:32 +01:00
// pointer might be null
null = false ;
2011-03-27 11:04:58 +02:00
2012-01-21 19:55:32 +01:00
// start token = first token after the if/while body
tok1 = i - > classEnd - > next ( ) ;
if ( ! tok1 )
continue ;
}
2011-01-09 20:16:16 +01:00
2012-01-26 16:50:59 +01:00
unsigned int indentlevel = 0 ;
2011-10-29 14:55:52 +02:00
2012-01-21 19:55:32 +01:00
// Set to true if we would normally bail out the check.
bool inconclusive = false ;
2011-03-27 21:29:49 +02:00
2012-01-21 19:55:32 +01:00
// Count { and } for tok2
for ( const Token * tok2 = tok1 ; tok2 ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > str ( ) = = " { " )
+ + indentlevel ;
else if ( tok2 - > str ( ) = = " } " ) {
if ( indentlevel = = 0 )
break ;
- - indentlevel ;
2011-12-28 08:17:58 +01:00
2012-01-21 19:55:32 +01:00
// calling exit function?
bool unknown = false ;
if ( _tokenizer - > IsScopeNoReturn ( tok2 , & unknown ) ) {
if ( _settings - > inconclusive & & unknown )
inconclusive = true ;
else
break ;
2010-10-31 11:51:25 +01:00
}
2012-01-21 19:55:32 +01:00
if ( null & & indentlevel = = 0 ) {
// skip all "else" blocks because they are not executed in this execution path
while ( Token : : simpleMatch ( tok2 , " } else { " ) )
tok2 = tok2 - > linkAt ( 2 ) ;
null = false ;
2010-10-31 11:51:25 +01:00
}
2012-01-21 19:55:32 +01:00
}
2010-10-31 11:51:25 +01:00
2012-01-25 15:16:22 +01:00
if ( tok2 - > str ( ) = = " return " | | tok2 - > str ( ) = = " throw " ) {
bool unknown = _settings - > inconclusive ;
for ( ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) = = varid ) {
if ( CheckNullPointer : : isPointerDeRef ( tok2 , unknown , symbolDatabase ) )
nullPointerError ( tok2 , pointerName , linenr , inconclusive ) ;
else if ( unknown )
nullPointerError ( tok2 , pointerName , linenr , true ) ;
}
}
2012-01-21 19:55:32 +01:00
break ;
}
2011-12-17 12:44:11 +01:00
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok2 , " goto|continue|break|if|switch|for " ) )
break ;
2012-01-21 19:55:32 +01:00
// parameters to sizeof are not dereferenced
if ( Token : : Match ( tok2 , " decltype|sizeof " ) ) {
if ( tok2 - > strAt ( 1 ) ! = " ( " )
2012-01-26 16:50:59 +01:00
tok2 = tok2 - > next ( ) ;
else
tok2 = tok2 - > next ( ) - > link ( ) ;
2012-01-21 19:55:32 +01:00
continue ;
}
2011-07-31 17:19:23 +02:00
2012-01-21 19:55:32 +01:00
// function call, check if pointer is dereferenced
if ( Token : : Match ( tok2 , " %var% ( " ) ) {
std : : list < const Token * > vars ;
parseFunctionCall ( * tok2 , vars , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = vars . begin ( ) ; it ! = vars . end ( ) ; + + it ) {
if ( Token : : Match ( * it , " %varid% [,)] " , varid ) ) {
nullPointerError ( * it , pointerName , linenr , inconclusive ) ;
break ;
2011-10-29 10:35:31 +02:00
}
2012-01-21 19:55:32 +01:00
}
}
2011-07-31 17:32:25 +02:00
2012-01-21 19:55:32 +01:00
// calling unknown function (abort/init)..
2012-01-26 16:50:59 +01:00
else if ( Token : : simpleMatch ( tok2 , " ) ; " ) &&
( Token : : Match ( tok2 - > link ( ) - > tokAt ( - 2 ) , " [;{}.] %var% ( " ) | |
Token : : Match ( tok2 - > link ( ) - > tokAt ( - 5 ) , " [;{}] ( * %var% ) ( " ) ) ) {
2012-01-21 19:55:32 +01:00
// noreturn function?
bool unknown = false ;
if ( _tokenizer - > IsScopeNoReturn ( tok2 - > tokAt ( 2 ) , & unknown ) ) {
if ( ! unknown | | ! _settings - > inconclusive ) {
2011-07-31 17:32:25 +02:00
break ;
2012-01-21 19:55:32 +01:00
}
2012-01-26 16:50:59 +01:00
inconclusive = _settings - > inconclusive ;
2010-10-31 11:51:25 +01:00
}
2012-01-21 19:55:32 +01:00
// init function (global variables)
if ( ! var | | ! ( var - > isLocal ( ) | | var - > isArgument ( ) ) )
break ;
}
2010-10-31 15:32:19 +01:00
2012-01-21 19:55:32 +01:00
if ( tok2 - > varId ( ) = = varid ) {
// unknown: this is set to true by isPointerDeRef if
// the function fails to determine if there
// is a dereference or not
bool unknown = _settings - > inconclusive ;
2010-10-31 11:51:25 +01:00
2012-01-21 19:55:32 +01:00
if ( Token : : Match ( tok2 - > previous ( ) , " [;{}=] %var% = 0 ; " ) )
;
2010-10-31 11:51:25 +01:00
2012-01-25 15:16:22 +01:00
else if ( CheckNullPointer : : isPointerDeRef ( tok2 , unknown , symbolDatabase ) )
2012-01-21 19:55:32 +01:00
nullPointerError ( tok2 , pointerName , linenr , inconclusive ) ;
2011-10-29 15:48:54 +02:00
2012-01-21 19:55:32 +01:00
else if ( unknown & & _settings - > inconclusive )
nullPointerError ( tok2 , pointerName , linenr , true ) ;
else
break ;
2010-10-31 11:51:25 +01:00
}
}
}
}
void CheckNullPointer : : nullPointer ( )
{
nullPointerAfterLoop ( ) ;
nullPointerLinkedList ( ) ;
nullPointerStructByDeRefAndChec ( ) ;
nullPointerByDeRefAndChec ( ) ;
nullPointerByCheckAndDeRef ( ) ;
}
2010-12-15 18:45:53 +01:00
/** Dereferencing null constant (simplified token list) */
2010-10-31 11:51:25 +01:00
void CheckNullPointer : : nullConstantDereference ( )
{
2012-01-21 19:55:32 +01:00
const SymbolDatabase * symbolDatabase = _tokenizer - > getSymbolDatabase ( ) ;
2010-10-31 11:51:25 +01:00
2012-01-21 19:55:32 +01:00
for ( std : : list < Scope > : : const_iterator i = symbolDatabase - > scopeList . begin ( ) ; i ! = symbolDatabase - > scopeList . end ( ) ; + + i ) {
if ( i - > type ! = Scope : : eFunction | | ! i - > classStart )
continue ;
2010-10-31 11:51:25 +01:00
2012-01-26 16:50:59 +01:00
const Token * tok = i - > classStart ;
if ( i - > function & & ( i - > function - > type = = Function : : eConstructor | | i - > function - > type = = Function : : eCopyConstructor ) )
tok = i - > function - > token ; // Check initialization list
for ( ; tok ! = i - > classEnd ; tok = tok - > next ( ) ) {
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok , " sizeof|decltype|typeid ( " ) )
tok = tok - > next ( ) - > link ( ) ;
2010-10-31 11:51:25 +01:00
2011-10-13 20:53:06 +02:00
else if ( Token : : simpleMatch ( tok , " * 0 " ) ) {
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok - > previous ( ) , " return|throw|;|{|}|:|[|(|, " ) | | tok - > previous ( ) - > isOp ( ) | | tok - > previous ( ) - > isAssignmentOp ( ) ) {
2010-10-31 11:51:25 +01:00
nullPointerError ( tok ) ;
}
}
2010-12-26 19:29:58 +01:00
2012-01-25 15:16:22 +01:00
else if ( Token : : Match ( tok , " 0 [ " ) & & ( tok - > previous ( ) - > str ( ) ! = " & " | | ! Token : : Match ( tok - > next ( ) - > link ( ) - > next ( ) , " [.(] " ) ) )
nullPointerError ( tok ) ;
2012-02-11 12:26:48 +01:00
else if ( Token : : Match ( tok - > previous ( ) , " !!. %var% ( " ) & & ( tok - > previous ( ) - > str ( ) ! = " :: " | | tok - > strAt ( - 2 ) = = " std " ) ) {
2012-04-02 12:12:02 +02:00
if ( Token : : simpleMatch ( tok - > tokAt ( 2 ) , " 0 ) " ) & & tok - > varId ( ) ) { // constructor call
2012-02-11 12:26:48 +01:00
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & Token : : Match ( var - > typeStartToken ( ) , " std :: string !!:: " ) )
2012-02-11 12:26:48 +01:00
nullPointerError ( tok ) ;
2012-04-02 12:12:02 +02:00
} else { // function call
std : : list < const Token * > var ;
parseFunctionCall ( * tok , var , 0 ) ;
// is one of the var items a NULL pointer?
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it ) {
if ( Token : : Match ( * it , " 0 [,)] " ) ) {
nullPointerError ( * it ) ;
}
2010-12-26 19:29:58 +01:00
}
}
2012-01-28 20:31:12 +01:00
} else if ( Token : : simpleMatch ( tok , " std :: string ( 0 ) " ) )
2012-01-25 15:16:22 +01:00
nullPointerError ( tok ) ;
2012-03-16 17:24:03 +01:00
else if ( Token : : simpleMatch ( tok - > previous ( ) , " >> 0 " ) ) { // Only checking input stream operations is safe here, because otherwise 0 can be an integer as well
const Token * tok2 = tok - > previous ( ) ; // Find start of statement
for ( ; tok2 ; tok2 = tok2 - > previous ( ) ) {
if ( Token : : Match ( tok2 - > previous ( ) , " ;|{|}|: " ) )
break ;
}
if ( Token : : simpleMatch ( tok2 , " std :: cin " ) )
nullPointerError ( tok ) ;
if ( tok2 & & tok2 - > varId ( ) ! = 0 ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok2 - > varId ( ) ) ;
2012-06-08 18:05:02 +02:00
if ( var & & Token : : Match ( var - > typeStartToken ( ) , " std :: istream|ifstream|istringstream|stringstream|fstream|iostream " ) )
2012-03-16 17:24:03 +01:00
nullPointerError ( tok ) ;
}
}
2012-01-25 15:16:22 +01:00
unsigned int ovarid = 0 ;
if ( Token : : Match ( tok , " 0 ==|!= %var% " ) )
ovarid = tok - > tokAt ( 2 ) - > varId ( ) ;
2012-04-02 12:12:02 +02:00
else if ( Token : : Match ( tok , " %var% ==|!= 0 " ) )
ovarid = tok - > varId ( ) ;
else if ( Token : : Match ( tok , " %var% =|+=|+ 0 ) | ] | , | ; | + " ))
2012-01-25 15:16:22 +01:00
ovarid = tok - > varId ( ) ;
if ( ovarid ) {
const Variable * var = symbolDatabase - > getVariableFromVarId ( ovarid ) ;
2012-06-08 18:05:02 +02:00
if ( var & & ! var - > isPointer ( ) & & ! var - > isArray ( ) & & Token : : Match ( var - > typeStartToken ( ) , " std :: string !!:: " ) )
2012-01-25 15:16:22 +01:00
nullPointerError ( tok ) ;
2010-12-26 19:29:58 +01:00
}
2010-10-31 11:51:25 +01:00
}
}
}
/// @addtogroup Checks
/// @{
/**
* @ brief % Check for null pointer usage ( using ExecutionPath )
*/
2011-10-13 20:53:06 +02:00
class Nullpointer : public ExecutionPath {
2010-10-31 11:51:25 +01:00
public :
/** Startup constructor */
2012-01-25 15:16:22 +01:00
Nullpointer ( Check * c , const SymbolDatabase * symbolDatabase_ ) : ExecutionPath ( c , 0 ) , symbolDatabase ( symbolDatabase_ ) , null ( false ) {
2010-10-31 11:51:25 +01:00
}
private :
2012-01-25 15:16:22 +01:00
const SymbolDatabase * symbolDatabase ;
2010-10-31 11:51:25 +01:00
/** Create checking of specific variable: */
2012-01-25 15:16:22 +01:00
Nullpointer ( Check * c , const unsigned int id , const std : : string & name , const SymbolDatabase * symbolDatabase_ )
2010-10-31 11:51:25 +01:00
: ExecutionPath ( c , id ) ,
2012-01-25 15:16:22 +01:00
symbolDatabase ( symbolDatabase_ ) ,
2010-10-31 11:51:25 +01:00
varname ( name ) ,
2011-10-13 20:53:06 +02:00
null ( false ) {
2010-10-31 11:51:25 +01:00
}
/** Copy this check */
2011-10-13 20:53:06 +02:00
ExecutionPath * copy ( ) {
2010-10-31 11:51:25 +01:00
return new Nullpointer ( * this ) ;
}
/** no implementation => compiler error if used by accident */
void operator = ( const Nullpointer & ) ;
/** is other execution path equal? */
2011-10-13 20:53:06 +02:00
bool is_equal ( const ExecutionPath * e ) const {
2010-10-31 11:51:25 +01:00
const Nullpointer * c = static_cast < const Nullpointer * > ( e ) ;
return ( varname = = c - > varname & & null = = c - > null ) ;
}
/** variable name for this check (empty => dummy check) */
const std : : string varname ;
/** is this variable null? */
bool null ;
/** variable is set to null */
2011-10-13 20:53:06 +02:00
static void setnull ( std : : list < ExecutionPath * > & checks , const unsigned int varid ) {
2010-10-31 11:51:25 +01:00
std : : list < ExecutionPath * > : : iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 11:51:25 +01:00
Nullpointer * c = dynamic_cast < Nullpointer * > ( * it ) ;
if ( c & & c - > varId = = varid )
c - > null = true ;
}
}
/**
* Dereferencing variable . Check if it is safe ( if the variable is null there ' s an error )
* @ param checks Checks
* @ param tok token where dereferencing happens
*/
2011-10-13 20:53:06 +02:00
static void dereference ( std : : list < ExecutionPath * > & checks , const Token * tok ) {
2010-10-31 11:51:25 +01:00
const unsigned int varid ( tok - > varId ( ) ) ;
std : : list < ExecutionPath * > : : iterator it ;
2011-10-13 20:53:06 +02:00
for ( it = checks . begin ( ) ; it ! = checks . end ( ) ; + + it ) {
2010-10-31 11:51:25 +01:00
Nullpointer * c = dynamic_cast < Nullpointer * > ( * it ) ;
2011-10-13 20:53:06 +02:00
if ( c & & c - > varId = = varid & & c - > null ) {
2012-03-07 20:31:23 +01:00
if ( ( Token : : Match ( tok - > tokAt ( - 4 ) , " [=[(,] %var% && * %var% ,|]|)|;|=|%op% " ) | |
Token : : Match ( tok - > tokAt ( - 5 ) , " [=[(,] ! %var% %oror% * %var% ,|]|)|;|=|%op% " ) | |
Token : : Match ( tok - > tokAt ( - 4 ) , " return|case %var% && * %var% ,|:|;|=|%op% " ) | |
Token : : Match ( tok - > tokAt ( - 5 ) , " return|case ! %var% %oror% * %var% ,|:|;|=|%op% " ) ) & &
tok - > tokAt ( - 3 ) & & ( tok - > tokAt ( - 3 ) - > varId ( ) = = tok - > varId ( ) ) )
return ;
2010-10-31 11:51:25 +01:00
CheckNullPointer * checkNullPointer = dynamic_cast < CheckNullPointer * > ( c - > owner ) ;
2011-10-13 20:53:06 +02:00
if ( checkNullPointer ) {
2010-10-31 11:51:25 +01:00
checkNullPointer - > nullPointerError ( tok , c - > varname ) ;
return ;
}
}
}
}
/** parse tokens */
2011-10-13 20:53:06 +02:00
const Token * parse ( const Token & tok , std : : list < ExecutionPath * > & checks ) const {
2012-01-25 15:16:22 +01:00
if ( tok . varId ( ) ! = 0 ) {
// Pointer declaration declaration?
const Variable * var = symbolDatabase - > getVariableFromVarId ( tok . varId ( ) ) ;
if ( var & & var - > isPointer ( ) & & var - > nameToken ( ) = = & tok )
checks . push_back ( new Nullpointer ( owner , var - > varId ( ) , var - > name ( ) , symbolDatabase ) ) ;
2010-10-31 11:51:25 +01:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : simpleMatch ( & tok , " try { " ) ) {
2010-10-31 11:51:25 +01:00
// Bail out all used variables
2012-01-25 15:16:22 +01:00
const Token * tok2 = & tok ;
2012-01-26 15:20:20 +01:00
const Token * endtok = tok . linkAt ( 1 ) ;
for ( ; tok2 & & tok2 ! = endtok ; tok2 = tok2 - > next ( ) ) {
2012-01-25 15:16:22 +01:00
if ( tok2 - > varId ( ) )
2010-10-31 11:51:25 +01:00
bailOutVar ( checks , tok2 - > varId ( ) ) ;
}
2012-01-25 15:16:22 +01:00
return tok2 ;
2010-10-31 11:51:25 +01:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " %var% ( " ) ) {
2011-11-11 09:58:17 +01:00
if ( tok . str ( ) = = " sizeof " | | tok . str ( ) = = " typeid " )
2010-10-31 11:51:25 +01:00
return tok . next ( ) - > link ( ) ;
// parse usage..
std : : list < const Token * > var ;
CheckNullPointer : : parseFunctionCall ( tok , var , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
dereference ( checks , * it ) ;
}
2010-12-09 18:17:56 +01:00
else if ( Token : : simpleMatch ( & tok , " ( 0 && " ) )
return tok . link ( ) ;
2011-10-13 20:53:06 +02:00
if ( tok . varId ( ) ! = 0 ) {
2012-01-25 15:16:22 +01:00
// unknown: if isPointerDeRef fails to determine if there
// is a dereference this will be set to true.
2011-12-12 07:35:53 +01:00
bool unknown = owner - > inconclusiveFlag ( ) ;
2012-01-25 15:16:22 +01:00
bool deref = CheckNullPointer : : isPointerDeRef ( & tok , unknown , symbolDatabase ) ;
2011-01-06 13:18:49 +01:00
2012-01-25 15:16:22 +01:00
if ( deref )
2010-10-31 11:51:25 +01:00
dereference ( checks , & tok ) ;
2011-10-18 19:34:14 +02:00
else if ( unknown & & owner - > inconclusiveFlag ( ) )
dereference ( checks , & tok ) ;
2012-01-25 15:16:22 +01:00
if ( Token : : Match ( tok . previous ( ) , " [;{}=] %var% = 0 ; " ) )
setnull ( checks , tok . varId ( ) ) ;
else if ( ! deref & &
2012-02-13 19:46:45 +01:00
( ! tok . previous ( ) - > isOp ( ) | | tok . previous ( ) - > str ( ) = = " & " ) & & ! tok . previous ( ) - > isAssignmentOp ( ) & &
2012-01-25 15:16:22 +01:00
( ! tok . next ( ) - > isOp ( ) | | tok . next ( ) - > str ( ) = = " >> " ) )
bailOutVar ( checks , tok . varId ( ) ) ; // If its possible that the pointers value changes, bail out.
2010-10-31 11:51:25 +01:00
}
2011-10-13 20:53:06 +02:00
else if ( tok . str ( ) = = " delete " ) {
2010-10-31 11:51:25 +01:00
const Token * ret = tok . next ( ) ;
if ( Token : : simpleMatch ( ret , " [ ] " ) )
ret = ret - > tokAt ( 2 ) ;
if ( Token : : Match ( ret , " %var% ; " ) )
return ret - > next ( ) ;
}
2011-07-25 21:40:32 +02:00
2011-10-13 20:53:06 +02:00
else if ( tok . str ( ) = = " return " ) {
2012-01-25 15:16:22 +01:00
bool unknown = owner - > inconclusiveFlag ( ) ;
const Token * tok2 = & tok ;
for ( ; tok2 & & tok2 - > str ( ) ! = " ; " ; tok2 = tok2 - > next ( ) ) {
if ( tok2 - > varId ( ) ) {
if ( CheckNullPointer : : isPointerDeRef ( tok2 , unknown , symbolDatabase ) | | unknown )
dereference ( checks , tok2 ) ;
}
2012-01-28 08:06:03 +01:00
// If return statement contains "?" then assume there
// is no dangours dereferencing later
if ( tok2 - > str ( ) = = " ? " ) {
while ( tok2 & & tok2 - > str ( ) ! = " ; " )
tok2 = tok2 - > next ( ) ;
return tok2 ;
}
2011-07-25 21:40:32 +02:00
}
2012-01-25 15:16:22 +01:00
return tok2 ;
2011-07-25 21:40:32 +02:00
}
2010-10-31 11:51:25 +01:00
return & tok ;
}
/** parse condition. @sa ExecutionPath::parseCondition */
2011-10-13 20:53:06 +02:00
bool parseCondition ( const Token & tok , std : : list < ExecutionPath * > & checks ) {
for ( const Token * tok2 = & tok ; tok2 ; tok2 = tok2 - > next ( ) ) {
2012-05-31 18:41:00 +02:00
if ( tok2 - > str ( ) = = " ( " | | tok2 - > str ( ) = = " ) " | | tok2 - > str ( ) = = " && " | | tok2 - > str ( ) = = " || " | | tok2 - > str ( ) = = " ? " )
2010-10-31 11:51:25 +01:00
break ;
2012-01-25 15:16:22 +01:00
bool unknown = owner - > inconclusiveFlag ( ) ;
if ( tok2 - > varId ( ) & & ( CheckNullPointer : : isPointerDeRef ( tok2 , unknown , symbolDatabase ) | | unknown ) )
dereference ( checks , tok2 ) ;
2010-10-31 11:51:25 +01:00
}
2011-10-13 20:53:06 +02:00
if ( Token : : Match ( & tok , " !| %var% ( " ) ) {
2010-10-31 11:51:25 +01:00
std : : list < const Token * > var ;
CheckNullPointer : : parseFunctionCall ( tok . str ( ) = = " ! " ? * tok . next ( ) : tok , var , 0 ) ;
for ( std : : list < const Token * > : : const_iterator it = var . begin ( ) ; it ! = var . end ( ) ; + + it )
dereference ( checks , * it ) ;
}
return ExecutionPath : : parseCondition ( tok , checks ) ;
}
2011-10-13 20:53:06 +02:00
void parseLoopBody ( const Token * tok , std : : list < ExecutionPath * > & checks ) const {
while ( tok ) {
2010-10-31 11:51:25 +01:00
if ( Token : : Match ( tok , " {|}|return|goto|break|if " ) )
return ;
const Token * next = parse ( * tok , checks ) ;
if ( next )
tok = tok - > next ( ) ;
}
}
} ;
/// @}
void CheckNullPointer : : executionPaths ( )
{
// Check for null pointer errors..
2012-01-25 15:16:22 +01:00
Nullpointer c ( this , _tokenizer - > getSymbolDatabase ( ) ) ;
2012-01-26 16:50:59 +01:00
checkExecutionPaths ( _tokenizer - > getSymbolDatabase ( ) , & c ) ;
2010-10-31 11:51:25 +01:00
}
void CheckNullPointer : : nullPointerError ( const Token * tok )
{
reportError ( tok , Severity : : error , " nullPointer " , " Null pointer dereference " ) ;
}
void CheckNullPointer : : nullPointerError ( const Token * tok , const std : : string & varname )
{
reportError ( tok , Severity : : error , " nullPointer " , " Possible null pointer dereference: " + varname ) ;
}
2011-10-09 15:09:02 +02:00
void CheckNullPointer : : nullPointerError ( const Token * tok , const std : : string & varname , const unsigned int line , bool inconclusive )
2010-10-31 11:51:25 +01:00
{
2011-10-09 15:09:02 +02:00
const std : : string errmsg ( " Possible null pointer dereference: " + varname + " - otherwise it is redundant to check if " + varname + " is null at line " + MathLib : : toString < unsigned int > ( line ) ) ;
2012-05-06 19:37:41 +02:00
reportError ( tok , Severity : : error , " nullPointer " , errmsg , inconclusive ) ;
2010-10-31 11:51:25 +01:00
}