parent
b444c002e2
commit
496b45f27b
|
@ -50,6 +50,20 @@ std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const
|
|||
|
||||
void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
|
||||
mValues[expr] = value;
|
||||
ValueFlow::Value subvalue = value;
|
||||
const Token* subexpr = solveExprValue(
|
||||
expr,
|
||||
[&](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||
if (tok->hasKnownIntValue())
|
||||
return {tok->values().front().intvalue};
|
||||
MathLib::bigint result = 0;
|
||||
if (getIntValue(tok->exprId(), &result))
|
||||
return {result};
|
||||
return {};
|
||||
},
|
||||
subvalue);
|
||||
if (subexpr)
|
||||
mValues[subexpr] = subvalue;
|
||||
}
|
||||
const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const
|
||||
{
|
||||
|
@ -77,7 +91,7 @@ void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool i
|
|||
ValueFlow::Value v(value);
|
||||
if (impossible)
|
||||
v.setImpossible();
|
||||
mValues[expr] = v;
|
||||
setValue(expr, v);
|
||||
}
|
||||
|
||||
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const
|
||||
|
@ -122,7 +136,7 @@ void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint val
|
|||
v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
|
||||
if (!isEqual)
|
||||
v.valueKind = ValueFlow::Value::ValueKind::Impossible;
|
||||
mValues[expr] = v;
|
||||
setValue(expr, v);
|
||||
}
|
||||
|
||||
void ProgramMemory::setUnknown(const Token* expr) {
|
||||
|
|
|
@ -2936,38 +2936,43 @@ static Analyzer::Result valueFlowForwardExpression(Token* startToken,
|
|||
return result;
|
||||
}
|
||||
|
||||
static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
|
||||
static const Token* parseBinaryIntOp(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
MathLib::bigint& known)
|
||||
{
|
||||
if (!expr)
|
||||
return nullptr;
|
||||
if (!expr->astOperand1() || !expr->astOperand2())
|
||||
return nullptr;
|
||||
if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue())
|
||||
if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
|
||||
return nullptr;
|
||||
if (expr->astOperand2()->exprId() == 0 && !expr->astOperand2()->hasKnownIntValue())
|
||||
std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
|
||||
std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
|
||||
if (expr->astOperand1()->exprId() == 0 && x1.empty())
|
||||
return nullptr;
|
||||
if (expr->astOperand2()->exprId() == 0 && x2.empty())
|
||||
return nullptr;
|
||||
const Token* knownTok = nullptr;
|
||||
const Token* varTok = nullptr;
|
||||
if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) {
|
||||
if (!x1.empty() && x2.empty()) {
|
||||
varTok = expr->astOperand2();
|
||||
knownTok = expr->astOperand1();
|
||||
} else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) {
|
||||
known = x1.front();
|
||||
} else if (x1.empty() && !x2.empty()) {
|
||||
varTok = expr->astOperand1();
|
||||
knownTok = expr->astOperand2();
|
||||
known = x2.front();
|
||||
}
|
||||
if (knownTok)
|
||||
known = knownTok->values().front().intvalue;
|
||||
return varTok;
|
||||
}
|
||||
|
||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||
const Token* solveExprValue(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
ValueFlow::Value& value)
|
||||
{
|
||||
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
|
||||
return expr;
|
||||
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
|
||||
return expr;
|
||||
MathLib::bigint intval;
|
||||
const Token* binaryTok = parseBinaryIntOp(expr, intval);
|
||||
const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
|
||||
bool rhs = astIsRHS(binaryTok);
|
||||
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
|
||||
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
|
||||
|
@ -2976,30 +2981,42 @@ static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
|||
switch (expr->str()[0]) {
|
||||
case '+': {
|
||||
value.intvalue -= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '-': {
|
||||
if (rhs)
|
||||
value.intvalue = intval - value.intvalue;
|
||||
else
|
||||
value.intvalue += intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '*': {
|
||||
if (intval == 0)
|
||||
break;
|
||||
value.intvalue /= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
case '^': {
|
||||
value.intvalue ^= intval;
|
||||
return solveExprValue(binaryTok, value);
|
||||
return solveExprValue(binaryTok, eval, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
|
||||
{
|
||||
return solveExprValue(
|
||||
expr,
|
||||
[](const Token* tok) -> std::vector<MathLib::bigint> {
|
||||
if (tok->hasKnownIntValue())
|
||||
return {tok->values().front().intvalue};
|
||||
return {};
|
||||
},
|
||||
value);
|
||||
}
|
||||
|
||||
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
|
||||
{
|
||||
const Token* expr = solveExprValue(exprTok, value);
|
||||
|
|
|
@ -503,6 +503,10 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math
|
|||
|
||||
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
|
||||
|
||||
const Token* solveExprValue(const Token* expr,
|
||||
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
|
||||
ValueFlow::Value& value);
|
||||
|
||||
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
|
||||
bool escape = false,
|
||||
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});
|
||||
|
|
|
@ -3612,6 +3612,17 @@ private:
|
|||
" int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str());
|
||||
|
||||
valueFlowUninit("void f(int height) {\n"
|
||||
" int a[11];\n"
|
||||
" int *p = a;\n"
|
||||
" int step = 2;\n"
|
||||
" for (int i = 0; i < (height * step); i += step)\n"
|
||||
" *p++ = 0;\n"
|
||||
" for (int i = 0; i < height; i++)\n"
|
||||
" if (a[i]) {}\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void uninitStructMember() { // struct members
|
||||
|
|
Loading…
Reference in New Issue