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 { else {
if (tok->strAt(1) == "=") const Token *parent = tok;
checkRhs(tok, var, *alloc, number_of_if, emptyString); 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 // assume that variable is assigned
return true; return true;
@ -788,6 +805,32 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
return false; 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) 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(); const Token * const endpar = startparentheses->link();
@ -1059,16 +1102,23 @@ const Token* CheckUninitVar::isVariableUsage(const Token *vartok, bool pointer,
int deref = 0; int deref = 0;
derefValue = valueExpr; derefValue = valueExpr;
while (Token::Match(derefValue->astParent(), "+|-|*|[|.") || (derefValue->astParent() && derefValue->astParent()->isCast())) { while (Token::Match(derefValue->astParent(), "+|-|*|[|.") || (derefValue->astParent() && derefValue->astParent()->isCast())) {
if (derefValue->astParent()->isUnaryOp("*")) const Token * const derefValueParent = derefValue->astParent();
if (derefValueParent->str() == "*") {
if (derefValueParent->isUnaryOp("*"))
++deref; ++deref;
else if (derefValue->astParent()->str() == "[") { else
break;
} else if (derefValueParent->str() == "[") {
if (astIsLhs(derefValue)) if (astIsLhs(derefValue))
++deref; ++deref;
else else
break; break;
} else if (derefValue->astParent()->str() == ".") } else if (Token::Match(derefValueParent, "[+-]")) {
if (derefValueParent->valueType() && derefValueParent->valueType()->pointer == 0)
break;
} else if (derefValueParent->str() == ".")
++deref; ++deref;
derefValue = derefValue->astParent(); derefValue = derefValueParent;
if (deref < arrayDim) if (deref < arrayDim)
valueExpr = derefValue; valueExpr = derefValue;
} }

View File

@ -79,6 +79,7 @@ public:
void checkStruct(const Token *tok, const Variable &structvar); void checkStruct(const Token *tok, const Variable &structvar);
enum Alloc { NO_ALLOC, NO_CTOR_CALL, CTOR_CALL, ARRAY }; 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); 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 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); 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; 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" " int a[10];\n"
" a[0] = 10 - a[1];\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.. // goto/setjmp/longjmp..
checkUninitVar("void foo(int x)\n" checkUninitVar("void foo(int x)\n"
@ -1495,7 +1495,7 @@ private:
" char a[10];\n" " char a[10];\n"
" a[a[0]] = 0;\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" checkUninitVar("int f()\n"
"{\n" "{\n"