Fix FP uninitStructMember / cleanup from #5311 (#5315)

This commit is contained in:
chrchr-github 2023-08-12 23:46:31 +02:00 committed by GitHub
parent 2b3dec4418
commit d4d77edeae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 55 additions and 20 deletions

View File

@ -3129,30 +3129,33 @@ static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings
return ExprUsage::Inconclusive;
}
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings)
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp)
{
if (indirect > 0 && tok->astParent()) {
if (Token::Match(tok->astParent(), "%assign%") && astIsRHS(tok))
const Token* const parent = tok->astParent();
if (indirect > 0 && parent) {
if (Token::Match(parent, "%assign%") && astIsRHS(tok))
return ExprUsage::NotUsed;
if (tok->astParent()->isConstOp())
if (parent->isConstOp())
return ExprUsage::NotUsed;
if (tok->astParent()->isCast())
if (parent->isCast())
return ExprUsage::NotUsed;
if (Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "?"))
return getExprUsage(tok->astParent()->astParent(), indirect, settings);
if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?"))
return getExprUsage(parent->astParent(), indirect, settings, cpp);
}
if (indirect == 0) {
if (Token::Match(tok->astParent(), "%cop%|%assign%|++|--") && !Token::Match(tok->astParent(), "=|>>") &&
!tok->astParent()->isUnaryOp("&"))
if (Token::Match(parent, "%cop%|%assign%|++|--") && parent->str() != "=" &&
!parent->isUnaryOp("&") &&
!(astIsRHS(tok) && isLikelyStreamRead(cpp, parent)))
return ExprUsage::Used;
if (Token::simpleMatch(tok->astParent(), "=") && astIsRHS(tok)) {
if (tok->astParent()->astOperand1() && tok->astParent()->astOperand1()->variable() && tok->astParent()->astOperand1()->variable()->isReference())
if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
const Token* const lhs = parent->astOperand1();
if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken())
return ExprUsage::NotUsed;
return ExprUsage::Used;
}
// Function call or index
if (((Token::simpleMatch(tok->astParent(), "(") && !tok->astParent()->isCast()) || (Token::simpleMatch(tok->astParent(), "[") && tok->valueType())) &&
(astIsLHS(tok) || Token::simpleMatch(tok->astParent(), "( )")))
if (((Token::simpleMatch(parent, "(") && !parent->isCast()) || (Token::simpleMatch(parent, "[") && tok->valueType())) &&
(astIsLHS(tok) || Token::simpleMatch(parent, "( )")))
return ExprUsage::Used;
}
return getFunctionUsage(tok, indirect, settings);

View File

@ -409,7 +409,7 @@ bool isConstVarExpression(const Token* tok, std::function<bool(const Token*)> sk
enum class ExprUsage { None, NotUsed, PassedByReference, Used, Inconclusive };
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings);
ExprUsage getExprUsage(const Token* tok, int indirect, const Settings* settings, bool cpp);
const Variable *getLHSVariable(const Token *tok);

View File

@ -3388,7 +3388,7 @@ void CheckOther::checkAccessOfMovedVariable()
else
inconclusive = true;
} else {
const ExprUsage usage = getExprUsage(tok, 0, mSettings);
const ExprUsage usage = getExprUsage(tok, 0, mSettings, mTokenizer->isCPP());
if (usage == ExprUsage::Used)
accessOfMoved = true;
if (usage == ExprUsage::PassedByReference)

View File

@ -709,9 +709,11 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
if (!membervar.empty()) {
if (!suppressErrors && Token::Match(tok, "%name% . %name%") && tok->strAt(2) == membervar && Token::Match(tok->next()->astParent(), "%cop%|return|throw|?"))
uninitStructMemberError(tok, tok->str() + "." + membervar);
else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?"))
else if (mTokenizer->isCPP() && !suppressErrors && Token::Match(tok, "%name%") && Token::Match(tok->astParent(), "return|throw|?")) {
if (std::any_of(tok->values().cbegin(), tok->values().cend(), std::mem_fn(&ValueFlow::Value::isUninitValue)))
uninitStructMemberError(tok, tok->str() + "." + membervar);
}
}
// Use variable
else if (!suppressErrors && isVariableUsage(tok, var.isPointer(), *alloc))
@ -1488,8 +1490,10 @@ bool CheckUninitVar::isMemberVariableUsage(const Token *tok, bool isPointer, All
if (!isPointer && !Token::simpleMatch(tok->astParent(), ".") && Token::Match(tok->previous(), "[(,] %name% [,)]") && isVariableUsage(tok, isPointer, alloc))
return true;
if (!isPointer && Token::Match(tok->previous(), "= %name% ;"))
return true;
if (!isPointer && Token::Match(tok->previous(), "= %name% ;")) {
const Token* lhs = tok->previous()->astOperand1();
return !(lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken());
}
// = *(&var);
if (!isPointer &&
@ -1639,7 +1643,7 @@ void CheckUninitVar::valueFlowUninit()
if (!isleaf && Token::Match(tok->astParent(), ". %name%") && (tok->astParent()->next()->varId() || tok->astParent()->next()->isEnumerator()))
continue;
}
const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings);
const ExprUsage usage = getExprUsage(tok, v->indirect, mSettings, mTokenizer->isCPP());
if (usage == ExprUsage::NotUsed || usage == ExprUsage::Inconclusive)
continue;
if (!v->subexpressions.empty() && usage == ExprUsage::PassedByReference)

View File

@ -4787,6 +4787,21 @@ private:
" }\n"
"}");
ASSERT_EQUALS("", errout.str());
checkUninitVar("struct S { int x; };\n"
"S h() {\n"
" S s;\n"
" S& r = s;\n"
" r.x = 0;\n"
" return s;\n"
"}\n"
"S i() {\n"
" S s;\n"
" S& r{ s };\n"
" r.x = 0;\n"
" return s;\n"
"}");
ASSERT_EQUALS("", errout.str());
}
void uninitvar2_while() {
@ -6169,6 +6184,19 @@ private:
" return s->i;\n"
"}\n");
ASSERT_EQUALS("", errout.str());
valueFlowUninit("int f(int i) {\n"
" int x;\n"
" int* p = &x;\n"
" return i >> *p;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: *p\n", errout.str());
valueFlowUninit("void f(int& x) {\n"
" int i;\n"
" x = i;\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: i\n", errout.str());
}
void valueFlowUninitBreak() { // Do not show duplicate warnings about the same uninitialized value