Fix #12188 FN uninitvar with increment of struct member (#5665)

This commit is contained in:
chrchr-github 2023-11-16 18:11:12 +01:00 committed by GitHub
parent 831aec5c03
commit 4b9f3c68fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 57 additions and 12 deletions

View File

@ -3265,6 +3265,18 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
return ExprUsage::Inconclusive; 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) ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp)
{ {
const Token* parent = tok->astParent(); const Token* parent = tok->astParent();
@ -3285,6 +3297,13 @@ ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings,
!parent->isUnaryOp("&") && !parent->isUnaryOp("&") &&
!(astIsRHS(tok) && isLikelyStreamRead(cpp, parent))) !(astIsRHS(tok) && isLikelyStreamRead(cpp, parent)))
return ExprUsage::Used; 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)) { if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
const Token* const lhs = parent->astOperand1(); const Token* const lhs = parent->astOperand1();
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken()) if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken())

View File

@ -418,6 +418,8 @@ bool isCPPCast(const Token* tok);
bool isConstVarExpression(const Token* tok, std::function<bool(const Token*)> skipPredicate = nullptr); 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 }; enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive };
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp); ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp);

View File

@ -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); "$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() void CheckUninitVar::valueFlowUninit()
{ {
logChecker("CheckUninitVar::valueFlowUninit"); logChecker("CheckUninitVar::valueFlowUninit");

View File

@ -7215,6 +7215,42 @@ private:
" foo(&my_st);\n" " foo(&my_st);\n"
"}\n"); "}\n");
ASSERT_EQUALS("", errout.str()); 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() { void uninitvar_memberfunction() {