Skip to content

Commit

Permalink
Fix #12188 FN uninitvar with increment of struct member (#5665)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrchr-github authored Nov 16, 2023
1 parent 831aec5 commit 4b9f3c6
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 12 deletions.
19 changes: 19 additions & 0 deletions lib/astutils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3265,6 +3265,18 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
return ExprUsage::Inconclusive;
}

bool isLeafDot(const Token* tok)
{
if (!tok)
return false;
const Token * parent = tok->astParent();
if (!Token::simpleMatch(parent, "."))
return false;
if (parent->astOperand2() == tok && !Token::simpleMatch(parent->astParent(), "."))
return true;
return isLeafDot(parent);
}

ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp)
{
const Token* parent = tok->astParent();
Expand All @@ -3285,6 +3297,13 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings,
!parent->isUnaryOp("&") &&
!(astIsRHS(tok) && isLikelyStreamRead(cpp, parent)))
return ExprUsage::Used;
if (isLeafDot(tok)) {
const Token* op = parent->astParent();
while (Token::simpleMatch(op, "."))
op = op->astParent();
if (Token::Match(op, "%assign%|++|--") && op->str() != "=")
return ExprUsage::Used;
}
if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
const Token* const lhs = parent->astOperand1();
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken())
Expand Down
2 changes: 2 additions & 0 deletions lib/astutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ bool isCPPCast(const Token* tok);

bool isConstVarExpression(const Token* tok, std::function<bool(const Token*)> skipPredicate = nullptr);

bool isLeafDot(const Token* tok);

enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive };

ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp);
Expand Down
12 changes: 0 additions & 12 deletions lib/checkuninitvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1596,18 +1596,6 @@ void CheckUninitVar::uninitStructMemberError(const Token *tok, const std::string
"$symbol:" + membername + "\nUninitialized struct member: $symbol", CWE_USE_OF_UNINITIALIZED_VARIABLE, Certainty::normal);
}

static bool isLeafDot(const Token* tok)
{
if (!tok)
return false;
const Token * parent = tok->astParent();
if (!Token::simpleMatch(parent, "."))
return false;
if (parent->astOperand2() == tok && !Token::simpleMatch(parent->astParent(), "."))
return true;
return isLeafDot(parent);
}

void CheckUninitVar::valueFlowUninit()
{
logChecker("CheckUninitVar::valueFlowUninit");
Expand Down
36 changes: 36 additions & 0 deletions test/testuninitvar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7215,6 +7215,42 @@ class TestUninitVar : public TestFixture {
" foo(&my_st);\n"
"}\n");
ASSERT_EQUALS("", errout.str());

valueFlowUninit("struct S {\n" // #12188
" int i;\n"
" struct T { int j; } t;\n"
"};\n"
"void f() {\n"
" S s;\n"
" ++s.i;\n"
"}\n"
"void g() {\n"
" S s;\n"
" s.i--;\n"
"}\n"
"void h() {\n"
" S s;\n"
" s.i &= 3;\n"
"}\n"
"void k() {\n"
" S s;\n"
" if (++s.i < 3) {}\n"
"}\n"
"void m() {\n"
" S s;\n"
" ++s.t.j;\n"
"}\n"
"void n() {\n"
" S s;\n"
" if (s.t.j-- < 3) {}\n"
"}\n");
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: s.i\n"
"[test.cpp:11]: (error) Uninitialized variable: s.i\n"
"[test.cpp:15]: (error) Uninitialized variable: s.i\n"
"[test.cpp:19]: (error) Uninitialized variable: s.i\n"
"[test.cpp:23]: (error) Uninitialized variable: s.t.j\n"
"[test.cpp:27]: (error) Uninitialized variable: s.t.j\n",
errout.str());
}

void uninitvar_memberfunction() {
Expand Down

0 comments on commit 4b9f3c6

Please sign in to comment.