ValueFlow: Put 'inconclusive' state in the ValueKind. A value can't be both known and inconclusive.

This commit is contained in:
Daniel Marjamäki 2017-09-20 22:41:36 +02:00
parent e61222126f
commit ba8222de1c
11 changed files with 54 additions and 50 deletions

View File

@ -86,7 +86,7 @@ void CheckBufferOverrun::arrayIndexOutOfBoundsError(const Token *tok, const Arra
bool inconclusive = false;
const Token *condition = nullptr;
for (std::size_t i = 0; i < index.size(); ++i) {
inconclusive |= index[i].inconclusive;
inconclusive |= index[i].isInconclusive();
if (condition == nullptr)
condition = index[i].condition;
}
@ -1805,7 +1805,7 @@ void CheckBufferOverrun::negativeIndexError(const Token *tok, const ValueFlow::V
<< ", otherwise there is negative array index " << index.intvalue << ".";
else
errmsg << "Array index " << index.intvalue << " is out of bounds.";
reportError(errorPath, index.errorSeverity() ? Severity::error : Severity::warning, "negativeIndex", errmsg.str(), CWE786, index.inconclusive);
reportError(errorPath, index.errorSeverity() ? Severity::error : Severity::warning, "negativeIndex", errmsg.str(), CWE786, index.isInconclusive());
}
CheckBufferOverrun::ArrayInfo::ArrayInfo()

View File

@ -149,7 +149,7 @@ void CheckFunctions::invalidFunctionArgError(const Token *tok, const std::string
"invalidFunctionArg",
errmsg.str(),
CWE628,
invalidValue->inconclusive);
invalidValue->isInconclusive());
else
reportError(tok,
Severity::error,

View File

@ -334,7 +334,7 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
if (!value)
continue;
if (!printInconclusive && value->inconclusive)
if (!printInconclusive && value->isInconclusive())
continue;
// Is pointer used as function parameter?
@ -350,7 +350,7 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
std::list<const Token *> varlist;
parseFunctionCall(*ftok->previous(), varlist, &_settings->library);
if (std::find(varlist.begin(), varlist.end(), tok) != varlist.end()) {
nullPointerError(tok, tok->str(), value, value->inconclusive);
nullPointerError(tok, tok->str(), value, value->isInconclusive());
}
continue;
}
@ -363,7 +363,7 @@ void CheckNullPointer::nullPointerByDeRefAndChec()
continue;
}
nullPointerError(tok, tok->str(), value, value->inconclusive);
nullPointerError(tok, tok->str(), value, value->isInconclusive());
}
}
@ -485,9 +485,9 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var
const ErrorPath errorPath = getErrorPath(tok, value, "Null pointer dereference");
if (value->condition) {
reportError(errorPath, Severity::warning, "nullPointerRedundantCheck", errmsgcond, CWE476, inconclusive || value->inconclusive);
reportError(errorPath, Severity::warning, "nullPointerRedundantCheck", errmsgcond, CWE476, inconclusive || value->isInconclusive());
} else if (value->defaultArg) {
reportError(errorPath, Severity::warning, "nullPointerDefaultArg", errmsgdefarg, CWE476, inconclusive || value->inconclusive);
reportError(errorPath, Severity::warning, "nullPointerDefaultArg", errmsgdefarg, CWE476, inconclusive || value->isInconclusive());
} else {
std::string errmsg;
errmsg = std::string(value->isKnown() ? "Null" : "Possible null") + " pointer dereference";
@ -498,7 +498,7 @@ void CheckNullPointer::nullPointerError(const Token *tok, const std::string &var
value->isKnown() ? Severity::error : Severity::warning,
"nullPointer",
errmsg,
CWE476, inconclusive || value->inconclusive);
CWE476, inconclusive || value->isInconclusive());
}
}
@ -518,7 +518,7 @@ void CheckNullPointer::arithmetic()
const ValueFlow::Value *value = tok->astOperand1()->getValue(0);
if (!value)
continue;
if (!_settings->inconclusive && value->inconclusive)
if (!_settings->inconclusive && value->isInconclusive())
continue;
if (value->condition && !_settings->isEnabled(Settings::WARNING))
continue;
@ -545,6 +545,6 @@ void CheckNullPointer::arithmeticError(const Token *tok, const ValueFlow::Value
(value && value->condition) ? "nullPointerArithmeticRedundantCheck" : "nullPointerArithmetic",
errmsg,
CWE682, // unknown - pointer overflow
value && value->inconclusive);
value && value->isInconclusive());
}

View File

@ -1678,7 +1678,7 @@ void CheckOther::zerodivError(const Token *tok, const ValueFlow::Value *value)
reportError(errorPath,
value->errorSeverity() ? Severity::error : Severity::warning,
value->condition ? "zerodivcond" : "zerodiv",
errmsg.str(), CWE369, value->inconclusive);
errmsg.str(), CWE369, value->isInconclusive());
}
//---------------------------------------------------------------------------
@ -2644,7 +2644,7 @@ void CheckOther::checkAccessOfMovedVariable()
const ValueFlow::Value * movedValue = tok->getMovedValue();
if (!movedValue || movedValue->moveKind == ValueFlow::Value::NonMovedVariable)
continue;
if (movedValue->inconclusive && !reportInconclusive)
if (movedValue->isInconclusive() && !reportInconclusive)
continue;
bool inconclusive = false;
@ -2664,7 +2664,7 @@ void CheckOther::checkAccessOfMovedVariable()
}
}
if (accessOfMoved || (inconclusive && reportInconclusive))
accessMovedError(tok, tok->str(), movedValue->moveKind, inconclusive || movedValue->inconclusive);
accessMovedError(tok, tok->str(), movedValue->moveKind, inconclusive || movedValue->isInconclusive());
}
}
}

View File

@ -474,7 +474,7 @@ void CheckStl::negativeIndexError(const Token *tok, const ValueFlow::Value &inde
<< ", otherwise there is negative array index " << index.intvalue << ".";
else
errmsg << "Array index " << index.intvalue << " is out of bounds.";
reportError(errorPath, index.errorSeverity() ? Severity::error : Severity::warning, "negativeContainerIndex", errmsg.str(), CWE786, index.inconclusive);
reportError(errorPath, index.errorSeverity() ? Severity::error : Severity::warning, "negativeContainerIndex", errmsg.str(), CWE786, index.isInconclusive());
}
void CheckStl::erase()

View File

@ -110,7 +110,7 @@ void CheckType::tooBigBitwiseShiftError(const Token *tok, int lhsbits, const Val
if (rhsbits.condition)
errmsg << ". See condition at line " << rhsbits.condition->linenr() << ".";
reportError(errorPath, rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.inconclusive);
reportError(errorPath, rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.isInconclusive());
}
void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, const ValueFlow::Value &rhsbits)
@ -129,7 +129,7 @@ void CheckType::tooBigSignedBitwiseShiftError(const Token *tok, int lhsbits, con
if (rhsbits.condition)
errmsg << ". See condition at line " << rhsbits.condition->linenr() << ".";
reportError(errorPath, rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.inconclusive);
reportError(errorPath, rhsbits.errorSeverity() ? Severity::error : Severity::warning, id, errmsg.str(), CWE758, rhsbits.isInconclusive());
}
//---------------------------------------------------------------------------
@ -198,7 +198,7 @@ void CheckType::integerOverflowError(const Token *tok, const ValueFlow::Value &v
"integerOverflow",
msg,
CWE190,
value.inconclusive);
value.isInconclusive());
}
//---------------------------------------------------------------------------
@ -410,5 +410,5 @@ void CheckType::floatToIntegerOverflowError(const Token *tok, const ValueFlow::V
reportError(getErrorPath(tok, &value, "float to integer conversion"),
value.errorSeverity() ? Severity::error : Severity::warning,
"floatConversionOverflow",
errmsg.str(), CWE190, value.inconclusive);
errmsg.str(), CWE190, value.isInconclusive());
}

View File

@ -1238,7 +1238,7 @@ void CheckUninitVar::valueFlowUninit()
if (!tok->variable() || tok->values().size() != 1U)
continue;
const ValueFlow::Value &v = tok->values().front();
if (v.valueType != ValueFlow::Value::UNINIT || v.inconclusive)
if (v.valueType != ValueFlow::Value::UNINIT || v.isInconclusive())
continue;
if (!isVariableUsage(tok, tok->variable()->isPointer(), NO_ALLOC))
continue;

View File

@ -131,7 +131,7 @@ bool Settings::isEnabled(const ValueFlow::Value *value, bool inconclusiveCheck)
{
if (!isEnabled(Settings::WARNING) && (value->condition || value->defaultArg))
return false;
if (!inconclusive && (inconclusiveCheck || value->inconclusive))
if (!inconclusive && (inconclusiveCheck || value->isInconclusive()))
return false;
return true;
}

View File

@ -1362,6 +1362,8 @@ void Token::printValueFlow(bool xml, std::ostream &out) const
out << " known=\"true\"";
else if (it->isPossible())
out << " possible=\"true\"";
else if (it->isInconclusive())
out << " inconclusive=\"true\"";
out << "/>" << std::endl;
}
@ -1409,14 +1411,14 @@ const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Sett
std::list<ValueFlow::Value>::const_iterator it;
for (it = _values->begin(); it != _values->end(); ++it) {
if (it->isIntValue() && it->intvalue <= val) {
if (!ret || ret->inconclusive || (ret->condition && !it->inconclusive))
if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive()))
ret = &(*it);
if (!ret->inconclusive && !ret->condition)
if (!ret->isInconclusive() && !ret->condition)
break;
}
}
if (settings && ret) {
if (ret->inconclusive && !settings->inconclusive)
if (ret->isInconclusive() && !settings->inconclusive)
return nullptr;
if (ret->condition && !settings->isEnabled(Settings::WARNING))
return nullptr;
@ -1432,14 +1434,14 @@ const ValueFlow::Value * Token::getValueGE(const MathLib::bigint val, const Sett
std::list<ValueFlow::Value>::const_iterator it;
for (it = _values->begin(); it != _values->end(); ++it) {
if (it->isIntValue() && it->intvalue >= val) {
if (!ret || ret->inconclusive || (ret->condition && !it->inconclusive))
if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive()))
ret = &(*it);
if (!ret->inconclusive && !ret->condition)
if (!ret->isInconclusive() && !ret->condition)
break;
}
}
if (settings && ret) {
if (ret->inconclusive && !settings->inconclusive)
if (ret->isInconclusive() && !settings->inconclusive)
return nullptr;
if (ret->condition && !settings->isEnabled(Settings::WARNING))
return nullptr;
@ -1455,14 +1457,14 @@ const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, unsigned int
std::list<ValueFlow::Value>::const_iterator it;
for (it = _values->begin(); it != _values->end(); ++it) {
if (it->isIntValue() && !settings->library.isargvalid(ftok, argnr, it->intvalue)) {
if (!ret || ret->inconclusive || (ret->condition && !it->inconclusive))
if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive()))
ret = &(*it);
if (!ret->inconclusive && !ret->condition)
if (!ret->isInconclusive() && !ret->condition)
break;
}
}
if (settings && ret) {
if (ret->inconclusive && !settings->inconclusive)
if (ret->isInconclusive() && !settings->inconclusive)
return nullptr;
if (ret->condition && !settings->isEnabled(Settings::WARNING))
return nullptr;
@ -1575,7 +1577,7 @@ bool Token::addValue(const ValueFlow::Value &value)
continue;
// same value, but old value is inconclusive so replace it
if (it->inconclusive && !value.inconclusive) {
if (it->isInconclusive() && !value.isInconclusive()) {
*it = value;
if (it->varId == 0)
it->varId = _varId;

View File

@ -382,7 +382,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
(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;
result.setInconclusive(value1->isInconclusive() | value2->isInconclusive());
result.varId = (value1->varId != 0U) ? value1->varId : value2->varId;
result.varvalue = (result.varId == value1->varId) ? value1->varvalue : value2->varvalue;
result.errorPath = (value1->errorPath.empty() ? value2 : value1)->errorPath;
@ -593,7 +593,7 @@ static void setTokenValue(Token* tok, const ValueFlow::Value &value, const Setti
(value1->varId == value2->varId && value1->varvalue == value2->varvalue)) {
ValueFlow::Value result(0);
result.condition = value1->condition ? value1->condition : value2->condition;
result.inconclusive = value1->inconclusive | value2->inconclusive;
result.setInconclusive(value1->isInconclusive() | value2->isInconclusive());
result.varId = (value1->varId != 0U) ? value1->varId : value2->varId;
result.varvalue = (result.varId == value1->varId) ? value1->intvalue : value2->intvalue;
if (value1->valueKind == value2->valueKind)
@ -1080,8 +1080,8 @@ static void valueFlowReverse(TokenList *tokenlist,
bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by subfunction");
break;
}
val.inconclusive |= inconclusive;
val2.inconclusive |= inconclusive;
val.setInconclusive(inconclusive);
val2.setInconclusive(inconclusive);
// skip if variable is conditionally used in ?: expression
if (const Token *parent = skipValueInConditionalExpression(tok2)) {
@ -1989,18 +1989,14 @@ static bool valueFlowForward(Token * const startToken,
}
if (inconclusive) {
std::list<ValueFlow::Value>::iterator it;
for (it = values.begin(); it != values.end(); ++it) {
it->inconclusive = true;
it->changeKnownToPossible();
}
for (it = values.begin(); it != values.end(); ++it)
it->setInconclusive();
}
if (tok2->strAt(1) == "." && tok2->next()->originalName() != "->") {
if (settings->inconclusive) {
std::list<ValueFlow::Value>::iterator it;
for (it = values.begin(); it != values.end(); ++it) {
it->inconclusive = true;
it->changeKnownToPossible();
}
for (it = values.begin(); it != values.end(); ++it)
it->setInconclusive();
} else {
if (settings->debugwarnings)
bailout(tokenlist, errorLogger, tok2, "possible assignment of " + tok2->str() + " by member function");
@ -3176,7 +3172,6 @@ ValueFlow::Value::Value(const Token *c, long long val)
condition(c),
varId(0U),
conditional(false),
inconclusive(false),
defaultArg(false),
valueKind(ValueKind::Possible)
{

View File

@ -39,7 +39,7 @@ namespace ValueFlow {
typedef std::pair<const Token *, std::string> ErrorPathItem;
typedef std::list<ErrorPathItem> ErrorPath;
explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(nullptr), varId(0U), conditional(false), inconclusive(false), defaultArg(false), valueKind(ValueKind::Possible) {}
explicit Value(long long val = 0) : valueType(INT), intvalue(val), tokvalue(nullptr), floatValue(0.0), moveKind(NonMovedVariable), varvalue(val), condition(nullptr), varId(0U), conditional(false), defaultArg(false), valueKind(ValueKind::Possible) {}
Value(const Token *c, long long val);
bool operator==(const Value &rhs) const {
@ -71,7 +71,6 @@ namespace ValueFlow {
condition == rhs.condition &&
varId == rhs.varId &&
conditional == rhs.conditional &&
inconclusive == rhs.inconclusive &&
defaultArg == rhs.defaultArg &&
valueKind == rhs.valueKind;
}
@ -121,9 +120,6 @@ namespace ValueFlow {
/** Conditional value */
bool conditional;
/** Is this value inconclusive? */
bool inconclusive;
/** Is this value passed as default parameter to the function? */
bool defaultArg;
@ -144,7 +140,9 @@ namespace ValueFlow {
/** This value is possible, other unlisted values may also be possible */
Possible,
/** Only listed values are possible */
Known
Known,
/** Inconclusive */
Inconclusive
} valueKind;
void setKnown() {
@ -163,6 +161,15 @@ namespace ValueFlow {
return valueKind == ValueKind::Possible;
}
void setInconclusive(bool inconclusive = true) {
if (inconclusive)
valueKind = ValueKind::Inconclusive;
}
bool isInconclusive() const {
return valueKind == ValueKind::Inconclusive;
}
void changeKnownToPossible() {
if (isKnown())
valueKind = ValueKind::Possible;