From 473266748847daa663021902a561a0f02f6ffe64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Nov 2016 22:33:39 +0100 Subject: [PATCH] ValueFlow: allow more value types --- lib/checkautovariables.cpp | 2 +- lib/checkbufferoverrun.cpp | 2 +- lib/checkio.cpp | 2 +- lib/token.cpp | 18 ++++----- lib/token.h | 6 +-- lib/valueflow.cpp | 80 ++++++++++++++++++++++++-------------- lib/valueflow.h | 29 +++++++++++--- 7 files changed, 89 insertions(+), 50 deletions(-) diff --git a/lib/checkautovariables.cpp b/lib/checkautovariables.cpp index f78b849bf..38edb76f4 100644 --- a/lib/checkautovariables.cpp +++ b/lib/checkautovariables.cpp @@ -121,7 +121,7 @@ bool CheckAutoVariables::isAutoVarArray(const Token *tok) if (var->isPointer() && !var->isArgument()) { for (std::list::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) { const ValueFlow::Value &val = *it; - if (val.tokvalue && isAutoVarArray(val.tokvalue)) + if (val.isTokValue() && isAutoVarArray(val.tokvalue)) return true; } } diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index c1092da49..d6341f6ef 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -1134,7 +1134,7 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable() continue; for (std::list::const_iterator it = tok->values.begin(); it != tok->values.end(); ++it) { - if (!it->tokvalue) + if (!it->isTokValue() || !it->tokvalue) continue; const Variable *var = it->tokvalue->variable(); if (var && var->isArray()) { diff --git a/lib/checkio.cpp b/lib/checkio.cpp index d22dd0ca2..77c015134 100644 --- a/lib/checkio.cpp +++ b/lib/checkio.cpp @@ -475,7 +475,7 @@ static bool findFormat(unsigned int arg, const Token *firstArg, argTok->variable()->dimensionKnown(0) && argTok->variable()->dimension(0) != 0))) { *formatArgTok = argTok->nextArgument(); - if (argTok->values.size() >= 1 && argTok->values.front().tokvalue && argTok->values.front().tokvalue->tokType() == Token::eString) + if (!argTok->values.empty() && argTok->values.front().isTokValue() && argTok->values.front().tokvalue && argTok->values.front().tokvalue->tokType() == Token::eString) *formatStringTok = argTok->values.front().tokvalue; return true; } diff --git a/lib/token.cpp b/lib/token.cpp index ba8d5c721..84dc469ac 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1325,9 +1325,9 @@ void Token::printValueFlow(bool xml, std::ostream &out) const for (std::list::const_iterator it=tok->values.begin(); it!=tok->values.end(); ++it) { if (xml) { out << " tokvalue) + if (it->isTokValue()) out << "tokvalue=\"" << it->tokvalue << '\"'; - else + else if (it->isIntValue()) out << "intvalue=\"" << it->intvalue << '\"'; if (it->condition) out << " condition-line=\"" << it->condition->linenr() << '\"'; @@ -1341,9 +1341,9 @@ void Token::printValueFlow(bool xml, std::ostream &out) const else { if (it != tok->values.begin()) out << ","; - if (it->tokvalue) + if (it->isTokValue()) out << it->tokvalue->str(); - else + else if (it->isIntValue()) out << it->intvalue; } } @@ -1363,7 +1363,7 @@ const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Sett const ValueFlow::Value *ret = nullptr; std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->intvalue <= val && !it->tokvalue) { + if (it->isIntValue() && it->intvalue <= val) { if (!ret || ret->inconclusive || (ret->condition && !it->inconclusive)) ret = &(*it); if (!ret->inconclusive && !ret->condition) @@ -1384,7 +1384,7 @@ const ValueFlow::Value * Token::getValueGE(const MathLib::bigint val, const Sett const ValueFlow::Value *ret = nullptr; std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->intvalue >= val && !it->tokvalue) { + if (it->isIntValue() && it->intvalue >= val) { if (!ret || ret->inconclusive || (ret->condition && !it->inconclusive)) ret = &(*it); if (!ret->inconclusive && !ret->condition) @@ -1406,7 +1406,7 @@ const Token *Token::getValueTokenMinStrSize() const std::size_t minsize = ~0U; std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->tokvalue && it->tokvalue->tokType() == Token::eString) { + if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) { std::size_t size = getStrSize(it->tokvalue); if (!ret || size < minsize) { minsize = size; @@ -1423,7 +1423,7 @@ const Token *Token::getValueTokenMaxStrLength() const std::size_t maxlength = 0U; std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->tokvalue && it->tokvalue->tokType() == Token::eString) { + if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) { std::size_t length = getStrLength(it->tokvalue); if (!ret || length > maxlength) { maxlength = length; @@ -1448,7 +1448,7 @@ const Token *Token::getValueTokenDeadPointer() const std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { // Is this a pointer alias? - if (!it->tokvalue || it->tokvalue->str() != "&") + if (!it->isTokValue() || (it->tokvalue && it->tokvalue->str() != "&")) continue; // Get variable const Token *vartok = it->tokvalue->astOperand1(); diff --git a/lib/token.h b/lib/token.h index 998c5d139..accb8485c 100644 --- a/lib/token.h +++ b/lib/token.h @@ -749,13 +749,13 @@ public: std::list values; bool hasKnownIntValue() const { - return values.size() == 1U && values.front().isKnown() && values.front().tokvalue == nullptr; + return values.size() == 1U && values.front().isKnown() && values.front().isIntValue(); } const ValueFlow::Value * getValue(const MathLib::bigint val) const { std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->intvalue == val && !it->tokvalue) + if (it->isIntValue() && it->intvalue == val) return &(*it); } return nullptr; @@ -765,7 +765,7 @@ public: const ValueFlow::Value *ret = nullptr; std::list::const_iterator it; for (it = values.begin(); it != values.end(); ++it) { - if (it->tokvalue) + if (!it->isIntValue()) continue; if ((!ret || it->intvalue > ret->intvalue) && ((it->condition != nullptr) == condition)) diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 0fd26562f..6f87c7f20 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -32,12 +32,15 @@ namespace { std::map tokvalues; void setValue(unsigned int varid, const ValueFlow::Value &value) { - if (value.tokvalue) { - intvalues.erase(varid); - tokvalues[varid] = value.tokvalue; - } else { + switch (value.valueType) { + case ValueFlow::Value::INT: intvalues[varid] = value.intvalue; tokvalues.erase(varid); + break; + case ValueFlow::Value::TOK: + intvalues.erase(varid); + tokvalues[varid] = value.tokvalue; + break; } } @@ -257,10 +260,10 @@ static bool addValue(Token *tok, const ValueFlow::Value &value) if (it->intvalue != value.intvalue) continue; - // different tokvalue => continue - if ((it->tokvalue == nullptr) != (value.tokvalue == nullptr)) + // different types => continue + if (it->valueType != value.valueType) continue; - if ((value.tokvalue != nullptr) && (it->tokvalue != value.tokvalue) && (it->tokvalue->str() != value.tokvalue->str())) + if (value.isTokValue() && (it->tokvalue != value.tokvalue) && (it->tokvalue->str() != value.tokvalue->str())) continue; // same value, but old value is inconclusive so replace it @@ -309,7 +312,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti // is condition always true/false? if (parent->astOperand1()->values.size() == 1U && parent->astOperand1()->values.front().isKnown()) { const ValueFlow::Value &condvalue = parent->astOperand1()->values.front(); - const bool cond(condvalue.tokvalue || condvalue.intvalue != 0); + const bool cond(condvalue.isTokValue() || (condvalue.isIntValue() && condvalue.intvalue != 0)); if (cond && !tok->astOperand1()) { // true condition, no second operator setTokenValue(parent, condvalue, settings); } else { @@ -361,20 +364,20 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti parent->astOperand2()->values.front().isKnown())); // known result when a operand is 0. - if (Token::Match(parent, "[&*]") && value.isKnown() && value.tokvalue==nullptr && value.intvalue==0) { + if (Token::Match(parent, "[&*]") && value.isKnown() && value.isIntValue() && value.intvalue==0) { setTokenValue(parent, value, settings); return; } std::list::const_iterator value1, value2; for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) { - if (value1->tokvalue && (!parent->isComparisonOp() || value1->tokvalue->tokType() != Token::eString)) + if (value1->isTokValue() && (!parent->isComparisonOp() || value1->tokvalue->tokType() != Token::eString)) continue; for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) { - if (value2->tokvalue && (!parent->isComparisonOp() || value2->tokvalue->tokType() != Token::eString || value1->tokvalue)) + if (value2->isTokValue() && (!parent->isComparisonOp() || value2->tokvalue->tokType() != Token::eString || value1->isTokValue())) continue; if (known || value1->varId == 0U || value2->varId == 0U || - (value1->varId == value2->varId && value1->varvalue == value2->varvalue && !value1->tokvalue && !value2->tokvalue)) { + (value1->varId == value2->varId && value1->varvalue == value2->varvalue && value1->isIntValue() && value2->isIntValue())) { ValueFlow::Value result(0); result.condition = value1->condition ? value1->condition : value2->condition; result.inconclusive = value1->inconclusive | value2->inconclusive; @@ -409,24 +412,30 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti break; case '=': if (parent->str() == "==") { - if (value1->tokvalue || value2->tokvalue) + if ((value1->isIntValue() && value2->isTokValue()) || + (value1->isTokValue() && value2->isIntValue())) { result.intvalue = 0; - else + setTokenValue(parent, result, settings); + } else if (value1->isIntValue() && value2->isIntValue()) { result.intvalue = value1->intvalue == value2->intvalue; - setTokenValue(parent, result, settings); + setTokenValue(parent, result, settings); + } } break; case '!': if (parent->str() == "!=") { - if (value1->tokvalue || value2->tokvalue) + if ((value1->isIntValue() && value2->isTokValue()) || + (value1->isTokValue() && value2->isIntValue())) { result.intvalue = 1; - else + setTokenValue(parent, result, settings); + } else if (value1->isIntValue() && value2->isIntValue()) { result.intvalue = value1->intvalue != value2->intvalue; - setTokenValue(parent, result, settings); + setTokenValue(parent, result, settings); + } } break; case '>': - if (value1->tokvalue || value2->tokvalue) + if (!value1->isIntValue() || !value2->isIntValue()) break; if (parent->str() == ">") result.intvalue = value1->intvalue > value2->intvalue; @@ -439,7 +448,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti setTokenValue(parent, result, settings); break; case '<': - if (value1->tokvalue || value2->tokvalue) + if (!value1->isIntValue() || !value2->isIntValue()) break; if (parent->str() == "<") result.intvalue = value1->intvalue < value2->intvalue; @@ -452,6 +461,8 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti setTokenValue(parent, result, settings); break; case '&': + if (!value1->isIntValue() || !value2->isIntValue()) + break; if (parent->str() == "&") result.intvalue = value1->intvalue & value2->intvalue; else @@ -459,6 +470,8 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti setTokenValue(parent, result, settings); break; case '|': + if (!value1->isIntValue() || !value2->isIntValue()) + break; if (parent->str() == "|") result.intvalue = value1->intvalue | value2->intvalue; else @@ -466,6 +479,8 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti setTokenValue(parent, result, settings); break; case '^': + if (!value1->isIntValue() || !value2->isIntValue()) + break; result.intvalue = value1->intvalue ^ value2->intvalue; setTokenValue(parent, result, settings); break; @@ -482,7 +497,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti else if (parent->str() == "!") { std::list::const_iterator it; for (it = tok->values.begin(); it != tok->values.end(); ++it) { - if (it->tokvalue) + if (!it->isIntValue()) continue; ValueFlow::Value v(*it); v.intvalue = !v.intvalue; @@ -494,7 +509,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti else if (parent->str() == "~") { std::list::const_iterator it; for (it = tok->values.begin(); it != tok->values.end(); ++it) { - if (it->tokvalue) + if (!it->isIntValue()) continue; ValueFlow::Value v(*it); v.intvalue = ~v.intvalue; @@ -518,7 +533,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti else if (parent->str() == "-" && !parent->astOperand2()) { std::list::const_iterator it; for (it = tok->values.begin(); it != tok->values.end(); ++it) { - if (it->tokvalue) + if (!it->isIntValue()) continue; ValueFlow::Value v(*it); v.intvalue = -v.intvalue; @@ -530,10 +545,10 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti else if (parent->str() == "[" && parent->astOperand1() && parent->astOperand2()) { std::list::const_iterator value1, value2; for (value1 = parent->astOperand1()->values.begin(); value1 != parent->astOperand1()->values.end(); ++value1) { - if (!value1->tokvalue) + if (!value1->isTokValue()) continue; for (value2 = parent->astOperand2()->values.begin(); value2 != parent->astOperand2()->values.end(); ++value2) { - if (value2->tokvalue) + if (!value2->isIntValue()) continue; if (value1->varId == 0U || value2->varId == 0U || (value1->varId == value2->varId && value1->varvalue == value2->varvalue)) { @@ -659,6 +674,7 @@ static void valueFlowString(TokenList *tokenlist) for (Token *tok = tokenlist->front(); tok; tok = tok->next()) { if (tok->tokType() == Token::eString) { ValueFlow::Value strvalue; + strvalue.valueType = ValueFlow::Value::TOK; strvalue.tokvalue = tok; strvalue.setKnown(); setTokenValue(tok, strvalue, tokenlist->getSettings()); @@ -675,6 +691,7 @@ static void valueFlowArray(TokenList *tokenlist) const std::map::const_iterator it = constantArrays.find(tok->varId()); if (it != constantArrays.end()) { ValueFlow::Value value; + value.valueType = ValueFlow::Value::TOK; value.tokvalue = it->second; value.setKnown(); setTokenValue(tok, value, tokenlist->getSettings()); @@ -689,6 +706,7 @@ static void valueFlowArray(TokenList *tokenlist) tok->astParent()->astOperand1()->variable() && tok->astParent()->astOperand1()->variable()->isPointer()) { ValueFlow::Value value; + value.valueType = ValueFlow::Value::TOK; value.tokvalue = tok; value.setKnown(); setTokenValue(tok, value, tokenlist->getSettings()); @@ -739,6 +757,7 @@ static void valueFlowPointerAlias(TokenList *tokenlist) continue; ValueFlow::Value value; + value.valueType = ValueFlow::Value::TOK; value.tokvalue = tok; setTokenValue(tok, value, tokenlist->getSettings()); } @@ -1463,7 +1482,7 @@ static bool valueFlowForward(Token * const startToken, if (!condition || !op2) // Ticket #6713 continue; - if (condition->values.size() == 1U && condition->values.front().isKnown() && !condition->values.front().tokvalue) { + if (condition->hasKnownIntValue()) { const ValueFlow::Value &condValue = condition->values.front(); const Token *expr = (condValue.intvalue != 0) ? op2->astOperand1() : op2->astOperand2(); std::list::const_iterator it; @@ -1561,7 +1580,7 @@ static bool valueFlowForward(Token * const startToken, std::list::iterator it; // Erase values that are not int values.. for (it = values.begin(); it != values.end();) { - if (it->tokvalue) + if (!it->isIntValue()) it = values.erase(it); else ++it; @@ -1850,7 +1869,7 @@ static void execute(const Token *expr, if (!expr) *error = true; - else if (expr->values.size() == 1U && expr->values.front().isKnown() && !expr->values.front().tokvalue) { + else if (expr->hasKnownIntValue()) { *result = expr->values.front().intvalue; } @@ -2316,7 +2335,7 @@ static void setTokenValues(Token *tok, const std::list &values { for (std::list::const_iterator it = values.begin(); it != values.end(); ++it) { const ValueFlow::Value &value = *it; - if (!value.tokvalue) + if (value.isIntValue()) setTokenValue(tok, value, settings); } } @@ -2337,9 +2356,10 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue, if (Token::simpleMatch(tokenList.front(), "strlen ( arg1 )") && arg1) { for (std::list::const_iterator it = arg1->values.begin(); it != arg1->values.end(); ++it) { const ValueFlow::Value &value = *it; - if (value.tokvalue && value.tokvalue->tokType() == Token::eString) { + if (value.isTokValue() && value.tokvalue->tokType() == Token::eString) { ValueFlow::Value retval(value); // copy all "inconclusive", "condition", etc attributes // set return value.. + retval.valueType = ValueFlow::Value::INT; retval.tokvalue = nullptr; retval.intvalue = Token::getStrLength(value.tokvalue); setTokenValue(tok, retval, settings); diff --git a/lib/valueflow.h b/lib/valueflow.h index f849266ed..4b7b6eee2 100644 --- a/lib/valueflow.h +++ b/lib/valueflow.h @@ -33,13 +33,24 @@ class Settings; namespace ValueFlow { class CPPCHECKLIB Value { public: - explicit Value(long long val = 0) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} - Value(const Token *c, long long val) : intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} + explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), varvalue(val), condition(0), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} + Value(const Token *c, long long val) : valueType(INT), intvalue(val), tokvalue(nullptr), varvalue(val), condition(c), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {} bool operator==(const Value &rhs) const { - return intvalue == rhs.intvalue && - tokvalue == rhs.tokvalue && - varvalue == rhs.varvalue && + if (valueType != rhs.valueType) + return false; + switch (valueType) { + case INT: + if (intvalue != rhs.intvalue) + return false; + break; + case TOK: + if (tokvalue != rhs.tokvalue) + return false; + break; + }; + + return varvalue == rhs.varvalue && condition == rhs.condition && varId == rhs.varId && conditional == rhs.conditional && @@ -48,6 +59,14 @@ namespace ValueFlow { valueKind == rhs.valueKind; } + enum ValueType { INT, TOK } valueType; + bool isIntValue() const { + return valueType == INT; + } + bool isTokValue() const { + return valueType == TOK; + } + /** int value */ long long intvalue;