Uninitialized variables; check RHS expression

This commit is contained in:
Daniel Marjamäki 2021-05-21 14:30:47 +02:00
parent cc74c8e1da
commit 8adfcc848c
3 changed files with 61 additions and 10 deletions

View File

@ -775,8 +775,25 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
}
else {
if (tok->strAt(1) == "=")
checkRhs(tok, var, *alloc, number_of_if, emptyString);
const Token *parent = tok;
while (parent->astParent() && ((astIsLHS(parent) && parent->astParent()->str() == "[") || parent->astParent()->isUnaryOp("*"))) {
parent = parent->astParent();
if (parent->str() == "[") {
if (const Token *errorToken = checkExpr(parent->astOperand2(), var, *alloc, number_of_if==0)) {
if (!suppressErrors)
uninitvarError(errorToken, errorToken->expressionString(), *alloc);
return true;
}
}
}
if (Token::simpleMatch(parent->astParent(), "=") && astIsLHS(parent)) {
const Token *eq = parent->astParent();
if (const Token *errorToken = checkExpr(eq->astOperand2(), var, *alloc, number_of_if==0)) {
if (!suppressErrors)
uninitvarError(errorToken, errorToken->expressionString(), *alloc);
return true;
}
}
// assume that variable is assigned
return true;
@ -788,6 +805,32 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
return false;
}
const Token *CheckUninitVar::checkExpr(const Token *tok, const Variable& var, const Alloc alloc, bool known, bool *bailout)
{
if (!tok)
return nullptr;
if (tok->astOperand1()) {
bool bailout1 = false;
const Token *errorToken = checkExpr(tok->astOperand1(), var, alloc, known, &bailout1);
if (bailout && bailout1)
*bailout = true;
if (errorToken)
return errorToken;
if ((bailout1 || !known) && Token::Match(tok, "%oror%|&&|?"))
return nullptr;
}
if (tok->astOperand2())
return checkExpr(tok->astOperand2(), var, alloc, known, bailout);
if (tok->varId() == var.declarationId()) {
const Token *errorToken = isVariableUsage(tok, var.isPointer(), alloc);
if (errorToken)
return errorToken;
else if (bailout)
*bailout = true;
}
return nullptr;
}
bool CheckUninitVar::checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar)
{
const Token * const endpar = startparentheses->link();
@ -1059,16 +1102,23 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer,
int deref = 0;
derefValue = valueExpr;
while (Token::Match(derefValue->astParent(), "+|-|*|[|.") || (derefValue->astParent() && derefValue->astParent()->isCast())) {
if (derefValue->astParent()->isUnaryOp("*"))
++deref;
else if (derefValue->astParent()->str() == "[") {
const Token * const derefValueParent = derefValue->astParent();
if (derefValueParent->str() == "*") {
if (derefValueParent->isUnaryOp("*"))
++deref;
else
break;
} else if (derefValueParent->str() == "[") {
if (astIsLhs(derefValue))
++deref;
else
break;
} else if (derefValue->astParent()->str() == ".")
} else if (Token::Match(derefValueParent, "[+-]")) {
if (derefValueParent->valueType() && derefValueParent->valueType()->pointer == 0)
break;
} else if (derefValueParent->str() == ".")
++deref;
derefValue = derefValue->astParent();
derefValue = derefValueParent;
if (deref < arrayDim)
valueExpr = derefValue;
}

View File

@ -79,6 +79,7 @@ public:
void checkStruct(const Token *tok, const Variable &structvar);
enum Alloc { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY };
bool checkScopeForVariable(const Token *tok, const Variable& var, bool* const possibleInit, bool* const noreturn, Alloc* const alloc, const std::string &membervar, std::map<nonneg int, VariableValue> variableValue);
const Token *checkExpr(const Token *tok, const Variable& var, const Alloc alloc, bool known, bool *bailout=nullptr);
bool checkIfForWhileHead(const Token *startparentheses, const Variable& var, bool suppressErrors, bool isuninit, Alloc alloc, const std::string &membervar);
bool checkLoopBody(const Token *tok, const Variable& var, const Alloc alloc, const std::string &membervar, const bool suppressErrors);
const Token* checkLoopBodyRecursive(const Token *start, const Variable& var, const Alloc alloc, const std::string &membervar, bool &bailout) const;

View File

@ -624,7 +624,7 @@ private:
" int a[10];\n"
" a[0] = 10 - a[1];\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a[1]\n", errout.str());
// goto/setjmp/longjmp..
checkUninitVar("void foo(int x)\n"
@ -1495,7 +1495,7 @@ private:
" char a[10];\n"
" a[a[0]] = 0;\n"
"}");
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a\n", "", errout.str());
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: a[0]\n", errout.str());
checkUninitVar("int f()\n"
"{\n"
@ -4944,7 +4944,7 @@ private:
" if (c->x() == 4) {}\n"
"}");
ASSERT_EQUALS("[test.cpp:6]: (error) Uninitialized variable: c\n", errout.str());
valueFlowUninit("struct A { \n"
" int i; \n"
" void f();\n"