ValueFlow: allow more value types

This commit is contained in:
Daniel Marjamäki 2016-11-13 22:33:39 +01:00
parent 7ebfb10edd
commit 4732667488
7 changed files with 89 additions and 50 deletions

View File

@ -121,7 +121,7 @@ bool CheckAutoVariables::isAutoVarArray(const Token *tok)
if (var->isPointer() && !var->isArgument()) {
for (std::list<ValueFlow::Value>::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;
}
}

View File

@ -1134,7 +1134,7 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
continue;
for (std::list<ValueFlow::Value>::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()) {

View File

@ -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;
}

View File

@ -1325,9 +1325,9 @@ void Token::printValueFlow(bool xml, std::ostream &out) const
for (std::list<ValueFlow::Value>::const_iterator it=tok->values.begin(); it!=tok->values.end(); ++it) {
if (xml) {
out << " <value ";
if (it->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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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();

View File

@ -749,13 +749,13 @@ public:
std::list<ValueFlow::Value> 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<ValueFlow::Value>::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<ValueFlow::Value>::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))

View File

@ -32,12 +32,15 @@ namespace {
std::map<unsigned int, const Token *> 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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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<ValueFlow::Value>::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<unsigned int, const Token *>::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<ValueFlow::Value>::const_iterator it;
@ -1561,7 +1580,7 @@ static bool valueFlowForward(Token * const startToken,
std::list<ValueFlow::Value>::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<ValueFlow::Value> &values
{
for (std::list<ValueFlow::Value>::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<ValueFlow::Value>::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);

View File

@ -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;