/*
* 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 "checkuninitvar.h"
#include "ctu.h"
#include "fixture.h"
#include "helpers.h"
#include "settings.h"
#include
#include
#include
class TestUninitVar : public TestFixture {
public:
TestUninitVar() : TestFixture("TestUninitVar") {}
private:
const Settings settings = settingsBuilder().library("std.cfg").build();
void run() override {
mNewTemplate = true;
TEST_CASE(uninitvar1);
TEST_CASE(uninitvar_warn_once); // only write 1 warning at a time
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(uninitvar_ignore); // ignore cast, *&x, ..
TEST_CASE(uninitvar2);
TEST_CASE(uninitvar3); // #3844
TEST_CASE(uninitvar4); // #3869 (reference)
TEST_CASE(uninitvar5); // #3861
TEST_CASE(uninitvar6); // #13227
TEST_CASE(uninitvar2_func); // function calls
TEST_CASE(uninitvar2_value); // value flow
TEST_CASE(valueFlowUninit2_value);
TEST_CASE(valueFlowUninit_uninitvar2);
TEST_CASE(valueFlowUninit_functioncall);
TEST_CASE(uninitStructMember); // 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(uninitvar10); // ticket #9467
TEST_CASE(uninitvar11); // ticket #9123
TEST_CASE(uninitvar12); // #10218 - stream read
TEST_CASE(uninitvar13); // #9772
TEST_CASE(uninitvar14);
TEST_CASE(uninitvar15); // #13685
TEST_CASE(uninitvar_unconditionalTry);
TEST_CASE(uninitvar_funcptr); // #6404
TEST_CASE(uninitvar_operator); // #6680
TEST_CASE(uninitvar_ternaryexpression1); // #4683
TEST_CASE(uninitvar_ternaryexpression2); // #14729
TEST_CASE(uninitvar_pointertoarray);
TEST_CASE(uninitvar_cpp11ArrayInit); // #7010
TEST_CASE(uninitvar_rangeBasedFor); // #7078
TEST_CASE(uninitvar_static); // #8734
TEST_CASE(uninitvar_configuration);
TEST_CASE(checkExpr);
TEST_CASE(trac_4871);
TEST_CASE(syntax_error); // Ticket #5073
TEST_CASE(trac_5970);
TEST_CASE(valueFlowUninitTest);
TEST_CASE(valueFlowUninitBreak);
TEST_CASE(valueFlowUninitStructMembers);
TEST_CASE(valueFlowUninitForLoop);
TEST_CASE(uninitvar_ipa);
TEST_CASE(uninitvar_memberfunction);
TEST_CASE(uninitvar_nonmember); // crash in ycmd test
TEST_CASE(uninitvarDesignatedInitializers);
TEST_CASE(uninitvarMemberPointer);
TEST_CASE(isVariableUsageDeref); // *p
TEST_CASE(isVariableUsageDerefValueflow); // *p
TEST_CASE(uninitvar_memberaccess); // (&(a))->b a.b
// whole program analysis
TEST_CASE(ctuTest);
}
struct CheckUninitVarOptions
{
bool cpp = true;
};
#define checkUninitVar(...) checkUninitVar_(__FILE__, __LINE__, __VA_ARGS__)
template
void checkUninitVar_(const char* file, int line, const char (&code)[size], const CheckUninitVarOptions& options = make_default_obj()) {
checkUninitVar_(file, line, code, settings, options.cpp);
}
template
void checkUninitVar_(const char* file, int line, const char (&code)[size], const Settings& settings1, bool cpp = true) {
SimpleTokenizer tokenizer(settings1, *this, cpp);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
// Check for redundant code..
CheckUninitVarImpl checkuninitvar(&tokenizer, settings1, *this);
checkuninitvar.check();
}
// TODO: get rid of this
void checkUninitVar_(const char* file, int line, const std::string& code) {
SimpleTokenizer tokenizer(settings, *this);
ASSERT_LOC(tokenizer.tokenize(code), file, line);
// Check for redundant code..
CheckUninitVarImpl checkuninitvar(&tokenizer, settings, *this);
checkuninitvar.check();
}
void uninitvar1() {
// extracttests.start: int b; int c;
// Ticket #2207 - False negative
checkUninitVar("void foo() {\n"
" int a;\n"
" b = c - a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3:13]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("void foo() {\n"
" int a;\n"
" b = a - c;\n"
"}");
ASSERT_EQUALS("[test.cpp:3:9]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
// Ticket #6455 - some compilers allow const variables to be uninitialized
// extracttests.disable
checkUninitVar("void foo() {\n"
" const int a;\n"
" b = c - a;\n"
"}");
ASSERT_EQUALS("[test.cpp:3:13]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
// extracttests.enable
checkUninitVar("void foo() {\n"
" int *p;\n"
" realloc(p,10);\n"
"}");
ASSERT_EQUALS("[test.cpp:3:13]: (error) Uninitialized variable: p [legacyUninitvar]\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..
// extracttests.start: struct Foo { void abcd(); };
checkUninitVar("static void foo()\n"
"{\n"
" Foo *p;\n"
" p->abcd();\n"
"}");
ASSERT_EQUALS("[test.cpp:4:5]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
// extracttests.start: template struct Foo { void abcd(); };
checkUninitVar("static void foo()\n"
"{\n"
" Foo *p;\n"
" p->abcd();\n"
"}");
ASSERT_EQUALS("[test.cpp:4:5]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
// extracttests.start: struct Foo { void* a; };
checkUninitVar("void f(Foo *p)\n"
"{\n"
" int a;\n"
" p->a = malloc(4 * a);\n"
"}");
ASSERT_EQUALS("[test.cpp:4:23]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" delete p;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:12]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" delete [] p;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:15]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" *p = 135;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:6]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *p;\n"
" p[0] = 135;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:5]: (error) Uninitialized variable: p [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *x;\n"
" int y = *x;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:14]: (error) Uninitialized variable: x [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int *x;\n"
" int &y(*x);\n"
"}");
ASSERT_EQUALS("[test.cpp:4:13]: (error) Uninitialized variable: x [legacyUninitvar]\n", errout_str());
checkUninitVar("void foo()\n"
"{\n"
" int x;\n"
" int *y = &x;\n"
"}");
ASSERT_EQUALS("", errout_str());
checkUninitVar("void foo()\n"
"{\n"
" int *x;\n"
" int *&y = x;\n"
"}");
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:13]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("void f()\n"
"{\n"
" int a;\n"
" a++;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:5]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("void f()\n"
"{\n"
" extern int a;\n"
" a++;\n"
"}");
ASSERT_EQUALS("", errout_str());
// extracttests.start: void bar(int);
checkUninitVar("void f()\n"
"{\n"
" int a;\n"
" bar(4 * a);\n"
"}");
ASSERT_EQUALS("[test.cpp:4:13]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int i;\n"
" if (i);\n"
"}");
ASSERT_EQUALS("[test.cpp:4:9]: (error) Uninitialized variable: i [legacyUninitvar]\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:21]: (error) Uninitialized variable: i [legacyUninitvar]\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:29]: (error) Uninitialized variable: i [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo(int x)\n"
"{\n"
" int i;\n"
" if (x)\n"
" i = 0;\n"
" i++;\n"
"}");
ASSERT_EQUALS("[test.cpp:6:5]: (error) Uninitialized variable: i [legacyUninitvar]\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:8]: (error) Uninitialized variable: i [legacyUninitvar]\n", errout_str());
checkUninitVar("static void foo()\n"
"{\n"
" int x, y;\n"
" x = (y = 10);\n"
" int z = y * 2;\n"
"}");
ASSERT_EQUALS("", errout_str());
checkUninitVar("static void foo() {\n"
" int x, y;\n"
" x = ((y) = 10);\n"
"}");
ASSERT_EQUALS("", errout_str());
// Ticket #3597
checkUninitVar("void f() {\n"
" int a;\n"
" int b = 1;\n"
" (b += a) = 1;\n"
"}");
ASSERT_EQUALS("[test.cpp:4:11]: (error) Uninitialized variable: a [legacyUninitvar]\n", errout_str());
checkUninitVar("int f() {\n"
" int a,b,c;\n"
" a = b = c;\n"
"}");
ASSERT_EQUALS("[test.cpp:3:0]: (error) Uninitialized variable: c [legacyUninitvar]\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
// extracttests.disable
{
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",
dinit(CheckUninitVarOptions, $.cpp = false));
ASSERT_EQUALS("[test.c:4:12]: (error) Uninitialized variable: ret [legacyUninitvar]\n", errout_str());
}
// extracttests.enable
// #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"
"}",
dinit(CheckUninitVarOptions, $.cpp = false));
ASSERT_EQUALS("", errout_str());
checkUninitVar("void a()\n"
"{\n"
" int x[10];\n"
" int *y = x;\n"
"}");
ASSERT_EQUALS("", errout_str());
checkUninitVar("void a()\n"
"{\n"
" int x;\n"
" int *y = &x;\n"
" *y = 0;\n"
" x++;\n"
"}");
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"
"}");
ASSERT_EQUALS("", errout_str());
// Handling >> and