Skip to content

Commit 496b45f

Browse files
authored
Fix 11009: FP uninitvar (#4076)
* Fix 11009: FP uninitvar * Format
1 parent b444c00 commit 496b45f

4 files changed

Lines changed: 64 additions & 18 deletions

File tree

lib/programmemory.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,20 @@ std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const
5050

5151
void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) {
5252
mValues[expr] = value;
53+
ValueFlow::Value subvalue = value;
54+
const Token* subexpr = solveExprValue(
55+
expr,
56+
[&](const Token* tok) -> std::vector<MathLib::bigint> {
57+
if (tok->hasKnownIntValue())
58+
return {tok->values().front().intvalue};
59+
MathLib::bigint result = 0;
60+
if (getIntValue(tok->exprId(), &result))
61+
return {result};
62+
return {};
63+
},
64+
subvalue);
65+
if (subexpr)
66+
mValues[subexpr] = subvalue;
5367
}
5468
const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const
5569
{
@@ -77,7 +91,7 @@ void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool i
7791
ValueFlow::Value v(value);
7892
if (impossible)
7993
v.setImpossible();
80-
mValues[expr] = v;
94+
setValue(expr, v);
8195
}
8296

8397
bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const
@@ -122,7 +136,7 @@ void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint val
122136
v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE;
123137
if (!isEqual)
124138
v.valueKind = ValueFlow::Value::ValueKind::Impossible;
125-
mValues[expr] = v;
139+
setValue(expr, v);
126140
}
127141

128142
void ProgramMemory::setUnknown(const Token* expr) {

lib/valueflow.cpp

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2936,38 +2936,43 @@ static Analyzer::Result valueFlowForwardExpression(Token* startToken,
29362936
return result;
29372937
}
29382938

2939-
static const Token* parseBinaryIntOp(const Token* expr, MathLib::bigint& known)
2939+
static const Token* parseBinaryIntOp(const Token* expr,
2940+
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
2941+
MathLib::bigint& known)
29402942
{
29412943
if (!expr)
29422944
return nullptr;
29432945
if (!expr->astOperand1() || !expr->astOperand2())
29442946
return nullptr;
2945-
if (expr->astOperand1()->exprId() == 0 && !expr->astOperand1()->hasKnownIntValue())
2947+
if (expr->astOperand1()->exprId() == 0 && expr->astOperand2()->exprId() == 0)
29462948
return nullptr;
2947-
if (expr->astOperand2()->exprId() == 0 && !expr->astOperand2()->hasKnownIntValue())
2949+
std::vector<MathLib::bigint> x1 = eval(expr->astOperand1());
2950+
std::vector<MathLib::bigint> x2 = eval(expr->astOperand2());
2951+
if (expr->astOperand1()->exprId() == 0 && x1.empty())
2952+
return nullptr;
2953+
if (expr->astOperand2()->exprId() == 0 && x2.empty())
29482954
return nullptr;
2949-
const Token* knownTok = nullptr;
29502955
const Token* varTok = nullptr;
2951-
if (expr->astOperand1()->hasKnownIntValue() && !expr->astOperand2()->hasKnownIntValue()) {
2956+
if (!x1.empty() && x2.empty()) {
29522957
varTok = expr->astOperand2();
2953-
knownTok = expr->astOperand1();
2954-
} else if (expr->astOperand2()->hasKnownIntValue() && !expr->astOperand1()->hasKnownIntValue()) {
2958+
known = x1.front();
2959+
} else if (x1.empty() && !x2.empty()) {
29552960
varTok = expr->astOperand1();
2956-
knownTok = expr->astOperand2();
2961+
known = x2.front();
29572962
}
2958-
if (knownTok)
2959-
known = knownTok->values().front().intvalue;
29602963
return varTok;
29612964
}
29622965

2963-
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
2966+
const Token* solveExprValue(const Token* expr,
2967+
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
2968+
ValueFlow::Value& value)
29642969
{
29652970
if (!value.isIntValue() && !value.isIteratorValue() && !value.isSymbolicValue())
29662971
return expr;
29672972
if (value.isSymbolicValue() && !Token::Match(expr, "+|-"))
29682973
return expr;
29692974
MathLib::bigint intval;
2970-
const Token* binaryTok = parseBinaryIntOp(expr, intval);
2975+
const Token* binaryTok = parseBinaryIntOp(expr, eval, intval);
29712976
bool rhs = astIsRHS(binaryTok);
29722977
// If its on the rhs, then -1 multiplication is needed, which is not possible with simple delta analysis used currently for symbolic values
29732978
if (value.isSymbolicValue() && rhs && Token::simpleMatch(expr, "-"))
@@ -2976,30 +2981,42 @@ static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
29762981
switch (expr->str()[0]) {
29772982
case '+': {
29782983
value.intvalue -= intval;
2979-
return solveExprValue(binaryTok, value);
2984+
return solveExprValue(binaryTok, eval, value);
29802985
}
29812986
case '-': {
29822987
if (rhs)
29832988
value.intvalue = intval - value.intvalue;
29842989
else
29852990
value.intvalue += intval;
2986-
return solveExprValue(binaryTok, value);
2991+
return solveExprValue(binaryTok, eval, value);
29872992
}
29882993
case '*': {
29892994
if (intval == 0)
29902995
break;
29912996
value.intvalue /= intval;
2992-
return solveExprValue(binaryTok, value);
2997+
return solveExprValue(binaryTok, eval, value);
29932998
}
29942999
case '^': {
29953000
value.intvalue ^= intval;
2996-
return solveExprValue(binaryTok, value);
3001+
return solveExprValue(binaryTok, eval, value);
29973002
}
29983003
}
29993004
}
30003005
return expr;
30013006
}
30023007

3008+
static const Token* solveExprValue(const Token* expr, ValueFlow::Value& value)
3009+
{
3010+
return solveExprValue(
3011+
expr,
3012+
[](const Token* tok) -> std::vector<MathLib::bigint> {
3013+
if (tok->hasKnownIntValue())
3014+
return {tok->values().front().intvalue};
3015+
return {};
3016+
},
3017+
value);
3018+
}
3019+
30033020
ValuePtr<Analyzer> makeAnalyzer(const Token* exprTok, ValueFlow::Value value, const TokenList* tokenlist)
30043021
{
30053022
const Token* expr = solveExprValue(exprTok, value);

lib/valueflow.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,10 @@ ValueFlow::Value inferCondition(const std::string& op, const Token* varTok, Math
503503

504504
CPPCHECKLIB ValuePtr<InferModel> makeIntegralInferModel();
505505

506+
const Token* solveExprValue(const Token* expr,
507+
const std::function<std::vector<MathLib::bigint>(const Token*)>& eval,
508+
ValueFlow::Value& value);
509+
506510
std::vector<LifetimeToken> getLifetimeTokens(const Token* tok,
507511
bool escape = false,
508512
ValueFlow::Value::ErrorPath errorPath = ValueFlow::Value::ErrorPath{});

test/testuninitvar.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,6 +3612,17 @@ class TestUninitVar : public TestFixture {
36123612
" int a[ 2 ] = { [ 0 ] = *p++, [ 1 ] = 1 };\n"
36133613
"}");
36143614
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: p\n", errout.str());
3615+
3616+
valueFlowUninit("void f(int height) {\n"
3617+
" int a[11];\n"
3618+
" int *p = a;\n"
3619+
" int step = 2;\n"
3620+
" for (int i = 0; i < (height * step); i += step)\n"
3621+
" *p++ = 0;\n"
3622+
" for (int i = 0; i < height; i++)\n"
3623+
" if (a[i]) {}\n"
3624+
"}\n");
3625+
ASSERT_EQUALS("", errout.str());
36153626
}
36163627

36173628
void uninitStructMember() { // struct members

0 commit comments

Comments
 (0)