diff --git a/lib/programmemory.cpp b/lib/programmemory.cpp index 9882cba2a3c..ffc97ae1509 100644 --- a/lib/programmemory.cpp +++ b/lib/programmemory.cpp @@ -205,7 +205,7 @@ bool ProgramMemory::empty() const } // NOLINTNEXTLINE(performance-unnecessary-value-param) - technically correct but we are moving the given values -void ProgramMemory::replace(ProgramMemory pm) +void ProgramMemory::replace(ProgramMemory pm, bool skipUnknown) { if (pm.empty()) return; @@ -213,6 +213,11 @@ void ProgramMemory::replace(ProgramMemory pm) copyOnWrite(); for (auto&& p : (*pm.mValues)) { + if (skipUnknown) { + auto it = mValues->find(p.first); + if (it != mValues->end() && it->second.isUninitValue()) + continue; + } (*mValues)[p.first] = std::move(p.second); } } @@ -405,7 +410,8 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok if (!setvar) { if (!pm.hasValue(vartok->exprId())) { const Token* valuetok = tok2->astOperand2(); - pm.setValue(vartok, execute(valuetok, pm, settings)); + ProgramMemory local = state; + pm.setValue(vartok, execute(valuetok, local, settings)); } } } else if (tok2->exprId() > 0 && Token::Match(tok2, ".|(|[|*|%var%") && !pm.hasValue(tok2->exprId()) && @@ -476,7 +482,7 @@ void ProgramMemoryState::replace(ProgramMemory pm, const Token* origin) if (origin) for (const auto& p : pm) origins[p.first.getExpressionId()] = origin; - state.replace(std::move(pm)); + state.replace(std::move(pm), /*skipUnknown*/ true); } static void addVars(ProgramMemory& pm, const ProgramMemory::Map& vars) @@ -489,13 +495,14 @@ static void addVars(ProgramMemory& pm, const ProgramMemory::Map& vars) void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& vars) { - ProgramMemory pm = state; - addVars(pm, vars); - fillProgramMemoryFromConditions(pm, tok, settings); - ProgramMemory local = pm; + ProgramMemory local = state; + addVars(local, vars); + fillProgramMemoryFromConditions(local, tok, settings); + ProgramMemory pm; fillProgramMemoryFromAssignments(pm, tok, settings, local, vars); - addVars(pm, vars); - replace(std::move(pm), tok); + local.replace(std::move(pm)); + addVars(local, vars); + replace(std::move(local), tok); } void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) diff --git a/lib/programmemory.h b/lib/programmemory.h index 36b453b71de..b2281669c0b 100644 --- a/lib/programmemory.h +++ b/lib/programmemory.h @@ -130,7 +130,7 @@ struct CPPCHECKLIB ProgramMemory { bool empty() const; - void replace(ProgramMemory pm); + void replace(ProgramMemory pm, bool skipUnknown = false); Map::const_iterator begin() const { return mValues->cbegin(); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index dfdc048b4f9..dfd1eeb9529 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -6588,6 +6588,23 @@ class TestUninitVar : public TestFixture { " return c.front();\n" "}\n"); ASSERT_EQUALS("[test.cpp:8:12]: (error) Uninitialized variable: c [uninitvar]\n", errout_str()); + + // #13930 + valueFlowUninit("extern int32_t g_items[10U];\n" + "uint16_t write_item(uint8_t n);\n" + "uint16_t write_item(uint8_t n) {\n" + " int32_t *p_item = NULL;\n" + " uint16_t ret;\n" + " ret = 0U;\n" + " if (n < 10U)\n" + " p_item = &g_items[n];\n" + " else\n" + " ret = 1U;\n" + " if (ret == 0U) \n" + " *p_item = 5;\n" + " return ret;\n" + "}\n"); + ASSERT_EQUALS("", errout_str()); } void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value