/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2014 Daniel Marjamki and Cppcheck team.
*
* 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 .
*/
#include "tokenize.h"
#include "checknullpointer.h"
#include "testsuite.h"
#include
extern std::ostringstream errout;
class TestNullPointer : public TestFixture {
public:
TestNullPointer() : TestFixture("TestNullPointer") {
}
private:
Settings settings;
void run() {
LOAD_LIB_2(settings.library, "std.cfg");
TEST_CASE(nullpointerAfterLoop);
TEST_CASE(nullpointer1);
TEST_CASE(nullpointer2);
TEST_CASE(structDerefAndCheck); // dereferencing struct and then checking if it's null
TEST_CASE(pointerDerefAndCheck);
TEST_CASE(nullpointer5); // References should not be checked
TEST_CASE(nullpointerExecutionPaths);
TEST_CASE(nullpointerExecutionPathsLoop);
TEST_CASE(nullpointer7);
TEST_CASE(nullpointer9);
TEST_CASE(nullpointer10);
TEST_CASE(nullpointer11); // ticket #2812
TEST_CASE(nullpointer12); // ticket #2470
TEST_CASE(nullpointer14);
TEST_CASE(nullpointer15); // #3560 (fp: return p ? f(*p) : f(0))
TEST_CASE(nullpointer16); // #3591
TEST_CASE(nullpointer17); // #3567
TEST_CASE(nullpointer18); // #1927
TEST_CASE(nullpointer19); // #3811
TEST_CASE(nullpointer20); // #3807 (fp: return p ? (p->x() || p->y()) : z)
TEST_CASE(nullpointer21); // #4038 (fp: if (x) p=q; else return;)
TEST_CASE(nullpointer23); // #4665 (false positive)
TEST_CASE(nullpointer24); // #5082 fp: chained assignment
TEST_CASE(nullpointer25); // #5061
TEST_CASE(nullpointer26); // #3589
TEST_CASE(nullpointerSwitch); // #2626
TEST_CASE(nullpointer_cast); // #4692
TEST_CASE(nullpointer_castToVoid); // #3771
TEST_CASE(pointerCheckAndDeRef); // check if pointer is null and then dereference it
TEST_CASE(nullConstantDereference); // Dereference NULL constant
TEST_CASE(gcc_statement_expression); // Don't crash
TEST_CASE(snprintf_with_zero_size);
TEST_CASE(snprintf_with_non_zero_size);
TEST_CASE(printf_with_invalid_va_argument);
TEST_CASE(scanf_with_invalid_va_argument);
TEST_CASE(nullpointer_in_return);
TEST_CASE(nullpointer_in_typeid);
TEST_CASE(nullpointer_in_for_loop);
TEST_CASE(nullpointerDelete);
TEST_CASE(nullpointerExit);
TEST_CASE(nullpointerStdString);
TEST_CASE(nullpointerStdStream);
TEST_CASE(functioncall);
TEST_CASE(functioncalllibrary); // use Library to parse function call
TEST_CASE(crash1);
TEST_CASE(functioncallDefaultArguments);
TEST_CASE(nullpointer_internal_error); // #5080
TEST_CASE(nullpointerFputc); // #5645 FP: Null pointer dereference in fputc argument
TEST_CASE(nullpointerMemchr);
TEST_CASE(nullpointerPutchar);
// Test that std.cfg is configured correctly
TEST_CASE(stdcfg);
// Load posix library file
LOAD_LIB_2(settings.library, "posix.cfg");
// Test that posix.cfg is configured correctly
TEST_CASE(posixcfg);
}
void check(const char code[], bool inconclusive = false, const char filename[] = "test.cpp", bool verify=true) {
// Clear the error buffer..
errout.str("");
settings.addEnabled("warning");
settings.inconclusive = inconclusive;
// Tokenize..
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
if (!tokenizer.tokenize(istr, filename))
return;
// Check for redundant code..
CheckNullPointer checkNullPointer(&tokenizer, &settings, this);
checkNullPointer.nullPointer();
const std::string str1(tokenizer.tokens()->stringifyList(0,true));
tokenizer.simplifyTokenList2();
const std::string str2(tokenizer.tokens()->stringifyList(0,true));
if (verify && str1 != str2)
warnUnsimplified(str1, str2);
checkNullPointer.nullConstantDereference();
}
void nullpointerAfterLoop() {
check("int foo(const Token *tok)\n"
"{\n"
" while (tok);\n"
" tok = tok->next();\n"
"}", true);
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3]: (warning, inconclusive) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", errout.str());
// #2681
{
const char code[] = "void foo(const Token *tok)\n"
"{\n"
" while (tok && tok->str() == \"=\")\n"
" tok = tok->next();\n"
"\n"
" if (tok->str() != \";\")\n"
" ;\n"
"}\n";
check(code, false); // inconclusive=false => no error
ASSERT_EQUALS("", errout.str());
check(code, true); // inconclusive=true => error
ASSERT_EQUALS("[test.cpp:6] -> [test.cpp:3]: (warning, inconclusive) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", errout.str());
}
check("void foo()\n"
"{\n"
" for (const Token *tok = tokens; tok; tok = tok->next())\n"
" {\n"
" while (tok && tok->str() != \";\")\n"
" tok = tok->next();\n"
" }\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (warning) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(Token &tok)\n"
"{\n"
" for (int i = 0; i < tok.size(); i++ )\n"
" {\n"
" while (!tok)\n"
" char c = tok.read();\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" for (const Token *tok = tokens; tok; tok = tok->next())\n"
" {\n"
" while (tok && tok->str() != \";\")\n"
" tok = tok->next();\n"
" if( !tok ) break;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" for (const Token *tok = tokens; tok; tok = tok ? tok->next() : NULL)\n"
" {\n"
" while (tok && tok->str() != \";\")\n"
" tok = tok->next();\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(A*a)\n"
"{\n"
" switch (a->b()) {\n"
" case 1:\n"
" while( a ){\n"
" a = a->next;\n"
" }\n"
" break;\n"
" case 2:\n"
" a->b();\n"
" break;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// dereference in outer scope..
check("void foo(int x, const Token *tok) {\n"
" if (x == 123) {\n"
" while (tok) tok = tok->next();\n"
" }\n"
" tok->str();\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:3]: (warning, inconclusive) Possible null pointer dereference: tok - otherwise it is redundant to check it against null.\n", "", errout.str());
check("int foo(const Token *tok)\n"
"{\n"
" while (tok){;}\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
check("int foo(const Token *tok)\n"
"{\n"
" while (tok){;}\n"
" char a[2] = {0,0};\n"
"}\n", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer1() {
// ticket #1923 - no false positive when using else if
check("void f(A *a)\n"
"{\n"
" if (a->x == 1)\n"
" {\n"
" a = a->next;\n"
" }\n"
" else if (a->x == 2) { }\n"
" if (a) { }\n"
"}", false, "test.cpp", false);
ASSERT_EQUALS("", errout.str());
// ticket #2134 - sizeof doesn't dereference
check("void f() {\n"
" int c = 1;\n"
" int *list = NULL;\n"
" sizeof(*list);\n"
" if (!list)\n"
" ;\n"
"}", true, "test.cpp", false);
ASSERT_EQUALS("", errout.str());
// ticket #2245 - sizeof doesn't dereference
check("void f(Bar *p) {\n"
" if (!p) {\n"
" int sz = sizeof(p->x);\n"
" }\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer2() {
// Null pointer dereference can only happen with pointers
check("void foo()\n"
"{\n"
" Fred fred;\n"
" while (fred);\n"
" fred.hello();\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
// Dereferencing a struct and then checking if it is null
// This is checked by this function:
// CheckOther::nullPointerStructByDeRefAndChec
void structDerefAndCheck() {
// errors..
check("void foo(struct ABC *abc)\n"
"{\n"
" int a = abc->a;\n"
" if (!abc)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(struct ABC *abc) {\n"
" bar(abc->a);\n"
" bar(x, abc->a);\n"
" bar(x, y, abc->a);\n"
" if (!abc)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n"
"[test.cpp:3] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n"
"[test.cpp:4] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(ABC *abc) {\n"
" if (abc->a == 3) {\n"
" return;\n"
" }\n"
" if (abc) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", errout.str());
check("void f(ABC *abc) {\n"
" if (abc->x == 0) {\n"
" return;\n"
" }\n"
" if (!abc);\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", errout.str());
// TODO: False negative if member of member is dereferenced
check("void foo(ABC *abc) {\n"
" abc->next->a = 0;\n"
" if (abc->next)\n"
" ;\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", "", errout.str());
check("void foo(ABC *abc) {\n"
" abc->a = 0;\n"
" if (abc && abc->b == 0)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n", errout.str());
// ok dereferencing in a condition
check("void foo(struct ABC *abc)\n"
"{\n"
" if (abc && abc->a);\n"
" if (!abc)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(struct ABC *abc) {\n"
" int x = abc && a(abc->x);\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
// ok to use a linked list..
check("void foo(struct ABC *abc)\n"
"{\n"
" abc = abc->next;\n"
" if (!abc)\n"
" ;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f(struct ABC *abc) {\n"
" abc = (ABC *)(abc->_next);\n"
" if (abc) { }"
"}", true, "test.cpp", false);
ASSERT_EQUALS("", errout.str());
// reassign struct..
check("void foo(struct ABC *abc)\n"
"{\n"
" int a = abc->a;\n"
" abc = abc->next;\n"
" if (!abc)\n"
" ;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void foo(struct ABC *abc)\n"
"{\n"
" int a = abc->a;\n"
" f(&abc);\n"
" if (!abc)\n"
" ;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
// goto..
check("void foo(struct ABC *abc)\n"
"{\n"
" int a;\n"
" if (!abc)\n"
" goto out;"
" a = abc->a;\n"
" return;\n"
"out:\n"
" if (!abc)\n"
" ;\n"
"}",false,"test.cpp",false);
ASSERT_EQUALS("", errout.str());
// loops..
check("void foo(struct ABC *abc)\n"
"{\n"
" int a = abc->a;"
" do\n"
" {\n"
" if (abc)\n"
" abc = abc->next;\n"
" --a;\n"
" }\n"
" while (a > 0);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f()\n"
"{\n"
" for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next())\n"
" {\n"
" while (tok && tok->str() != \"{\")\n"
" tok = tok->next();\n"
" if (!tok)\n"
" return;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// dynamic_cast..
check("void foo(ABC *abc)\n"
"{\n"
" int a = abc->a;\n"
" if (!dynamic_cast(abc))\n"
" ;\n"
"}",false,"test.cpp",false);
ASSERT_EQUALS("", errout.str());
// #2641 - global pointer, function call
check("ABC *abc;\n"
"void f() {\n"
" abc->a = 0;\n"
" do_stuff();\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("",errout.str());
check("Fred *fred;\n"
"void f() {\n"
" fred->foo();\n"
" if (fred) { }\n"
"}");
ASSERT_EQUALS("",errout.str());
// #2641 - local pointer, function call
check("void f() {\n"
" ABC *abc;\n"
" abc->a = 0;\n"
" do_stuff();\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:5]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n",errout.str());
// #2641 - local pointer, function call
check("void f(ABC *abc) {\n"
" abc->a = 0;\n"
" do_stuff();\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (warning) Possible null pointer dereference: abc - otherwise it is redundant to check it against null.\n",errout.str());
// #2691 - switch/break
check("void f(ABC *abc) {\n"
" switch ( x ) {\n"
" case 14:\n"
" sprintf(buf, \"%d\", abc->a);\n"
" break;\n"
" case 15:\n"
" if ( abc ) {}\n"
" break;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #3128
check("void f(ABC *abc) {\n"
" x(!abc || y(abc->a));\n"
" if (abc) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(ABC *abc) {\n"
" x(def || !abc || y(def, abc->a));\n"
" if (abc) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(ABC *abc) {\n"
" x(abc && y(def, abc->a));\n"
" if (abc) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(ABC *abc) {\n"
" x(def && abc && y(def, abc->a));\n"
" if (abc) {}\n"
"}");
ASSERT_EQUALS("", errout.str());
// #3228 - calling function with null object
{
const char code[] = "void f(Fred *fred) {\n"
" fred->x();\n"
" if (fred) { }\n"
"}";
check(code);
ASSERT_EQUALS("", errout.str());
check(code, true);
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning, inconclusive) Possible null pointer dereference: fred - otherwise it is redundant to check it against null.\n", errout.str());
}
// #3425 - false positives when there are macros
check("void f(struct FRED *fred) {\n"
" fred->x = 0;\n"
" $if(!fred){}\n"
"}");
ASSERT_EQUALS("", errout.str());
}
// Dereferencing a pointer and then checking if it is null
void pointerDerefAndCheck() {
// errors..
check("void foo(int *p)\n"
"{\n"
" *p = 0;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(int *p)\n"
"{\n"
" *p = 0;\n"
" if (p) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(int *p)\n"
"{\n"
" *p = 0;\n"
" if (p || q) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(int *p)\n"
"{\n"
" bar(*p);\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(char *p)\n"
"{\n"
" strcpy(p, \"abc\");\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
check("void foo(char *p)\n"
"{\n"
" if (*p == 0) { }\n"
" if (!p) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
// no error
check("void foo()\n"
"{\n"
" int *p;\n"
" f(&p);\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" int **p = f();\n"
" if (!p)\n"
" ;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void foo(int *p)\n"
"{\n"
" if (x)\n"
" p = 0;\n"
" else\n"
" *p = 0;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(int x)\n"
"{\n"
" int a = 2 * x;"
" if (x == 0)\n"
" ;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void foo(int *p)\n"
"{\n"
" int var1 = p ? *p : 0;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(int *p)\n"
"{\n"
" int var1 = x ? *p : 5;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
// while
check("void f(int *p) {\n"
" *p = 0;\n"
" while (p) { p = 0; }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(int *p) {\n"
" *p = 0;\n"
" while (p) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
// Ticket #3125
check("void foo(ABC *p)\n"
"{\n"
" int var1 = p ? (p->a) : 0;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(ABC *p)\n"
"{\n"
" int var1 = p ? (1 + p->a) : 0;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" int * a=0;\n"
" if (!a) {};\n"
" int c = a ? 0 : 1;\n"
"}\n",true,"test.cpp",false);
ASSERT_EQUALS("", errout.str());
// #3686
check("void f() {\n"
" int * a=0;\n"
" if (!a) {};\n"
" int c = a ? b : b+1;\n"
"}\n",true,"test.cpp",false);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" int * a=0;\n"
" if (!a) {};\n"
" int c = (a) ? b : b+1;\n"
"}\n",true,"test.cpp",false);
ASSERT_EQUALS("", errout.str());
check("void foo(P *p)\n"
"{\n"
" while (p)\n"
" if (p->check())\n"
" break;\n"
" else\n"
" p = p->next();\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(Document *doc) {\n"
" int x = doc && doc->x;\n"
" if (!doc) {\n"
" return;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #3128 - false positive
check("void f(int *p) {\n"
" assert(!p || (*pnext);\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(x *p)\n"
"{\n"
" p = aa->bar(p->next);\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(x *p)\n"
"{\n"
" p = *p2 = p->next;\n"
" if (!p)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo(struct ABC *abc)\n"
"{\n"
" abc = abc ? abc->next : 0;\n"
" if (!abc)\n"
" ;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(struct ABC *abc) {\n" // #4523
" abc = (*abc).next;\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(struct ABC *abc) {\n" // #4523
" abc = (*abc->ptr);\n"
" if (abc) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("int f(Item *item) {\n"
" x = item ? ab(item->x) : 0;\n"
" if (item) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("int f(Item *item) {\n"
" item->x = 0;\n"
" a = b ? c : d;\n"
" if (item) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (warning) Possible null pointer dereference: item - otherwise it is redundant to check it against null.\n", errout.str());
check("BOOL GotoFlyAnchor()\n" // #2243
"{\n"
" const SwFrm* pFrm = GetCurrFrm();\n"
" do {\n"
" pFrm = pFrm->GetUpper();\n"
" } while( pFrm && !pFrm->IsFlyFrm() );\n"
"\n"
" if( !pFrm )\n"
" return FALSE;\n"
"}");
ASSERT_EQUALS("", errout.str());
// Ticket #2463
check("struct A\n"
"{\n"
" B* W;\n"
"\n"
" void f() {\n"
" switch (InData) {\n"
" case 2:\n"
" if (!W) return;\n"
" W->foo();\n"
" break;\n"
" case 3:\n"
" f();\n"
" if (!W) return;\n"
" break;\n"
" }\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #2525 - sizeof
check("void f() {\n"
" int *test = NULL;\n"
" int c = sizeof(test[0]);\n"
" if (!test)\n"
" ;\n"
"}", true, "test.cpp", false);
ASSERT_EQUALS("", errout.str());
check("void f(type* p) {\n" // #4983
" x(sizeof p[0]);\n"
" if (!p)\n"
" ;\n"
"}", false, "test.cpp", false);
ASSERT_EQUALS("", errout.str());
// #3023 - checked deref
check("void f(struct ABC *abc) {\n"
" WARN_ON(!abc || abc->x == 0);\n"
" if (!abc) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(struct ABC *abc) {\n"
" WARN_ON(!abc || abc->x == 7);\n"
" if (!abc) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
// #3425 - false positives when there are macros
check("void f(int *p) {\n"
" *p = 0;\n"
" $if(!p){}\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f() {\n" // #3914 - false positive
" int *p;\n"
" ((p=ret()) && (x=*p));\n"
" if (p);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void nullpointer5() {
// errors..
check("void foo(A &a)\n"
"{\n"
" char c = a.c();\n"
" if (!a)\n"
" return;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
// Execution paths..
void nullpointerExecutionPaths() {
// errors..
check("static void foo()\n"
"{\n"
" Foo *p = 0;\n"
" if (a == 1) {\n"
" p = new FooBar;\n"
" } else { if (a == 2) {\n"
" p = new FooCar; } }\n"
" p->abcd();\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:8]: (error) Possible null pointer dereference: p\n",
"", errout.str());
check("static void foo() {\n"
" int &r = *0;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str());
check("static void foo(int x) {\n"
" int y = 5 + *0;\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str());
{
const char code[] = "static void foo() {\n"
" Foo *abc = 0;\n"
" abc->a();\n"
"}\n";
// inconclusive=false => no error
check(code,false);
ASSERT_EQUALS("", errout.str());
// inconclusive=true => error
check(code, true);
ASSERT_EQUALS("[test.cpp:3]: (error, inconclusive) Possible null pointer dereference: abc\n", errout.str());
}
check("static void foo() {\n"
" std::cout *0);\n"
"}");
ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str());
// no false positive..
check("static void foo()\n"
"{\n"
" Foo *p = 0;\n"
" p = new Foo;\n"
" p->abcd();\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void foo()\n"
"{\n"
" int sz = sizeof((*(struct dummy *)0).x);\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void get_offset(long &offset)\n"
"{\n"
" mystruct * temp; temp = 0;\n"
" offset = (long)(&(temp->z));\n"
"}");
ASSERT_EQUALS("", errout.str());
// Ticket #1893 - try/catch inside else
check("int *test(int *Z)\n"
"{\n"
" int *Q=NULL;\n"
" if (Z) {\n"
" Q = Z;\n"
" }\n"
" else {\n"
" Z = new int;\n"
" try {\n"
" } catch(...) {\n"
" }\n"
" Q = Z;\n"
" }\n"
" *Q=1;\n"
" return Q;\n"
"}");
ASSERT_EQUALS("", errout.str());
check("int *test(int *Z)\n"
"{\n"
" int *Q=NULL;\n"
" if (Z) {\n"
" Q = Z;\n"
" }\n"
" else {\n"
" try {\n"
" } catch(...) {\n"
" }\n"
" }\n"
" *Q=1;\n"
" return Q;\n"
"}");
ASSERT_EQUALS("[test.cpp:12]: (error) Possible null pointer dereference: Q\n", errout.str());
// Ticket #2052 (false positive for 'else continue;')
check("void f() {\n"
" for (int x = 0; x < 5; ++x) {"
" int *p = 0;\n"
" if (a(x)) p=b(x);\n"
" else continue;\n"
" *p = 0;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// function pointer..
check("void foo()\n"
"{\n"
" void (*f)();\n"
" f = 0;\n"
" f();\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Possible null pointer dereference: f\n", errout.str());
// loops..
check("void f() {\n"
" int *p = 0;\n"
" for (int i = 0; i < 10; ++i) {\n"
" int x = *p + 1;\n"
" }\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str());
check("void f(int a) {\n"
" const char *p = 0;\n"
" if (a) {\n"
" p = \"abcd\";\n"
" }\n"
" for (int i = 0; i < 3; i++) {\n"
" if (a && (p[i] == '1'));\n"
" }\n"
"}", true);
ASSERT_EQUALS("", errout.str());
// ticket #2251: taking the address of member
check("void f() {\n"
" Fred *fred = 0;\n"
" int x = &fred->x;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
// ticket #3220: calling member function
check("void f() {\n"
" Fred *fred = NULL;\n"
" fred->do_something();\n"
"}");
ASSERT_EQUALS("", errout.str());
// ticket #3570 - parsing of conditions
{
check("void f() {\n"
" int *p = NULL;\n"
" if (x)\n"
" p = q;\n"
" if (p && *p) { }\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" int *p = NULL;\n"
" if (x)\n"
" p = q;\n"
" if (!p || *p) { }\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("void f() {\n"
" int *p = NULL;\n"
" if (x)\n"
" p = q;\n"
" if (p || *p) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:5]: (warning) Possible null pointer dereference: p - otherwise it is redundant to check it against null.\n", errout.str());
}
}
// Ticket #2350
void nullpointerExecutionPathsLoop() {
// No false positive:
check("void foo() {\n"
" int n;\n"
" int *argv32 = p;\n"
" if (x) {\n"
" n = 0;\n"
" argv32 = 0;\n"
" }\n"
"\n"
" for (int i = 0; i < n; i++) {\n"
" argv32[i] = 0;\n"
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
// No false negative:
check("void foo() {\n"
" int n;\n"
" int *argv32;\n"
" if (x) {\n"
" n = 10;\n"
" argv32 = 0;\n"
" }\n"
"\n"
" for (int i = 0; i < n; i++) {\n"
" argv32[i] = 0;\n"
" }\n"
"}");
TODO_ASSERT_EQUALS("error",
"", errout.str());
// #2231 - error if assignment in loop is not used
check("void f() {\n"
" char *p = 0;\n"
"\n"
" for (int x = 0; x < 3; ++x) {\n"
" if (y[x] == 0) {\n"
" p = malloc(10);\n"
" break;\n"
" }\n"
" }\n"
"\n"
" *p = 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:11]: (error) Possible null pointer dereference: p\n", errout.str());
}
void nullpointer7() {
check("void foo()\n"
"{\n"
" wxLongLong x = 0;\n"
" int y = x.GetValue();\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer9() { //#ticket 1778
check("void foo()\n"
"{\n"
" std::string * x = 0;\n"
" *x = \"test\";\n"
"}", false, "test.cpp", false);
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: x\n"
"[test.cpp:4]: (error) Null pointer dereference\n", errout.str());
}
void nullpointer10() {
check("void foo()\n"
"{\n"
" struct my_type* p = 0;\n"
" p->x = 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str());
}
void nullpointer11() { // ticket #2812
check("int foo()\n"
"{\n"
" struct my_type* p;\n"
" p = 0;\n"
" return p->x;\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Possible null pointer dereference: p\n", errout.str());
}
void nullpointer12() { // ticket #2470, #4035
const char code[] = "int foo()\n"
"{\n"
" int* i = nullptr;\n"
" return *i;\n"
"}\n";
check(code, false, "test.cpp", false); // C++ file => nullptr means NULL
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: i\n"
"[test.cpp:4]: (error) Null pointer dereference\n", errout.str());
check(code, false, "test.c", false); // C file => nullptr does not mean NULL
ASSERT_EQUALS("", errout.str());
}
void nullpointer14() {
check("void foo()\n"
"{\n"
" strcpy(bar, 0);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Null pointer dereference\n", errout.str());
check("void foo()\n"
"{\n"
" memcmp(bar(xyz()), 0, 123);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Null pointer dereference\n", errout.str());
check("void foo(const char *s)\n"
"{\n"
" char *p = malloc(100);\n"
" frexp(1.0, p);\n"
" char *q = 0;\n"
" frexp(1.0, q);\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Possible null pointer dereference: q\n", errout.str());
}
void nullpointer15() { // #3560
check("void f() {\n"
" char *p = 0;\n"
" if (x) p = \"abcd\";\n"
" return p ? f(*p) : f(0);\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void nullpointer16() { // #3591
check("void foo() {\n"
" int *p = 0;\n"
" bar(&p);\n"
" *p = 0;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer17() { // #3567
check("int foo() {\n"
" int *p = 0;\n"
" if (x) { return 0; }\n"
" return !p || *p;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
check("int foo() {\n"
" int *p = 0;\n"
" if (x) { return 0; }\n"
" return p && *p;\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer18() { // #1927
check("void f ()\n"
"{\n"
" int i=0;\n"
" char *str=NULL;\n"
" while (str[i])\n"
" {\n"
" i++;\n"
" };\n"
"}\n", false, "test.cpp", false);
ASSERT_EQUALS("[test.cpp:5]: (error) Possible null pointer dereference: str\n"
"[test.cpp:5]: (error) Null pointer dereference\n", errout.str());
}
void nullpointer19() { // #3811
check("int foo() {\n"
" perror(0);\n"
"}", true);
ASSERT_EQUALS("", errout.str());
}
void nullpointer20() { // #3807
check("void f(int x) {\n"
" struct xy *p = 0;\n"
" if (x) p = q;\n"
" if (p ? p->x || p->y : 0) { }\n"
"}");
ASSERT_EQUALS("", errout.str());
check("void f(int x) {\n" // false negative
" struct xy *p = 0;\n"
" if (x) p = q;\n"
" if (y ? p->x : p->y) { }\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Possible null pointer dereference: p\n", errout.str());
}
void nullpointer21() { // #4038 - fp: if (x) p=q; else return;
check("void f(int x) {\n"
" int *p = 0;\n"
" if (x) p = q;\n"
" else return;\n"
" *p = 0;\n" //