Fixed #7663 (False positive: uninitialized variable (multi variables in inner scopes))
This commit is contained in:
parent
120d0f86d0
commit
57004ed533
|
@ -124,12 +124,14 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set<std::string>
|
||||||
|
|
||||||
if (i->isArray()) {
|
if (i->isArray()) {
|
||||||
Alloc alloc = ARRAY;
|
Alloc alloc = ARRAY;
|
||||||
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, emptyString);
|
std::map<unsigned int, VariableValue> variableValue;
|
||||||
|
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, emptyString, variableValue);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stdtype || i->isPointer()) {
|
if (stdtype || i->isPointer()) {
|
||||||
Alloc alloc = NO_ALLOC;
|
Alloc alloc = NO_ALLOC;
|
||||||
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, emptyString);
|
std::map<unsigned int, VariableValue> variableValue;
|
||||||
|
checkScopeForVariable(tok, *i, nullptr, nullptr, &alloc, emptyString, variableValue);
|
||||||
}
|
}
|
||||||
if (i->type())
|
if (i->type())
|
||||||
checkStruct(tok, *i);
|
checkStruct(tok, *i);
|
||||||
|
@ -147,7 +149,8 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set<std::string>
|
||||||
checkStruct(tok, *arg);
|
checkStruct(tok, *arg);
|
||||||
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
|
else if (arg->typeStartToken()->isStandardType() || arg->typeStartToken()->isEnumType()) {
|
||||||
Alloc alloc = NO_ALLOC;
|
Alloc alloc = NO_ALLOC;
|
||||||
checkScopeForVariable(tok->next(), *arg, nullptr, nullptr, &alloc, emptyString);
|
std::map<unsigned int, VariableValue> variableValue;
|
||||||
|
checkScopeForVariable(tok->next(), *arg, nullptr, nullptr, &alloc, emptyString, variableValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,18 +191,14 @@ void CheckUninitVar::checkStruct(const Token *tok, const Variable &structvar)
|
||||||
const Token *tok2 = tok;
|
const Token *tok2 = tok;
|
||||||
if (tok->str() == "}")
|
if (tok->str() == "}")
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
checkScopeForVariable(tok2, structvar, nullptr, nullptr, &alloc, var.name());
|
std::map<unsigned int, VariableValue> variableValue;
|
||||||
|
checkScopeForVariable(tok2, structvar, nullptr, nullptr, &alloc, var.name(), variableValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct VariableValue {
|
|
||||||
explicit VariableValue(MathLib::bigint val = 0) : value(val), notEqual(false) {}
|
|
||||||
MathLib::bigint value;
|
|
||||||
bool notEqual;
|
|
||||||
};
|
|
||||||
static VariableValue operator!(VariableValue v)
|
static VariableValue operator!(VariableValue v)
|
||||||
{
|
{
|
||||||
v.notEqual = !v.notEqual;
|
v.notEqual = !v.notEqual;
|
||||||
|
@ -319,7 +318,7 @@ static bool isVariableUsed(const Token *tok, const Variable& var)
|
||||||
return !parent2 || parent2->isConstOp() || (parent2->str() == "=" && parent2->astOperand2() == parent);
|
return !parent2 || parent2->isConstOp() || (parent2->str() == "=" && parent2->astOperand2() == parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar)
|
bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var, bool * const possibleInit, bool * const noreturn, Alloc* const alloc, const std::string &membervar, std::map<unsigned int, VariableValue> variableValue)
|
||||||
{
|
{
|
||||||
const bool suppressErrors(possibleInit && *possibleInit);
|
const bool suppressErrors(possibleInit && *possibleInit);
|
||||||
const bool printDebug = _settings->debugwarnings;
|
const bool printDebug = _settings->debugwarnings;
|
||||||
|
@ -332,9 +331,6 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
|
||||||
if (var.declarationId() == 0U)
|
if (var.declarationId() == 0U)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// variable values
|
|
||||||
std::map<unsigned int, VariableValue> variableValue;
|
|
||||||
|
|
||||||
for (; tok; tok = tok->next()) {
|
for (; tok; tok = tok->next()) {
|
||||||
// End of scope..
|
// End of scope..
|
||||||
if (tok->str() == "}") {
|
if (tok->str() == "}") {
|
||||||
|
@ -353,7 +349,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
|
||||||
|
|
||||||
// Unconditional inner scope or try..
|
// Unconditional inner scope or try..
|
||||||
if (tok->str() == "{" && Token::Match(tok->previous(), ",|;|{|}|try")) {
|
if (tok->str() == "{" && Token::Match(tok->previous(), ",|;|{|}|try")) {
|
||||||
if (checkScopeForVariable(tok->next(), var, possibleInit, noreturn, alloc, membervar))
|
if (checkScopeForVariable(tok->next(), var, possibleInit, noreturn, alloc, membervar, variableValue))
|
||||||
return true;
|
return true;
|
||||||
tok = tok->link();
|
tok = tok->link();
|
||||||
continue;
|
continue;
|
||||||
|
@ -418,7 +414,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
|
||||||
if (tok->str() == "{") {
|
if (tok->str() == "{") {
|
||||||
bool possibleInitIf((!alwaysTrue && number_of_if > 0) || suppressErrors);
|
bool possibleInitIf((!alwaysTrue && number_of_if > 0) || suppressErrors);
|
||||||
bool noreturnIf = false;
|
bool noreturnIf = false;
|
||||||
const bool initif = !alwaysFalse && checkScopeForVariable(tok->next(), var, &possibleInitIf, &noreturnIf, alloc, membervar);
|
const bool initif = !alwaysFalse && checkScopeForVariable(tok->next(), var, &possibleInitIf, &noreturnIf, alloc, membervar, variableValue);
|
||||||
|
|
||||||
// bail out for such code:
|
// bail out for such code:
|
||||||
// if (a) x=0; // conditional initialization
|
// if (a) x=0; // conditional initialization
|
||||||
|
@ -468,7 +464,7 @@ bool CheckUninitVar::checkScopeForVariable(const Token *tok, const Variable& var
|
||||||
|
|
||||||
bool possibleInitElse((!alwaysFalse && number_of_if > 0) || suppressErrors);
|
bool possibleInitElse((!alwaysFalse && number_of_if > 0) || suppressErrors);
|
||||||
bool noreturnElse = false;
|
bool noreturnElse = false;
|
||||||
const bool initelse = !alwaysTrue && checkScopeForVariable(tok->next(), var, &possibleInitElse, &noreturnElse, alloc, membervar);
|
const bool initelse = !alwaysTrue && checkScopeForVariable(tok->next(), var, &possibleInitElse, &noreturnElse, alloc, membervar, variableValue);
|
||||||
|
|
||||||
std::map<unsigned int, VariableValue> varValueElse;
|
std::map<unsigned int, VariableValue> varValueElse;
|
||||||
if (!alwaysTrue && !initelse && !noreturnElse) {
|
if (!alwaysTrue && !initelse && !noreturnElse) {
|
||||||
|
|
|
@ -35,6 +35,13 @@ class Token;
|
||||||
class Tokenizer;
|
class Tokenizer;
|
||||||
class Variable;
|
class Variable;
|
||||||
|
|
||||||
|
|
||||||
|
struct VariableValue {
|
||||||
|
explicit VariableValue(MathLib::bigint val = 0) : value(val), notEqual(false) {}
|
||||||
|
MathLib::bigint value;
|
||||||
|
bool notEqual;
|
||||||
|
};
|
||||||
|
|
||||||
/// @addtogroup Checks
|
/// @addtogroup Checks
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
|
@ -65,7 +72,7 @@ public:
|
||||||
void checkScope(const Scope* scope, const std::set<std::string> &arrayTypeDefs);
|
void checkScope(const Scope* scope, const std::set<std::string> &arrayTypeDefs);
|
||||||
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);
|
bool checkScopeForVariable(const Token *tok, const Variable& var, bool* const possibleInit, bool* const noreturn, Alloc* const alloc, const std::string &membervar, std::map<unsigned int, VariableValue> variableValue);
|
||||||
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);
|
||||||
void checkRhs(const Token *tok, const Variable &var, Alloc alloc, unsigned int number_of_if, const std::string &membervar);
|
void checkRhs(const Token *tok, const Variable &var, Alloc alloc, unsigned int number_of_if, const std::string &membervar);
|
||||||
|
|
|
@ -2489,6 +2489,16 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkUninitVar("void f(int a) {\n"
|
||||||
|
" int x;\n"
|
||||||
|
" if (a) x=123;\n"
|
||||||
|
" if (!a) {\n"
|
||||||
|
" if (!a) {}\n"
|
||||||
|
" else if (x) {}\n"
|
||||||
|
" }\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
// asm
|
// asm
|
||||||
checkUninitVar("void f() {\n"
|
checkUninitVar("void f() {\n"
|
||||||
" int x;\n"
|
" int x;\n"
|
||||||
|
|
Loading…
Reference in New Issue