Skip to content

Commit 52081ef

Browse files
authored
Add special function to match lifetimes (#5320)
This also removes the termination checking in `valueFlowUninit` as this causes a lot of FNs.
1 parent 48c91ab commit 52081ef

File tree

3 files changed

+36
-20
lines changed

3 files changed

+36
-20
lines changed

lib/checkuninitvar.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,9 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
710710
if (!suppressErrors && Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar && Token::Match(tok->next()->astParent(), "%cop%|return|throw|?"))
711711
uninitStructMemberError(tok, tok->str() + "." + membervar);
712712
else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?")) {
713-
if (std::any_of(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isUninitValue)))
713+
if (std::any_of(tok->values().cbegin(), tok->values().cend(), [](const ValueFlow::Value& v) {
714+
return v.isUninitValue() && !v.isInconclusive();
715+
}))
714716
uninitStructMemberError(tok, tok->str() + "." + membervar);
715717
}
716718
}

lib/valueflow.cpp

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -641,9 +641,10 @@ static void setTokenValue(Token* tok,
641641
}
642642
}
643643

644-
if (Token::simpleMatch(parent, "=") && astIsRHS(tok) && !value.isLifetimeValue()) {
645-
setTokenValue(parent, std::move(value), settings);
646-
return;
644+
if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
645+
setTokenValue(parent, value, settings);
646+
if (!value.isUninitValue())
647+
return;
647648
}
648649

649650
if (value.isContainerSizeValue() && astIsContainer(tok)) {
@@ -2433,6 +2434,20 @@ struct ValueFlowAnalyzer : Analyzer {
24332434
return settings;
24342435
}
24352436

2437+
// Returns Action::Match if its an exact match, return Action::Read if it partially matches the lifetime
2438+
Action analyzeLifetime(const Token* tok) const
2439+
{
2440+
if (!tok)
2441+
return Action::None;
2442+
if (match(tok))
2443+
return Action::Match;
2444+
if (Token::simpleMatch(tok, ".") && analyzeLifetime(tok->astOperand1()) != Action::None)
2445+
return Action::Read;
2446+
if (astIsRHS(tok) && Token::simpleMatch(tok->astParent(), "."))
2447+
return analyzeLifetime(tok->astParent());
2448+
return Action::None;
2449+
}
2450+
24362451
struct ConditionState {
24372452
bool dependent = true;
24382453
bool unknown = true;
@@ -2806,7 +2821,10 @@ struct ValueFlowAnalyzer : Analyzer {
28062821
return Action::None;
28072822
lifeTok = v.tokvalue;
28082823
}
2809-
if (lifeTok && match(lifeTok)) {
2824+
if (!lifeTok)
2825+
return Action::None;
2826+
Action la = analyzeLifetime(lifeTok);
2827+
if (la.matches()) {
28102828
Action a = Action::Read;
28112829
if (isModified(tok).isModified())
28122830
a = Action::Invalid;
@@ -2816,6 +2834,9 @@ struct ValueFlowAnalyzer : Analyzer {
28162834
return Action::Inconclusive;
28172835
return a;
28182836
}
2837+
if (la.isRead()) {
2838+
return isAliasModified(tok);
2839+
}
28192840
return Action::None;
28202841

28212842
} else if (isAlias(ref, inconclusive)) {
@@ -3299,12 +3320,6 @@ struct MemberExpressionAnalyzer : SubExpressionAnalyzer {
32993320
: SubExpressionAnalyzer(e, std::move(val), t, s), varname(std::move(varname))
33003321
{}
33013322

3302-
bool match(const Token* tok) const override
3303-
{
3304-
return SubExpressionAnalyzer::match(tok) ||
3305-
(Token::simpleMatch(tok->astParent(), ".") && SubExpressionAnalyzer::match(tok->astParent()));
3306-
}
3307-
33083323
bool submatch(const Token* tok, bool exact) const override
33093324
{
33103325
if (!Token::Match(tok, ". %var%"))
@@ -3334,6 +3349,8 @@ static std::string lifetimeType(const Token *tok, const ValueFlow::Value *val)
33343349
case ValueFlow::Value::LifetimeKind::Address:
33353350
if (astIsPointer(tok))
33363351
result = "pointer";
3352+
else if (Token::simpleMatch(tok, "=") && astIsPointer(tok->astOperand2()))
3353+
result = "pointer";
33373354
else
33383355
result = "object";
33393356
break;
@@ -7977,7 +7994,6 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings)
79777994
Token* start = findStartToken(var, tok->next(), &settings->library);
79787995

79797996
std::map<Token*, ValueFlow::Value> partialReads;
7980-
Analyzer::Result result;
79817997
if (const Scope* scope = var->typeScope()) {
79827998
if (Token::findsimplematch(scope->bodyStart, "union", scope->bodyEnd))
79837999
continue;
@@ -7992,7 +8008,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings)
79928008
continue;
79938009
}
79948010
MemberExpressionAnalyzer analyzer(memVar.nameToken()->str(), tok, uninitValue, tokenlist, settings);
7995-
result = valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings);
8011+
valueFlowGenericForward(start, tok->scope()->bodyEnd, analyzer, *settings);
79968012

79978013
for (auto&& p : *analyzer.partialReads) {
79988014
Token* tok2 = p.first;
@@ -8022,8 +8038,7 @@ static void valueFlowUninit(TokenList& tokenlist, const Settings* settings)
80228038
if (partial)
80238039
continue;
80248040

8025-
if (result.terminate != Analyzer::Terminate::Modified)
8026-
valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings);
8041+
valueFlowForward(start, tok->scope()->bodyEnd, var->nameToken(), uninitValue, tokenlist, settings);
80278042
}
80288043
}
80298044

test/testuninitvar.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6209,7 +6209,7 @@ class TestUninitVar : public TestFixture {
62096209
" memcpy(wcsin, x, sizeof(wcsstruct));\n" // <- warning
62106210
" x->wcsprm = NULL;\n" // <- no warning
62116211
"}");
6212-
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x.wcsprm\n", errout.str());
6212+
ASSERT_EQUALS("[test.cpp:7]: (error) Uninitialized variable: x\n", errout.str());
62136213

62146214
valueFlowUninit("struct wcsstruct {\n"
62156215
" int *wcsprm;\n"
@@ -7037,8 +7037,7 @@ class TestUninitVar : public TestFixture {
70377037
" memcpy(in, s, sizeof(S));\n"
70387038
" s->p = NULL;\n"
70397039
"}\n");
7040-
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s.p\n",
7041-
errout.str());
7040+
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: s\n", errout.str());
70427041

70437042
valueFlowUninit("struct S {\n" // #11321
70447043
" int a = 0;\n"
@@ -7298,7 +7297,7 @@ class TestUninitVar : public TestFixture {
72987297
" A::B b;\n"
72997298
" x.push_back(b);\n"
73007299
"}\n");
7301-
ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b.i\n", errout.str());
7300+
ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: b\n", errout.str());
73027301

73037302
valueFlowUninit("struct A {\n"
73047303
" struct B {\n"
@@ -7322,7 +7321,7 @@ class TestUninitVar : public TestFixture {
73227321
" A a;\n"
73237322
" x.push_back(a);\n"
73247323
"}\n");
7325-
ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: a.j\n", errout.str());
7324+
ASSERT_EQUALS("[test.cpp:9]: (error) Uninitialized variable: a\n", errout.str());
73267325

73277326
valueFlowUninit("struct S { struct T { int* p; } t[2]; };\n" // #11018
73287327
"void f() {\n"

0 commit comments

Comments
 (0)