/*
* Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2018 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 "checkuninitvar.h"
#include "library.h"
#include "settings.h"
#include "testsuite.h"
#include "tokenize.h"
#include
#include
struct InternalError;
class TestUninitVar : public TestFixture {
public:
TestUninitVar() : TestFixture("TestUninitVar") {
}
private:
Settings settings;
void run() override {
LOAD_LIB_2(settings.library, "std.cfg");
TEST_CASE(uninitvar1);
TEST_CASE(uninitvar_decl); // handling various types in C and C++ files
TEST_CASE(uninitvar_bitop); // using uninitialized operand in bit operation
TEST_CASE(uninitvar_alloc); // data is allocated but not initialized
TEST_CASE(uninitvar_arrays); // arrays
TEST_CASE(uninitvar_class); // class/struct
TEST_CASE(uninitvar_enum); // enum variables
TEST_CASE(uninitvar_if); // handling if
TEST_CASE(uninitvar_loops); // handling for/while
TEST_CASE(uninitvar_switch); // handling switch
TEST_CASE(uninitvar_references); // references
TEST_CASE(uninitvar_return); // return
TEST_CASE(uninitvar_assign); // = {..}
TEST_CASE(uninitvar_strncpy); // strncpy doesn't always null-terminate
TEST_CASE(func_uninit_var); // analyse function calls for: 'int a(int x) { return x+x; }'
TEST_CASE(func_uninit_pointer); // analyse function calls for: 'void a(int *p) { *p = 0; }'
TEST_CASE(uninitvar_typeof); // typeof
TEST_CASE(uninitvar2);
TEST_CASE(uninitvar3); // #3844
TEST_CASE(uninitvar4); // #3869 (reference)
TEST_CASE(uninitvar5); // #3861
TEST_CASE(uninitvar2_func); // function calls
TEST_CASE(uninitvar2_value); // value flow
TEST_CASE(uninitvar2_structmembers); // struct members
TEST_CASE(uninitvar2_while);
TEST_CASE(uninitvar2_4494); // #4494
TEST_CASE(uninitvar2_malloc); // malloc returns uninitialized data
TEST_CASE(uninitvar8); // ticket #6230
TEST_CASE(uninitvar9); // ticket #6424
TEST_CASE(uninitvar_unconditionalTry);
TEST_CASE(uninitvar_funcptr); // #6404
TEST_CASE(uninitvar_operator); // #6680
TEST_CASE(uninitvar_ternaryexpression); // #4683
TEST_CASE(uninitvar_pointertoarray);
TEST_CASE(uninitvar_cpp11ArrayInit); // #7010
TEST_CASE(uninitvar_rangeBasedFor); // #7078
TEST_CASE(trac_4871);
TEST_CASE(syntax_error); // Ticket #5073
TEST_CASE(trac_5970);
TEST_CASE(valueFlowUninit);
TEST_CASE(isVariableUsageDeref); // *p
// dead pointer
TEST_CASE(deadPointer);
}
void checkUninitVar(const char code[], const char fname[] = "test.cpp", bool debugwarnings = false) {
// Clear the error buffer..
errout.str("");
// Tokenize..
settings.debugwarnings = debugwarnings;
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, fname);
tokenizer.simplifyTokenList2();
// Check for redundant code..
CheckUninitVar checkuninitvar(&tokenizer, &settings, this);
checkuninitvar.check();
settings.debugwarnings = false;
settings.experimental = true;
}
void uninitvar1() {
// Ticket #2207 - False negative
checkUninitVar("void foo() {\n"
" int a;\n"
" b = c - a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void foo() {\n"
" int a;\n"
" b = a - c;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
// Ticket #6455 - some compilers allow const variables to be uninitialized
checkUninitVar("void foo() {\n"
" const int a;\n"
" b = c - a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void foo() {\n"
" int *p;\n"
" realloc(p,10);\n"
"}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("void foo() {\n" // #5240
" char *p = malloc(100);\n"
" char *tmp = realloc(p,1000);\n"
" if (!tmp) free(p);\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void foo() {\n"
" int *p = NULL;\n"
" realloc(p,10);\n"
"}");
ASSERT_EQUALS("", errout.str());
// dereferencing uninitialized pointer..
checkUninitVar("static void foo()\n"
"{\n"
" Foo *p;\n"
" p->abcd();\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" Foo *p;\n"
" p->abcd();\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("void f(Foo *p)\n"
"{\n"
" int a;\n"
" p->a = malloc(4 * a);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" delete p;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" delete [] p;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" *p = 135;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" p[0] = 135;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *x;\n"
" int y = *x;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int *x;\n"
" int &y(*x);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str());
checkUninitVar("void foo()\n"
"{\n"
" int x;\n"
" int *y = &x;\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
checkUninitVar("void foo()\n"
"{\n"
" int *x;\n"
" int *&y = x;\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
checkUninitVar("void foo()\n"
"{\n"
" int x = xyz::x;\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f()\n"
"{\n"
" int a;\n"
" a = 5 + a;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void f()\n"
"{\n"
" int a;\n"
" a++;\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("void f()\n"
"{\n"
" extern int a;\n"
" a++;\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void f()\n"
"{\n"
" int a;\n"
" bar(4 * a);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int i;\n"
" if (i);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: i\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int i;\n"
" for (int x = 0; i < 10; x++);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: i\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int i;\n"
" for (int x = 0; x < 10; i++);\n"
"}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: i\n", errout.str());
checkUninitVar("static int foo(int x)\n"
"{\n"
" int i;\n"
" if (x)\n"
" i = 0;\n"
" i++;\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: i\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int ar[10];\n"
" int i;\n"
" ar[i] = 0;\n"
"}");
ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: i\n", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" int x, y;\n"
" x = (y = 10);\n"
" int z = y * 2;\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
checkUninitVar("static void foo() {\n"
" int x, y;\n"
" x = ((y) = 10);\n"
"}");
ASSERT_EQUALS("", errout.str());
// Ticket #3597
checkUninitVar("int f() {\n"
" int a;\n"
" int b = 1;\n"
" (b += a) = 1;\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n","", errout.str());
checkUninitVar("int f() {\n"
" int a,b,c;\n"
" a = b = c;\n"
"}", "test.cpp", /*verify=*/ false);
TODO_ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: c\n", "", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" Foo p;\n"
" p.abcd();\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("static void foo()\n"
"{\n"
" Foo p;\n"
" int x = p.abcd();\n"
"}");
ASSERT_EQUALS("", errout.str());
// Unknown types
{
checkUninitVar("void a()\n"
"{\n"
" A ret;\n"
" return ret;\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("void a()\n"
"{\n"
" A ret;\n"
" return ret;\n"
"}\n",
"test.c");
ASSERT_EQUALS("[test.c:4]: (error) Uninitialized variable: ret\n", errout.str());
// #3916 - avoid false positive
checkUninitVar("void f(float x) {\n"
" union lf { long l; float f; } u_lf;\n"
" float hx = (u_lf.f = (x), u_lf.l);\n"
"}",
"test.c", false);
ASSERT_EQUALS("", errout.str());
}
checkUninitVar("void a()\n"
"{\n"
" int x[10];\n"
" int *y = x;\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
checkUninitVar("void a()\n"
"{\n"
" int x;\n"
" int *y = &x;\n"
" *y = 0;\n"
" x++;\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
checkUninitVar("void a()\n"
"{\n"
" char x[10], y[10];\n"
" char *z = x;\n"
" memset(z, 0, sizeof(x));\n"
" memcpy(y, x, sizeof(x));\n"
"}", "test.cpp", false);
ASSERT_EQUALS("", errout.str());
// Handling >> and