From b535e553a786a9e35284127443c69d542687456e Mon Sep 17 00:00:00 2001 From: Anton Lindqvist Date: Fri, 6 Mar 2026 07:40:37 +0100 Subject: [PATCH] Fix #13685 FP uinitvar with nested compound statement scopes PR #6714 introduced a regression in which variables initialized in nested compound statements are incorrectly flagged as uninitialized by uninitvar. Such scopes could be present due to usage of GNU compound statements. --- lib/symboldatabase.cpp | 14 +++++++++----- test/testsymboldatabase.cpp | 19 +++++++++++++++++++ test/testuninitvar.cpp | 12 ++++++++++++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 3bde7a71e19..9748959ba53 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -160,6 +160,7 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() }; std::stack inIfCondition; + std::stack pendingIfScopes; auto addLambda = [this, &scope](const Token* tok, const Token* lambdaEndToken) -> const Token* { const Token* lambdaStartToken = lambdaEndToken->link(); @@ -766,13 +767,14 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() scopeList.emplace_back(*this, tok, scope, ScopeType::eSwitch, scopeStartTok); scope->nestedList.push_back(&scopeList.back()); - scope = &scopeList.back(); - if (scope->type == ScopeType::eFor) - scope->checkVariable(tok->tokAt(2), AccessControl::Local); // check for variable declaration and add it to new scope if found - else if (scope->type == ScopeType::eCatch) - scope->checkVariable(tok->tokAt(2), AccessControl::Throw); // check for variable declaration and add it to new scope if found + Scope* newScope = &scopeList.back(); + if (newScope->type == ScopeType::eFor) + newScope->checkVariable(tok->tokAt(2), AccessControl::Local); // check for variable declaration and add it to new scope if found + else if (newScope->type == ScopeType::eCatch) + newScope->checkVariable(tok->tokAt(2), AccessControl::Throw); // check for variable declaration and add it to new scope if found tok = tok->next(); inIfCondition.push(scopeStartTok); + pendingIfScopes.push(newScope); } else if (Token::Match(tok, "%var% {")) { endInitList.emplace(tok->linkAt(1), scope); tok = tok->next(); @@ -783,6 +785,8 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes() endInitList.emplace(tok->link(), scope); } else if (!inIfCondition.empty() && tok == inIfCondition.top()) { inIfCondition.pop(); + scope = pendingIfScopes.top(); + pendingIfScopes.pop(); } else if (isExecutableScope(tok)) { scopeList.emplace_back(*this, tok, scope, ScopeType::eUnconditional, tok); scope->nestedList.push_back(&scopeList.back()); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 192c40f51e5..05dd0ab9b8f 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -441,6 +441,7 @@ class TestSymbolDatabase : public TestFixture { TEST_CASE(createSymbolDatabaseFindAllScopes8); // #12761 TEST_CASE(createSymbolDatabaseFindAllScopes9); TEST_CASE(createSymbolDatabaseFindAllScopes10); + TEST_CASE(createSymbolDatabaseFindAllScopes11); TEST_CASE(createSymbolDatabaseIncompleteVars); @@ -6110,6 +6111,24 @@ class TestSymbolDatabase : public TestFixture { } } + void createSymbolDatabaseFindAllScopes11() // #13685 + { + GET_SYMBOL_DB("int f() {\n" + " int x;\n" + " if (!({ int *p = &x; *p = 1; 1; }))\n" + " return 0;\n" + " return x;\n" + "}\n"); + ASSERT(db && db->scopeList.size() == 4); + + auto it = db->scopeList.begin(); + std::advance(it, 3); + const Scope& compoundScope = *it; + ASSERT_EQUALS_ENUM(ScopeType::eUnconditional, compoundScope.type); + ASSERT_EQUALS_ENUM(ScopeType::eFunction, compoundScope.nestedIn->type); + ASSERT_EQUALS("f", compoundScope.nestedIn->className); + } + void createSymbolDatabaseIncompleteVars() { { diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 554eaca1f11..62be497638a 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -76,6 +76,7 @@ class TestUninitVar : public TestFixture { 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 @@ -3647,6 +3648,17 @@ class TestUninitVar : public TestFixture { (checkuninitvar.valueFlowUninit)(); } + void uninitvar15() { // #13685 + const char code[] = "int f() {\n" + " int x;\n" + " if (!({ int *p = &x; *p = 1; 1; }))\n" + " return 0;\n" + " return x;\n" + "}"; + valueFlowUninit(code, false); + ASSERT_EQUALS("", errout_str()); + } + void valueFlowUninit2_value() { valueFlowUninit("void f() {\n"