FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

GitHub Viewer

/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2026 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 "check.h" #include "checknullpointer.h" #include "ctu.h" #include "errortypes.h" #include "fixture.h" #include "helpers.h" #include "library.h" #include "settings.h" #include "standards.h" #include "token.h" #include #include #include class TestNullPointer : public TestFixture { public: TestNullPointer() : TestFixture("TestNullPointer") {} private: const Settings settings = settingsBuilder().library("std.cfg").severity(Severity::warning).build(); const Settings settings_i = settingsBuilder(settings).certainty(Certainty::inconclusive).build(); void run() override { mNewTemplate = true; 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(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(nullpointer27); // #6568 TEST_CASE(nullpointer28); // #6491 TEST_CASE(nullpointer30); // #6392 TEST_CASE(nullpointer31); // #8482 TEST_CASE(nullpointer32); // #8460 TEST_CASE(nullpointer33); TEST_CASE(nullpointer34); TEST_CASE(nullpointer35); TEST_CASE(nullpointer36); // #9264 TEST_CASE(nullpointer37); // #9315 TEST_CASE(nullpointer38); TEST_CASE(nullpointer39); // #2153 TEST_CASE(nullpointer40); TEST_CASE(nullpointer41); TEST_CASE(nullpointer42); TEST_CASE(nullpointer43); // #9404 TEST_CASE(nullpointer44); // #9395, #9423 TEST_CASE(nullpointer45); TEST_CASE(nullpointer46); // #9441 TEST_CASE(nullpointer47); // #6850 TEST_CASE(nullpointer48); // #9196 TEST_CASE(nullpointer49); // #7804 TEST_CASE(nullpointer50); // #6462 TEST_CASE(nullpointer51); TEST_CASE(nullpointer52); TEST_CASE(nullpointer53); // #8005 TEST_CASE(nullpointer54); // #9573 TEST_CASE(nullpointer55); // #8144 TEST_CASE(nullpointer56); // #9701 TEST_CASE(nullpointer57); // #9751 TEST_CASE(nullpointer58); // #9807 TEST_CASE(nullpointer59); // #9897 TEST_CASE(nullpointer60); // #9842 TEST_CASE(nullpointer61); TEST_CASE(nullpointer62); TEST_CASE(nullpointer63); TEST_CASE(nullpointer64); TEST_CASE(nullpointer65); // #9980 TEST_CASE(nullpointer66); // #10024 TEST_CASE(nullpointer67); // #10062 TEST_CASE(nullpointer68); TEST_CASE(nullpointer69); // #8143 TEST_CASE(nullpointer70); TEST_CASE(nullpointer71); // #10178 TEST_CASE(nullpointer72); // #10215 TEST_CASE(nullpointer73); // #10321 TEST_CASE(nullpointer74); TEST_CASE(nullpointer75); TEST_CASE(nullpointer76); // #10408 TEST_CASE(nullpointer77); TEST_CASE(nullpointer78); // #7802 TEST_CASE(nullpointer79); // #10400 TEST_CASE(nullpointer80); // #10410 TEST_CASE(nullpointer81); // #8724 TEST_CASE(nullpointer82); // #10331 TEST_CASE(nullpointer83); // #9870 TEST_CASE(nullpointer84); // #9873 TEST_CASE(nullpointer85); // #10210 TEST_CASE(nullpointer86); TEST_CASE(nullpointer87); // #9291 TEST_CASE(nullpointer88); // #9949 TEST_CASE(nullpointer89); // #10640 TEST_CASE(nullpointer90); // #6098 TEST_CASE(nullpointer91); // #10678 TEST_CASE(nullpointer92); TEST_CASE(nullpointer93); // #3929 TEST_CASE(nullpointer94); // #11040 TEST_CASE(nullpointer95); // #11142 TEST_CASE(nullpointer96); // #11416 TEST_CASE(nullpointer97); // #11229 TEST_CASE(nullpointer98); // #11458 TEST_CASE(nullpointer99); // #10602 TEST_CASE(nullpointer100); // #11636 TEST_CASE(nullpointer101); // #11382 TEST_CASE(nullpointer102); TEST_CASE(nullpointer103); TEST_CASE(nullpointer104); // #13881 TEST_CASE(nullpointer105); // #13861 TEST_CASE(nullpointer106); // #13682 TEST_CASE(nullpointer107); // #13682 (FP/FN cases around guards that depend on the pointer indirectly) TEST_CASE(nullpointer108); TEST_CASE(nullpointer109); TEST_CASE(nullpointer110); // #14937 TEST_CASE(nullpointer_addressOf); // address of TEST_CASE(nullpointerSwitch); // #2626 TEST_CASE(nullpointer_cast); // #4692 TEST_CASE(nullpointer_castToVoid); // #3771 TEST_CASE(nullpointer_subfunction); 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_alignof); // #11401 TEST_CASE(nullpointer_in_for_loop); TEST_CASE(nullpointerDeadCode); // #11311 TEST_CASE(nullpointerDelete); TEST_CASE(nullpointerSubFunction); TEST_CASE(nullpointerExit); TEST_CASE(nullpointerStdString); TEST_CASE(nullpointerStdStream); TEST_CASE(nullpointerSmartPointer); TEST_CASE(nullpointerOutOfMemory); TEST_CASE(nullpointerOutOfResources); TEST_CASE(functioncall); TEST_CASE(functioncalllibrary); // use Library to parse function call TEST_CASE(functioncallDefaultArguments); TEST_CASE(nullpointer_internal_error); // #5080 TEST_CASE(ticket6505); TEST_CASE(subtract); TEST_CASE(addNull); TEST_CASE(isPointerDeRefFunctionDecl); TEST_CASE(ctuTest); } struct CheckOptions { bool inconclusive = false; bool cpp = true; }; #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) template void check_(const char* file, int line, const char (&code)[size], const CheckOptions& options = make_default_obj()) { const Settings& settings1 = options.inconclusive ? settings_i : settings; check_(file, line, code, settings1, options.cpp); } template void check_(const char* file, int line, const char (&code)[size], const Settings& s, bool cpp = true) { // Tokenize.. SimpleTokenizer tokenizer(s, *this, cpp); ASSERT_LOC(tokenizer.tokenize(code), file, line); CheckNullPointer check; runChecks(check, tokenizer, *this); } #define checkP(...) checkP_(__FILE__, __LINE__, __VA_ARGS__) template void checkP_(const char* file, int line, const char (&code)[size]) { SimpleTokenizer2 tokenizer(settings, *this, code, "test.cpp"); // Tokenizer.. ASSERT_LOC(tokenizer.simplifyTokens1(""), file, line); CheckNullPointer check; runChecks(check, tokenizer, *this); } void nullpointerAfterLoop() { // extracttests.start: struct Token { const Token *next() const; std::string str() const; }; check("void foo(const Token *tok)\n" "{\n" " while (tok);\n" " tok = tok->next();\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:4:11]: (warning) Either the condition 'tok' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\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); ASSERT_EQUALS("[test.cpp:3:12] -> [test.cpp:6:9]: (warning) Either the condition 'tok' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\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" "}"); TODO_ASSERT_EQUALS("[test.cpp:5] -> [test.cpp:3]: (warning) Either the condition 'while' is redundant or there is possible null pointer dereference: tok.\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" "}"); ASSERT_EQUALS("[test.cpp:3:16] -> [test.cpp:5:5]: (warning) Either the condition 'tok' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\n", errout_str()); check("int foo(const Token *tok)\n" "{\n" " while (tok){;}\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo(const Token *tok)\n" "{\n" " while (tok){;}\n" " char a[2] = {0,0};\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct b {\n" " b * c;\n" " int i;\n" "}\n" "void a(b * e) {\n" " for (b *d = e;d; d = d->c)\n" " while (d && d->i == 0)\n" " d = d->c;\n" " if (!d) throw;\n" "}"); ASSERT_EQUALS("", errout_str()); check("struct b {\n" " b * c;\n" " int i;\n" "};\n" "void f(b* e1, b* e2) {\n" " for (const b* d = e1; d != e2; d = d->c) {\n" " if (d && d->i != 0) {}\n" " }\n" "}\n"); ASSERT_EQUALS("[test.cpp:7:13] -> [test.cpp:6:40]: (warning) Either the condition 'd' is redundant or there is possible null pointer dereference: d. [nullPointerRedundantCheck]\n", 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" "}"); 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" "}", dinit(CheckOptions, $.inconclusive = true)); 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" "}", dinit(CheckOptions, $.inconclusive = 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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } // Dereferencing a struct and then checking if it is null // This is checked by this function: // CheckOther::nullPointerStructByDeRefAndCheck void structDerefAndCheck() { // extracttests.start: struct ABC { int a; int b; int x; }; // errors.. check("void foo(struct ABC *abc)\n" "{\n" " int a = abc->a;\n" " if (!abc)\n" " ;\n" "}"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:13]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\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:5:9] -> [test.cpp:2:9]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n" "[test.cpp:5:9] -> [test.cpp:3:12]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n" "[test.cpp:5:9] -> [test.cpp:4:15]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(ABC *abc) {\n" " if (abc->a == 3) {\n" " return;\n" " }\n" " if (abc) {}\n" "}"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:2:9]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); check("void f(ABC *abc) {\n" " if (abc->x == 0) {\n" " return;\n" " }\n" " if (!abc);\n" "}"); ASSERT_EQUALS("[test.cpp:5:9] -> [test.cpp:2:9]: (warning) Either the condition '!abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\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:3] -> [test.cpp:2]: (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:3:9] -> [test.cpp:2:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(struct ABC *abc) {\n" " abc = (ABC *)(abc->_next);\n" " if (abc) { }" "}", dinit(CheckOptions, $.inconclusive = true)); 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" "}", dinit(CheckOptions, $.inconclusive = 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" "}", dinit(CheckOptions, $.inconclusive = 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" "}"); 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" "}"); 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 = abc1;\n" " abc->a = 0;\n" " do_stuff();\n" " if (abc) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:3:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\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:4:9] -> [test.cpp:2:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\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( "[test.cpp:3:9] -> [test.cpp:2:5]: (warning) Either the condition 'fred' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", errout_str()); } // #3425 - false positives when there are macros checkP("#define IF if\n" "void f(struct FRED *fred) {\n" " fred->x = 0;\n" " IF(!fred){}\n" "}"); ASSERT_EQUALS("", errout_str()); check("void foo() {\n" " BUFFER *buffer = get_buffer();\n" " if (!buffer)\n" " uv_fatal_error();\n" " buffer->x = 11;\n" "}"); ASSERT_EQUALS("", errout_str()); } // Dereferencing a pointer and then checking if it is null void pointerDerefAndCheck() { // extracttests.start: void bar(int); // errors.. check("void foo(int *p)\n" "{\n" " *p = 0;\n" " if (!p)\n" " ;\n" "}"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(int *p)\n" "{\n" " *p = 0;\n" " if (p) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(int *p)\n" "{\n" " *p = 0;\n" " if (p || q) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(int *p)\n" "{\n" " bar(*p);\n" " if (!p)\n" " ;\n" "}"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:10]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p)\n" "{\n" " strcpy(p, \"abc\");\n" " if (!p)\n" " ;\n" "}"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:12]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p)\n" "{\n" " if (*p == 0) { }\n" " if (!p) { }\n" "}"); ASSERT_EQUALS("[test.cpp:4:9] -> [test.cpp:3:10]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\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" "}", dinit(CheckOptions, $.inconclusive = 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" "}", dinit(CheckOptions, $.inconclusive = 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, bool x)\n" "{\n" " int var1 = x ? *p : 5;\n" " if (!p)\n" " ;\n" "}"); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:3:21]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\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:3:12] -> [test.cpp:2:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\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",dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #3686 check("void f() {\n" " int * a=0;\n" " if (!a) {};\n" " int c = a ? b : b+1;\n" "}\n",dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int * a=0;\n" " if (!a) {};\n" " int c = (a) ? b : b+1;\n" "}\n",dinit(CheckOptions, $.inconclusive = true)); 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:4:9] -> [test.cpp:2:5]: (warning) Either the condition 'item' is redundant or there is possible null pointer dereference: item. [nullPointerRedundantCheck]\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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(type* p) {\n" // #4983 " x(sizeof p[0]);\n" " if (!p)\n" " ;\n" "}"); 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 checkP("#define IF if\n" "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()); check("struct S { struct T { char c; } *p; };\n" // #6541 "char f(S* s) { return s->p ? 'a' : s->p->c; }\n"); ASSERT_EQUALS("[test.cpp:2:24] -> [test.cpp:2:37]: (warning) Either the condition 's->p' is redundant or there is possible null pointer dereference: s->p. [nullPointerRedundantCheck]\n", errout_str()); check("int f(const int a[]) {\n" // #14544 " int i = 0;\n" " if (!a)\n" " a = &i;\n" " return *a;\n" "}\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 = *(int*)0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:15]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); check("static void foo(int x) {\n" " int y = 5 + *(int*)0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:18]: (error) Null pointer dereference: (int*)0 [nullPointer]\n", errout_str()); { const char code[] = "static void foo() {\n" " Foo *abc = 0;\n" " abc->a();\n" "}\n"; check(code); ASSERT_EQUALS("[test.cpp:3:5]: (error) Null pointer dereference: abc [nullPointer]\n", errout_str()); } check("static void foo() {\n" " std::cout *(int*)0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:14]: (error) Null pointer dereference: (int*)0 [nullPointer]\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:6]: (warning) Possible null pointer dereference: Q [nullPointer]\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:5]: (error) Null pointer dereference: f [nullPointer]\n", errout_str()); check("int* g();\n" // #11007 "int* f() {\n" " static int* (*fun)() = 0;\n" " if (!fun)\n" " fun = g;\n" " return fun();\n" "}\n"); ASSERT_EQUALS("", 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:18]: (error) Null pointer dereference: p [nullPointer]\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" "}", dinit(CheckOptions, $.inconclusive = 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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // ticket #3220: dereferencing a null pointer is UB check("void f() {\n" " Fred *fred = NULL;\n" " fred->do_something();\n" "}"); ASSERT_EQUALS("[test.cpp:3:5]: (error) Null pointer dereference: fred [nullPointer]\n", 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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " int *p = NULL;\n" " if (x)\n" " p = q;\n" " if (!p || *p) { }\n" "}", dinit(CheckOptions, $.inconclusive = 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:15]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } // ticket #8831 - FP triggered by if/return/else sequence { check("void f(int *p, int *q) {\n" " if (p == NULL)\n" " return;\n" " else if (q == NULL)\n" " return;\n" " *q = 0;\n" "}\n" "\n" "void g() {\n" " f(NULL, NULL);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } check("void f() {\n" // #5979 " int* const crash = 0;\n" " *crash = 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:6]: (error) Null pointer dereference: crash [nullPointer]\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" "}"); ASSERT_EQUALS("[test.cpp:10:9]: (warning) Possible null pointer dereference: argv32 [nullPointer]\n", errout_str()); // #2231 - error if assignment in loop is not used // extracttests.start: int y[20]; check("void f() {\n" " char *p = 0;\n" "\n" " for (int x = 0; x < 3; ++x) {\n" " if (y[x] == 0) {\n" " p = (char *)malloc(10);\n" " break;\n" " }\n" " }\n" "\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:11:6]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } void nullpointer7() { check("void foo()\n" "{\n" " wxLongLong x = 0;\n" " int y = x.GetValue();\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer9() { //#ticket 1778 check("void foo()\n" "{\n" " std::string * x = 0;\n" " *x = \"test\";\n" "}"); ASSERT_EQUALS("[test.cpp:4:4]: (error) Null pointer dereference: x [nullPointer]\n", errout_str()); } void nullpointer10() { // extracttests.start: struct my_type { int x; }; check("void foo()\n" "{\n" " struct my_type* p = 0;\n" " p->x = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:4:3]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); } void nullpointer11() { // ticket #2812 // extracttests.start: struct my_type { int x; }; check("int foo()\n" "{\n" " struct my_type* p;\n" " p = 0;\n" " return p->x;\n" "}"); ASSERT_EQUALS("[test.cpp:5:10]: (error) Null pointer dereference: p [nullPointer]\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); // C++ file => nullptr means NULL ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: i [nullPointer]\n", errout_str()); const Settings s = settingsBuilder(settings).c(Standards::C17).build(); check(code, s, false); // C17 file => nullptr does not mean NULL ASSERT_EQUALS("", errout_str()); check(code, dinit(CheckOptions, $.cpp = false)); ASSERT_EQUALS("[test.c:4:11]: (error) Null pointer dereference: i [nullPointer]\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" "}", dinit(CheckOptions, $.inconclusive = 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" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo() {\n" " int *p = 0;\n" " if (x) { return 0; }\n" " return p && *p;\n" "}", dinit(CheckOptions, $.inconclusive = 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" "}"); ASSERT_EQUALS("[test.cpp:5:10]: (error) Null pointer dereference: str [nullPointer]\n", errout_str()); } void nullpointer19() { // #3811 check("int foo() {\n" " perror(0);\n" "}", dinit(CheckOptions, $.inconclusive = 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:13]: (warning) Possible null pointer dereference: p [nullPointer]\n" "[test.cpp:4:20]: (warning) Possible null pointer dereference: p [nullPointer]\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" // no FP check("struct S { void g(); bool f() const; };\n" "void f(S* p) {\n" " bool ok = (p != nullptr);\n" " if (p && p->f())\n" " return;\n" " if (!ok)\n" " return;\n" " p->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); // unrelated bool guard -> conservative, no FP check("struct S { void g(); bool f() const; };\n" "void f(S* p, bool valid) {\n" " S* p1 = p;\n" " if (p1 && p1->f())\n" " return;\n" " if (!valid)\n" " return;\n" " p1->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); // guard on a different pointer -> no FP check("struct S { void g(); bool f() const; };\n" "void f(S* p, S* q) {\n" " S* p1 = p;\n" " if (p1 && p1->f())\n" " return;\n" " if (!q)\n" " return;\n" " p1->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); // direct null guard on the alias -> no FP check("struct S { void g(); bool f() const; };\n" "void f(S* p) {\n" " S* p1 = p;\n" " if (p1 && p1->f())\n" " return;\n" " if (!p)\n" " return;\n" " p1->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); // FN: 'if (ok)' => survivor has p==nullptr, but the cached 'ok' is not followed -> should warn check("struct S { void g(); bool f() const; };\n" "void f(S* p) {\n" " bool ok = (p != nullptr);\n" " if (p && p->f())\n" " return;\n" " if (ok)\n" " return;\n" " p->g();\n" "}\n"); TODO_ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:8:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", "", errout_str()); // FN: sink(q) drops the q==p symbolic, so guard 'if (q)' is no longer seen to relate to p -> should warn check("struct S { void g(); bool f() const; };\n" "void sink(S*&);\n" "void f(S* p) {\n" " S* q = p;\n" " if (p && p->f())\n" " return;\n" " sink(q);\n" " if (q)\n" " return;\n" " p->g();\n" "}\n"); TODO_ASSERT_EQUALS( "[test.cpp:5:9] -> [test.cpp:10:5]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", "", errout_str()); // a conditional modification makes ProgramMemory drop the guard (FP-prone) -> must stay quiet: // alias 'q==p' re-assigned to p under a condition check("struct S { void g(); bool f() const; };\n" "void f(S* p, bool c) {\n" " S* q = p;\n" " if (p && p->f())\n" " return;\n" " if (c)\n" " q = p;\n" " if (!q)\n" " return;\n" " p->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); // cached 'ok' refreshed under a condition check("struct S { void g(); bool f() const; };\n" "void f(S* p, bool c) {\n" " bool ok = (p != nullptr);\n" " if (p && p->f())\n" " return;\n" " if (c)\n" " ok = (p != nullptr);\n" " if (!ok)\n" " return;\n" " p->g();\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void nullpointer108() { // #14422 check("void f() {\n" " int *p{};\n" " int *&r{p};\n" " if (*r) {}\n" "}"); ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference: r [nullPointer]\n", errout_str()); } void nullpointer109() { check("boost::asio::awaitable test()\n" "{\n" " const auto *s = getStr();\n" " if(!s) co_return int{1};\n" " std::print(\"{}\",*s);\n" " co_return int{9};\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void nullpointer110() { // #14937 - noreturn member function called on operator() result check("struct A {\n" " [[noreturn]] void g(int);\n" "};\n" "template\n" "struct Thunk {\n" " T& operator()() const;\n" "};\n" "void f(Thunk thunk, int* p) {\n" " if (!p)\n" " thunk().g(0);\n" " *p = 1;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer_addressOf() { // address of check("void f() {\n" " struct X *x = 0;\n" " if (addr == &x->y) {}\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " struct X *x = 0;\n" " if (addr == &x->y.z[0]) {}\n" "}"); ASSERT_EQUALS("", errout_str()); checkP("typedef int Count;\n" // #10018 "#define offsetof(TYPE, MEMBER) ((Count) & ((TYPE*)0)->MEMBER)\n" "struct S {\n" " int a[20];\n" "};\n" "int g(int i) {\n" " return offsetof(S, a[i]);\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void nullpointerSwitch() { // #2626 // extracttests.start: char *do_something(); check("char *f(int x) {\n" " char *p = do_something();\n" " switch (x) {\n" " case 1:\n" " p = 0;\n" " case 2:\n" " *p = 0;\n" " break;\n" " }\n" " return p;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:7:10]: (warning) Possible null pointer dereference: p [nullPointer]\n", errout_str()); } void nullpointer_cast() { check("char *nasm_skip_spaces(const char *p) {\n" // #4692 " if (p)\n" " while (*p && nasm_isspace(*p))\n" " p++;\n" " return p;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(char* origin) {\n" // #11449 " char* cp = (strchr)(origin, '\\0');\n" " if (cp[-1] != '/')\n" " *cp++ = '/';\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void nullpointer_castToVoid() { // #3771 check("void f () {\n" " int *buf; buf = NULL;\n" " buf;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer_subfunction() { check("int f(int* x, int* y) {\n" " if (!x)\n" " return;\n" " return *x + *y;\n" "}\n" "void g() {\n" " f(nullptr, nullptr);\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } // Check if pointer is null and the dereference it void pointerCheckAndDeRef() { check("void foo(char *p) {\n" " if (!p) {\n" " }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p && *p == 0) {\n" " }\n" " printf(\"%c\", *p);\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:19]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p && *p == 0) {\n" " } else { *p = 0; }\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:15]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p) {\n" " }\n" " strcpy(p, \"abc\");\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:4:12]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(char *p) {\n" " if (p) {\n" " }\n" " bar();\n" " strcpy(p, \"abc\");\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:5:12]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void foo(abc *p) {\n" " if (!p) {\n" " }\n" " else { if (!p->x) {\n" " } }\n" "}"); ASSERT_EQUALS("", errout_str()); { static const char code[] = "void foo(char *p) {\n" " if (!p) {\n" " abort();\n" " }\n" " *p = 0;\n" "}"; check(code); ASSERT_EQUALS("", errout_str()); check(code, dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } check("void foo(char *p) {\n" " if (!p) {\n" " (*bail)();\n" " }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " throw x;\n" " }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " ab.abort();\n" " }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " switch (x) { }\n" " }\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(char *p) {\n" " if (!p) {\n" " }\n" " return *x;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo(int *p) {\n" " if (!p) {\n" " x = *p;\n" " return 5+*p;\n" " }\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:14]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" "[test.cpp:2:9] -> [test.cpp:4:19]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // operator! check("void f() {\n" " A a;\n" " if (!a) {\n" " a.x();\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // This is why this check can't be used on the simplified token list check("void f(Foo *foo) {\n" " if (!dynamic_cast(foo)) {\n" " *foo = 0;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // ticket: #2300 - calling unknown function that may initialize the pointer check("Fred *fred;\n" "void a() {\n" " if (!fred) {\n" " initfred();\n" " fred->x = 0;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // ticket #1219 check("void foo(char *p) {\n" " if (p) {\n" " return;\n" " }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:5:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // #2467 - unknown macro may terminate the application check("void f(Fred *fred) {\n" " if (fred == NULL) {\n" " MACRO;\n" " }\n" " fred->a();\n" "}"); ASSERT_EQUALS("", errout_str()); // #2493 - switch check("void f(Fred *fred) {\n" " if (fred == NULL) {\n" " x = 0;\n" " }\n" " switch (x) {\n" " case 1:\n" " fred->a();\n" " break;\n" " };\n" "}"); ASSERT_EQUALS("", errout_str()); // #4118 - second if check("void f(char *p) {\n" " int x = 1;\n" " if (!p) x = 0;\n" " if (x) *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); // #2674 - different functions check("class Fred {\n" "public:\n" " Wilma *wilma;\n" " void a();\n" " void b();\n" "};\n" "\n" "void Fred::a() {\n" " if ( wilma ) { }\n" "}\n" "\n" "void Fred::b() {\n" " wilma->Reload();\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void test(int *i) {\n" " if(i == NULL) { }\n" " else {\n" " int b = *i;\n" " }\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 1 check("void f()\n" "{\n" " struct foo *pFoo = NULL;\n" " size_t len;\n" "\n" " len = sizeof(*pFoo) - sizeof(pFoo->data);\n" "\n" " if (pFoo)\n" " bar();\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 2 check("void f()\n" "{\n" " struct foo *pFoo = NULL;\n" " size_t len;\n" "\n" " while (pFoo)\n" " pFoo = pFoo->next;\n" "\n" " len = sizeof(pFoo->data);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #2696 - false positives nr 3 check("void f()\n" "{\n" " struct foo *pFoo = NULL;\n" " size_t len;\n" "\n" " while (pFoo)\n" " pFoo = pFoo->next;\n" "\n" " len = decltype(*pFoo);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int foo(struct Fred *fred) {\n" " if (fred) { }\n" " return fred->a;\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:12]: (warning) Either the condition 'fred' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", errout_str()); // #2789 - assign and check pointer check("void f() {\n" " char *p; p = x();\n" " if (!p) { }\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:4:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, assign and use check("void f() {\n" " char *p;\n" " if (p == 0 && (p = malloc(10)) != 0) {\n" " *p = 0;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // check, assign and use check("void f() {\n" " char *p;\n" " if (p == 0 && (p = malloc(10)) != a && (*p = a)) {\n" " *p = 0;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // check, and use check("void f() {\n" " char *p;\n" " if (p == 0 && (*p = 0)) {\n" " return;\n" " }\n" "}"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:21]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use check("void f() {\n" " struct foo *p;\n" " if (p == 0 && p->x == 10) {\n" " return;\n" " }\n" "}"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:19]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use check("void f() {\n" " struct foo *p;\n" " if (p == 0 || p->x == 10) {\n" " return;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); // check, and use check("void f() {\n" " char *p; p = malloc(10);\n" " if (p == NULL && (*p = a)) {\n" " return;\n" " }\n" "}"); ASSERT_EQUALS("[test.cpp:3:11] -> [test.cpp:3:24]: (warning) Either the condition 'p==NULL' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // check, and use check("void f(struct X *p, int x) {\n" " if (!p && x==1 || p && p->x==0) {\n" " return;\n" " }\n" "}"); ASSERT_EQUALS("", errout_str()); { const char code[] = "void f(Fred *fred) {\n" " if (fred == NULL) { }\n" " fred->x();\n" "}"; check(code); // inconclusive ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:3:5]: (warning) Either the condition 'fred==NULL' is redundant or there is possible null pointer dereference: fred. [nullPointerRedundantCheck]\n", errout_str()); } check("void f(char *s) {\n" // #3358 " if (s==0);\n" " strcpy(a, s?b:c);\n" "}"); ASSERT_EQUALS("", errout_str()); // sizeof check("void f(struct fred_t *fred) {\n" " if (!fred)\n" " int sz = sizeof(fred->x);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // check in macro check("void f(int *x) {\n" " $if (!x) {}\n" " *x = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); // return ?: check("int f(ABC *p) {\n" // FP : return ?: " if (!p) {}\n" " return p ? p->x : 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("int f(ABC *p) {\n" // no fn " if (!p) {}\n" " return q ? p->x : 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:9] -> [test.cpp:3:16]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("int f(ABC *p) {\n" // FP : return && " if (!p) {}\n" " return p && p->x;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int x, int *p) {\n" " if (x || !p) {}\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:14] -> [test.cpp:3:6]: (warning) Either the condition '!p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // sizeof check("void f() {\n" " int *pointer = NULL;\n" " pointer = func(sizeof pointer[0]);\n" "}"); ASSERT_EQUALS("", errout_str()); check("struct T {\n" // #14164 " T* next;\n" " char op;\n" "};\n" "void h(int, char);\n" "void g(const T* tok, bool b) {\n" " if (tok->op == '') {}\n" " }\n" " h(b ? 1 : 0, tok->op);\n" "}\n"); ASSERT_EQUALS("[test.cpp:8:21] -> [test.cpp:10:18]: (warning) Either the condition 'tok=tok->next' is redundant or there is possible null pointer dereference: tok. [nullPointerRedundantCheck]\n", errout_str()); } // Test CheckNullPointer::nullConstantDereference void nullConstantDereference() { check("int f() {\n" " int* p = 0;\n" " return p[4];\n" "}"); ASSERT_EQUALS("[test.cpp:3:12]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("void f() {\n" " typeof(*NULL) y;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("int * f() {\n" " return NULL;\n" "}\n" "int main() {\n" " return *f();\n" "}"); ASSERT_EQUALS("[test.cpp:5:12]: (error) Null pointer dereference: f() [nullPointer]\n", errout_str()); } void gcc_statement_expression() { // Ticket #2621 check("void f(struct ABC *abc) {\n" " ({ if (abc) dbg(); })\n" "}"); ASSERT_EQUALS("", errout_str()); } void snprintf_with_zero_size() { // Ticket #2840 check("void f() {\n" " int bytes = snprintf(0, 0, \"%u\", 1);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void snprintf_with_non_zero_size() { // Ticket #2840 check("void f() {\n" " int bytes = snprintf(0, 10, \"%u\", 1);\n" "}"); ASSERT_EQUALS("[test.cpp:2:26]: (error) Null pointer dereference [nullPointer]\n", errout_str()); } void printf_with_invalid_va_argument() { check("void f() {\n" " printf(\"%s\", 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:18]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"%s\", s);\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char* s = 0;\n" " printf(\"%s\", s);\n" "}"); ASSERT_EQUALS( "[test.cpp:3:18]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); check("void f() {\n" " char *s = 0;\n" " printf(\"%s\", s == 0 ? a : s);\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " printf(\"%u%s\", 0, 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:23]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"%u%s\", 0, s);\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " char* s = 0;\n" " printf(\"%u%s\", 123, s);\n" "}"); ASSERT_EQUALS( "[test.cpp:3:25]: (error) Null pointer dereference: s [nullPointer]\n", errout_str()); check("void f() {\n" " printf(\"%%%s%%\", 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:22]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"text: %s, %s\", s, 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:31]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " char* s = \"blabla\";\n" " printf(\"%s\", s);\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(char* s) {\n" " printf(\"text: %m%s, %s\", s, 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:33]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* s) {\n" " printf(\"text: %*s, %s\", s, 0);\n" "}"); ASSERT_EQUALS("[test.cpp:2:32]: (error) Null pointer dereference [nullPointer]\n", errout_str()); // Ticket #3364 check("void f() {\n" " printf(\"%-*.*s\", s, 0);\n" " sprintf(\"%*\", s);\n" "}"); ASSERT_EQUALS("", errout_str()); } void scanf_with_invalid_va_argument() { check("void f(char* s) {\n" " sscanf(s, \"%s\", 0);\n" "}"); ASSERT_EQUALS( "[test.cpp:2:21]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " scanf(\"%d\", 0);\n" "}"); ASSERT_EQUALS( "[test.cpp:2:17]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f(char* foo) {\n" " char location[200];\n" " int width, height;\n" " sscanf(imgInfo, \"%s %d %d\", location, &width, &height);\n" "}"); ASSERT_EQUALS("", errout_str()); // ticket #3207 check("void f(char *dummy) {\n" " int iVal;\n" " sscanf(dummy, \"%d%c\", &iVal);\n" "}"); ASSERT_EQUALS("", errout_str()); // ticket #3211 check("void f(char *dummy) {\n" " int* iVal = 0;\n" " sscanf(dummy, \"%d\", iVal);\n" "}"); ASSERT_EQUALS( "[test.cpp:3:25]: (error) Null pointer dereference: iVal [nullPointer]\n", errout_str()); check("void f(char *dummy) {\n" " int* iVal;\n" " sscanf(dummy, \"%d\", foo(iVal));\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(char *dummy) {\n" " int* iVal = 0;\n" " sscanf(dummy, \"%d%d\", foo(iVal), iVal);\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(char* dummy) {\n" " sscanf(dummy, \"%*d%u\", 0);\n" "}"); ASSERT_EQUALS( "[test.cpp:2:28]: (error) Null pointer dereference [nullPointer]\n", errout_str()); } void nullpointer_in_return() { // extracttests.start: int maybe(); int *g(); check("int foo() {\n" " int* iVal = 0;\n" " if(maybe()) iVal = g();\n" " return iVal[0];\n" "}"); ASSERT_EQUALS("[test.cpp:4:12]: (warning) Possible null pointer dereference: iVal [nullPointer]\n", errout_str()); check("int foo(int* iVal) {\n" " return iVal[0];\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer_in_typeid() { // Should throw std::bad_typeid check("struct PolymorphicA { virtual ~A() {} };\n" "bool foo() {\n" " PolymorphicA* a = 0;\n" " return typeid(*a) == typeid(*a);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("struct NonPolymorphicA { ~A() {} };\n" "bool foo() {\n" " NonPolymorphicA* a = 0;\n" " return typeid(*a) == typeid(*a);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("bool foo() {\n" " char* c = 0;\n" " return typeid(*c) == typeid(*c);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer_in_alignof() // #11401 { check("size_t foo() {\n" " char* c = 0;\n" " return alignof(*c);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return alignof(*0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void foo(int *p) {\n" " f(alignof(*p));\n" " if (p) {}\n" " return;\n" "}"); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " char* c = 0;\n" " return _Alignof(*c);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return _alignof(*0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return __alignof(*0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("size_t foo() {\n" " return __alignof__(*0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointer_in_for_loop() { // Ticket #3278 check("void f(int* ptr, int cnt){\n" " if (!ptr)\n" " cnt = 0;\n" " for (int i = 0; i < cnt; ++i)\n" " *ptr++ = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); // #11635 check("void f(char *cons, int rlen, int pos) {\n" " int i;\n" " char* cp1;\n" " for (cp1 = &cons[pos], i = 1; i < rlen; cp1--)\n" " if (*cp1 == '*')\n" " continue;\n" " else\n" " i++;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check("void f(const int* p) {\n" // #6710 " for (int i = *p; i < 5; ++i) {}\n" " if (p) {}\n" "}\n" "struct S { int a; };\n" "void g(const S* s) {\n" " for (int i = s->a; i < 5; ++i) {}\n" " if (s) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:9] -> [test.cpp:2:19]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n" "[test.cpp:8:9] -> [test.cpp:7:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", errout_str()); check("struct S { int a; };\n" // #6492 "void h(const S* s) {\n" " for (int i = s->a; s; ++i) {}\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:24] -> [test.cpp:3:18]: (warning) Either the condition 's' is redundant or there is possible null pointer dereference: s. [nullPointerRedundantCheck]\n", errout_str()); } void nullpointerDeadCode() { // Ticket #11311 check ("void f() {\n" " if (0)\n" " *(int *)0 = 1;\n" " else\n" " ;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check ("void f() {\n" " if (0)\n" " *(int *)0 = 1;\n" " else {\n" " if (0)\n" " *(int *)0 = 2;\n" " else\n" " ;\n" " }\n" "}\n"); ASSERT_EQUALS("", errout_str()); check ("void f() {\n" " while(0)\n" " *(int*)0 = 1;\n" " do {\n" " } while(0);\n" "}\n"); ASSERT_EQUALS("", errout_str()); check ("int f() {\n" " return 0 ? *(int*)0 = 1 : 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check ("int f() {\n" " return 1 ? 1 : *(int*)0 = 1;\n" "}\n"); ASSERT_EQUALS("", errout_str()); check ("struct S {\n" // #13220 " explicit S(int* p) : i(*p) {\n" " if (p) {}\n" " }\n" " int i;\n" "};\n"); ASSERT_EQUALS("[test.cpp:3:13] -> [test.cpp:2:29]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); } void nullpointerDelete() { check("void f() {\n" " K *k = getK();\n" " if (k)\n" " k->doStuff();\n" " delete k;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " K *k = getK();\n" " if (k)\n" " k[0] = ptr;\n" " delete [] k;\n" " k = new K[10];\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointerSubFunction() { check("void g(int* x) { *x; }\n" "void f(int* x) {\n" " if (x)\n" " g(x);\n" "}"); ASSERT_EQUALS("", errout_str()); check("struct T {\n" // #14308 " bool b{};\n" " T* next{};\n" "};\n" "bool g(const T*& r) {\n" " const T* t = r;\n" " r = t->next;\n" " return t->b;\n" "}\n" "void f(const T* tok) {\n" " if (g(tok)) {}\n" " if (tok) {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); } void nullpointerExit() { check("void f() {\n" " K *k = getK();\n" " if (!k)\n" " exit(1);\n" " k->f();\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointerStdString() { check("void f(std::string s1) {\n" " void* p = 0;\n" " s1 = 0;\n" " s1 = '\\0';\n" " std::string s2 = 0;\n" " std::string s2 = '\\0';\n" " std::string s3(0);\n" " foo(std::string(0));\n" " s1 = p;\n" " std::string s4 = p;\n" " std::string s5(p);\n" " foo(std::string(p));\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:9:10]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:10:22]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:11:20]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:12:21]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:3:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:5:22]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:7:17]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:8:9]: (error) Null pointer dereference [nullPointer]\n" , errout_str()); check("void f(std::string s1) {\n" " s1 = nullptr;\n" " std::string s2 = nullptr;\n" " std::string s3(nullptr);\n" " foo(std::string(nullptr));\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:3:22]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:4:17]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:5:9]: (error) Null pointer dereference [nullPointer]\n" , errout_str()); check("void f(std::string s1) {\n" " s1 = NULL;\n" " std::string s2 = NULL;\n" " std::string s3(NULL);\n" " foo(std::string(NULL));\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:2:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:3:22]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:4:17]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:5:9]: (error) Null pointer dereference [nullPointer]\n" , errout_str()); check("void f(std::string s1, const std::string& s2, const std::string* s3) {\n" " void* p = 0;\n" " if (x) { return; }\n" " foo(s1 == p);\n" " foo(s2 == p);\n" " foo(s3 == p);\n" " foo(p == s1);\n" " foo(p == s2);\n" " foo(p == s3);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:4:15]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:5:15]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:7:9]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:8:9]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("void f(std::string s1, const std::string& s2, const std::string* s3) {\n" " void* p = 0;\n" " if (x) { return; }\n" " foo(0 == s1.size());\n" " foo(0 == s2.size());\n" " foo(0 == s3->size());\n" " foo(s1.size() == 0);\n" " foo(s2.size() == 0);\n" " foo(s3->size() == 0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(std::string s1, const std::string& s2) {\n" " if (x) { return; }\n" " foo(0 == s1[0]);\n" " foo(0 == s2[0]);\n" " foo(s1[0] == 0);\n" " foo(s2[0] == 0);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(std::string s1, const std::string& s2) {\n" " if (x) { return; }\n" " foo(s1 == '\\0');\n" " foo(s2 == '\\0');\n" " foo('\\0' == s1);\n" " foo('\\0' == s2);\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("class Bar {\n" " std::string s;\n" " Bar() : s(0) {}\n" "};\n" "class Foo {\n" " std::string s;\n" " Foo();\n" "};\n" "Foo::Foo() : s(0) {}"); ASSERT_EQUALS("[test.cpp:3:13]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:9:14]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("void f() {\n" " std::string s = 0 == x ? \"a\" : \"b\";\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f() {\n" " const std::string s = g();\n" " ASSERT_MESSAGE(\"Error on s\", 0 == s.compare(\"Some text\"));\n" "}"); ASSERT_EQUALS("", errout_str()); check("void foo(int i, std::string s);\n" "void bar() {\n" " foo(0, \"\");\n" " foo(0, 0);\n" " foo(var, 0);\n" " foo(var, NULL);\n" " foo(var, nullptr);\n" " foo(0, var);\n" "}"); ASSERT_EQUALS("[test.cpp:4:10]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:5:12]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:6:12]: (error) Null pointer dereference [nullPointer]\n" "[test.cpp:7:12]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("std::string f() {\n" // #9827 " char* p = NULL;\n" " int r = g(p);\n" " if (!r)\n" " return \"\";\n" " std::string s(p);\n" " return s;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:6:17]: (warning, inconclusive) Possible null pointer dereference: p [nullPointer]\n", errout_str()); check("void f() {\n" // #11078 " const char* p = nullptr;\n" " std::string s1{ p };\n" " std::string s2{ nullptr };\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:21]: (error) Null pointer dereference: p [nullPointer]\n" "[test.cpp:4:17]: (error) Null pointer dereference [nullPointer]\n", errout_str()); check("const char* g(long) { return nullptr; }\n" // #11561 "void f() { std::string s = g(0L); }\n"); ASSERT_EQUALS("[test.cpp:2:29]: (error) Null pointer dereference: g(0L) [nullPointer]\n", errout_str()); check("const char* g() { return nullptr; }\n" // #14098 "std::string f() {\n" " std::string s{ g() };\n" " return s + std::string(g());\n" "}\n"); ASSERT_EQUALS("[test.cpp:3:21]: (error) Null pointer dereference: g() [nullPointer]\n" "[test.cpp:4:29]: (error) Null pointer dereference: g() [nullPointer]\n", errout_str()); } void nullpointerStdStream() { check("void f(std::ifstream& is) {\n" " char* p = 0;\n" " is >> p;\n" "}"); TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Possible null pointer dereference: p\n", "", errout_str()); check("void f(const std::ostringstream& oss, char* q) {\n" " char const* p = 0;\n" // Simplification makes detection of bug difficult " oss [test.cpp:4:22]: (warning) Either the condition 'p==0' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void f() {\n" " void* p1 = 0;\n" " std::cout > (int)p;\n" // result casted " std::cout > std::hex >> ret;\n" // Read integer " return ret;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); check("void f(int* i) {\n" " if(i) return;\n" " std::cout 0) & 0xFF);\n" " return out.str();\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // avoid regression from first fix attempt for #5811... check("void deserialize(const std::string &data) {\n" "std::istringstream iss(data);\n" "unsigned int len = 0;\n" "if (!(iss >> len))\n" " return;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); } void nullpointerSmartPointer() { // extracttests.start: void dostuff(int); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " if (p) {}\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:3:7] -> [test.cpp:4:11]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p = nullptr;\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::unique_ptr p) {\n" " if (p) {}\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:3:7] -> [test.cpp:4:11]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::unique_ptr p) {\n" " p = nullptr;\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f() {\n" " std::shared_ptr p;\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p.reset();\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " Fred * pp = nullptr;\n" " p.reset(pp);\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:5:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f(Fred& f) {\n" " std::shared_ptr p;\n" " p.reset(&f);\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("", errout_str()); check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " p.reset();\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct Fred { int x; };\n" "void f() {\n" " std::shared_ptr p(nullptr);\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4:11]: (error) Null pointer dereference: p [nullPointer]\n", errout_str()); check("struct A {};\n" "void f(int n) {\n" " std::unique_ptr p;\n" " p.reset(new const A*[n]);\n" "}"); ASSERT_EQUALS("", errout_str()); // #9216 check("struct A {\n" " void reset();\n" " void f();\n" "};\n" "void g(std::unique_ptr var) {\n" " var->reset();\n" " var->f();\n" "}"); ASSERT_EQUALS("", errout_str()); // #9439 check("char* g();\n" "char* f() {\n" " std::unique_ptr x(g());\n" " if( x ) {}\n" " return x.release();\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // #9496 check("std::shared_ptr f() {\n" " return std::shared_ptr(nullptr);\n" "}\n" "void g() {\n" " int a = *f();\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("[test.cpp:5:15]: (error) Null pointer dereference: f() [nullPointer]\n", errout_str()); } void nullpointerOutOfMemory() { check("void f() {\n" " int *p = malloc(10);\n" " *p = 0;\n" " free(p);\n" "}"); ASSERT_EQUALS("[test.cpp:3:6]: (warning) If memory allocation fails, then there is a possible null pointer dereference: p [nullPointerOutOfMemory]\n", errout_str()); check("void f() {\n" " int *p = malloc(10);\n" " *(p+2) = 0;\n" " free(p);\n" "}"); ASSERT_EQUALS("[test.cpp:3:8]: (error) If memory allocation fails: pointer addition with NULL pointer. [nullPointerArithmeticOutOfMemory]\n", errout_str()); check("void f() {\n" // #13676 " int* q = static_cast(std::malloc(4));\n" " *q = 0;\n" " std::free(q);\n" "}"); ASSERT_EQUALS("[test.cpp:3:6]: (warning) If memory allocation fails, then there is a possible null pointer dereference: q [nullPointerOutOfMemory]\n", errout_str()); } void functioncall() { // #3443 - function calls // dereference pointer and then check if it's null { // function not seen check("void f(int *p) {\n" " *p = 0;\n" " foo(p);\n" " if (p) { }\n" "}"); ASSERT_EQUALS("", errout_str()); // function seen (taking pointer parameter) check("void foo(int *p) { }\n" "\n" "void f(int *p) {\n" " *p = 0;\n" " foo(p);\n" " if (p) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // function seen (taking reference parameter) check("void foo(int *&p) { }\n" "\n" "void f(int *p) {\n" " *p = 0;\n" " foo(p);\n" " if (p) { }\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS("", errout_str()); // function implementation not seen check("void foo(int *p);\n" "\n" "void f(int *p) {\n" " *p = 0;\n" " foo(p);\n" " if (p) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:6]: (warning) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); // inconclusive check("void f(int *p) {\n" " *p = 0;\n" " foo(p);\n" " if (p) { }\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:6]: (warning, inconclusive) Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); } // dereference struct pointer and then check if it's null { // function not seen check("void f(struct ABC *abc) {\n" " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" "}"); ASSERT_EQUALS("", errout_str()); // function seen (taking pointer parameter) check("void foo(struct ABC *abc) { }\n" "\n" "void f(struct ABC *abc) {\n" " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); // function implementation not seen check("void foo(struct ABC *abc);\n" "\n" "void f(struct ABC *abc) {\n" " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" "}"); ASSERT_EQUALS( "[test.cpp:6:9] -> [test.cpp:4:5]: (warning) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); // inconclusive check("void f(struct ABC *abc) {\n" " abc->a = 0;\n" " foo(abc);\n" " if (abc) { }\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:4:9] -> [test.cpp:2:5]: (warning, inconclusive) Either the condition 'abc' is redundant or there is possible null pointer dereference: abc. [nullPointerRedundantCheck]\n", errout_str()); } } void nullpointerOutOfResources() { check("void f() {\n" " FILE* fid = fopen(\"x.txt\", \"w\");\n" " fprintf(fid, \"abcdef\");\n" " fclose(fid);\n" "}\n"); ASSERT_EQUALS( "[test.cpp:3:13]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n" "[test.cpp:4:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", errout_str()); // the guard might call an unknown, possibly noreturn function -> no warning check("void f() {\n" " FILE* fid = fopen(\"x.txt\", \"w\");\n" " if (fid == NULL)\n" " g();\n" " fclose(fid);\n" "}\n"); ASSERT_EQUALS("", errout_str()); // .. but an inconclusive warning is reported with --inconclusive check("void f() {\n" " FILE* fid = fopen(\"x.txt\", \"w\");\n" " if (fid == NULL)\n" " g();\n" " fclose(fid);\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:5:12]: (warning, inconclusive) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", errout_str()); check("int f(const int* p) {\n" " if (p == nullptr)\n" " g();\n" " return *p;\n" "}\n", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:2:11] -> [test.cpp:4:13]: (warning, inconclusive) Either the condition 'p==nullptr' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]\n", errout_str()); check("void f() {\n" " FILE* fid = fopen(\"x.txt\", \"w\");\n" " if (fid != NULL)\n" " ;\n" " else\n" " g();\n" " fclose(fid);\n" "}\n"); ASSERT_EQUALS("", errout_str()); // guard function is known to return -> warning check("void g() {}\n" "void f() {\n" " FILE* fid = fopen(\"x.txt\", \"w\");\n" " if (fid == NULL)\n" " g();\n" " fclose(fid);\n" "}\n"); ASSERT_EQUALS( "[test.cpp:6:12]: (warning) If resource allocation fails, then there is a possible null pointer dereference: fid [nullPointerOutOfResources]\n", errout_str()); } void functioncalllibrary() { SimpleTokenizer tokenizer(settingsDefault,*this,false); const char code[] = "void f() { int a,b,c; x(a,b,c); }"; ASSERT_EQUALS(true, tokenizer.tokenize(code)); const Token *xtok = Token::findsimplematch(tokenizer.tokens(), "x"); // nothing bad.. { constexpr char xmldata[] = "\n" "\n" " \n" " \n" " \n" " \n" " \n" ""; Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(0U, null.size()); } // for 1st parameter null pointer is not ok.. { constexpr char xmldata[] = "\n" "\n" " \n" " \n" " \n" " \n" " \n" ""; Library library; ASSERT(LibraryHelper::loadxmldata(library, xmldata, sizeof(xmldata))); const std::list null = CheckNullPointerImpl::parseFunctionCall(*xtok, library); ASSERT_EQUALS(1U, null.size()); ASSERT_EQUALS("a", null.front()->str()); } } void functioncallDefaultArguments() { check("void f(int *p = 0) {\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:6]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " if (!p)\n" " return;\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(char a, int *p = 0) {\n" " *p = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2:6]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " printf(\"p = %d\", *p);\n" "}"); ASSERT_EQUALS("[test.cpp:2:23]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " printf(\"p[1] = %d\", p[1]);\n" "}"); ASSERT_EQUALS("[test.cpp:2:25]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " buf[p] = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " if (p != 0 && bar())\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int *p) {\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " if (p != 0)\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int *p = 0) {\n" " int y;\n" " if (p == 0)\n" " p = &y;\n" " *p = 0;\n" "}"); ASSERT_EQUALS("", errout_str()); check("void f(int a, int *p = 0) {\n" " if (a != 0)\n" " *p = 0;\n" "}", dinit(CheckOptions, $.inconclusive = true)); ASSERT_EQUALS( "[test.cpp:3:8]: (warning) Possible null pointer dereference if the default parameter value is used: p [nullPointerDefaultArg]\n", errout_str()); check("void f(int *p = 0) {\n" " p = a;\n" " *p = 0;\n" //

Back | FazBrowse Home | New Git URL