Uninitialized variables; check RHS expression
This commit is contained in:
parent
cc74c8e1da
commit
8adfcc848c
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue