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) { void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
mValues[expr] = 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 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); ValueFlow::Value v(value);
if (impossible) if (impossible)
v.setImpossible(); v.setImpossible();
mValues[expr] = v; setValue(expr, v);
} }
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const 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; v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
if (!isEqual) if (!isEqual)
v.valueKind = ValueFlow::Value::ValueKind::Impossible; v.valueKind = ValueFlow::Value::ValueKind::Impossible;
mValues[expr] = v; setValue(expr, v);
} }
void ProgramMemory::setUnknown(const Token* expr) { void ProgramMemory::setUnknown(const Token* expr) {

View File

@ -2936,38 +2936,43 @@ static Analyzer::Result valueFlowForwardExpression(Token* startToken,
return result; 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) if (!expr)
return nullptr; return nullptr;
if (!expr->astOperand1() || !expr->astOperand2()) if (!expr->astOperand1() || !expr->astOperand2())
return nullptr; return nullptr;
if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue()) if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
return nullptr; 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; return nullptr;
const Token* knownTok = nullptr;
const Token* varTok = nullptr; const Token* varTok = nullptr;
if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) { if (!x1.empty() && x2.empty()) {
varTok = expr->astOperand2(); varTok = expr->astOperand2();
knownTok = expr->astOperand1(); known = x1.front();
} else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) { } else if (x1.empty() && !x2.empty()) {
varTok = expr->astOperand1(); varTok = expr->astOperand1();
knownTok = expr->astOperand2(); known = x2.front();
} }
if (knownTok)
known = knownTok->values().front().intvalue;
return varTok; 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()) if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
return expr; return expr;
if (value.isSymbolicValue() && !Token::Match(expr, "+|-")) if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
return expr; return expr;
MathLib::bigint intval; MathLib::bigint intval;
const Token* binaryTok = parseBinaryIntOp(expr, intval); const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
bool rhs = astIsRHS(binaryTok); 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 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, "-")) 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]) { switch (expr->str()[0]) {
case '+': { case '+': {
value.intvalue -= intval; value.intvalue -= intval;
return solveExprValue(binaryTok, value); return solveExprValue(binaryTok, eval, value);
} }
case '-': { case '-': {
if (rhs) if (rhs)
value.intvalue = intval - value.intvalue; value.intvalue = intval - value.intvalue;
else else
value.intvalue += intval; value.intvalue += intval;
return solveExprValue(binaryTok, value); return solveExprValue(binaryTok, eval, value);
} }
case '*': { case '*': {
if (intval == 0) if (intval == 0)
break; break;
value.intvalue /= intval; value.intvalue /= intval;
return solveExprValue(binaryTok, value); return solveExprValue(binaryTok, eval, value);
} }
case '^': { case '^': {
value.intvalue ^= intval; value.intvalue ^= intval;
return solveExprValue(binaryTok, value); return solveExprValue(binaryTok, eval, value);
} }
} }
} }
return expr; 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) ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
{ {
const Token* expr = solveExprValue(exprTok, value); 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(); 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, std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
bool escape = false, bool escape = false,
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{}); ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});

View File

@ -3612,6 +3612,17 @@ private:
" int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n" " int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n"
"}"); "}");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str()); 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 void uninitStructMember() { // struct members