Fix 11009: FP uninitvar (#4076)

* Fix 11009: FP uninitvar

* Format
This commit is contained in:
Paul Fultz II 2022-05-03 22:59:01 -05:00 committed by GitHub
parent b444c002e2
commit 496b45f27b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 64 additions and 18 deletions

View File

@ -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) {

View File

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

View File

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

View File

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