Skip to content

Commit 5e9bc48

Browse files
authored
Evaluate symbolic values (#3495)
1 parent 85b02e4 commit 5e9bc48

6 files changed

Lines changed: 129 additions & 18 deletions

File tree

lib/analyzer.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#define analyzerH
2121

2222
#include "config.h"
23+
#include "mathlib.h"
2324
#include <string>
2425
#include <type_traits>
2526
#include <vector>
@@ -155,8 +156,9 @@ struct Analyzer {
155156
/// Update the state of the value
156157
virtual void update(Token* tok, Action a, Direction d) = 0;
157158
/// Try to evaluate the value of a token(most likely a condition)
158-
virtual std::vector<int> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const = 0;
159-
std::vector<int> evaluate(const Token* tok, const Token* ctx = nullptr) const {
159+
virtual std::vector<MathLib::bigint> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const = 0;
160+
std::vector<MathLib::bigint> evaluate(const Token* tok, const Token* ctx = nullptr) const
161+
{
160162
return evaluate(Evaluate::Integral, tok, ctx);
161163
}
162164
/// Lower any values to possible

lib/forwardanalyzer.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ struct ForwardTraversal {
7474
std::pair<bool, bool> evalCond(const Token* tok, const Token* ctx = nullptr) const {
7575
if (!tok)
7676
return std::make_pair(false, false);
77-
std::vector<int> result = analyzer->evaluate(tok, ctx);
77+
std::vector<MathLib::bigint> result = analyzer->evaluate(tok, ctx);
7878
// TODO: We should convert to bool
7979
bool checkThen = std::any_of(result.begin(), result.end(), [](int x) {
8080
return x != 0;
@@ -600,7 +600,8 @@ struct ForwardTraversal {
600600
if (conTok && updateRecursive(conTok) == Progress::Break)
601601
return Break();
602602
bool isEmpty = false;
603-
std::vector<int> result = analyzer->evaluate(Analyzer::Evaluate::ContainerEmpty, conTok);
603+
std::vector<MathLib::bigint> result =
604+
analyzer->evaluate(Analyzer::Evaluate::ContainerEmpty, conTok);
604605
if (result.empty())
605606
analyzer->assume(conTok, false, Analyzer::Assume::ContainerEmpty);
606607
else

lib/reverseanalyzer.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ struct ReverseTraversal {
1818
const Settings* settings;
1919

2020
std::pair<bool, bool> evalCond(const Token* tok) {
21-
std::vector<int> result = analyzer->evaluate(tok);
21+
std::vector<MathLib::bigint> result = analyzer->evaluate(tok);
2222
// TODO: We should convert to bool
2323
bool checkThen = std::any_of(result.begin(), result.end(), [](int x) {
2424
return x == 1;

lib/valueflow.cpp

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -803,11 +803,11 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
803803
// increment
804804
else if (parent->str() == "++") {
805805
for (const ValueFlow::Value &val : tok->values()) {
806-
if (!val.isIntValue() && !val.isFloatValue())
806+
if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
807807
continue;
808808
ValueFlow::Value v(val);
809809
if (parent == tok->previous()) {
810-
if (v.isIntValue())
810+
if (v.isIntValue() || v.isSymbolicValue())
811811
v.intvalue = v.intvalue + 1;
812812
else
813813
v.floatValue = v.floatValue + 1.0;
@@ -819,11 +819,11 @@ static void setTokenValue(Token* tok, ValueFlow::Value value, const Settings* se
819819
// decrement
820820
else if (parent->str() == "--") {
821821
for (const ValueFlow::Value &val : tok->values()) {
822-
if (!val.isIntValue() && !val.isFloatValue())
822+
if (!val.isIntValue() && !val.isFloatValue() && !val.isSymbolicValue())
823823
continue;
824824
ValueFlow::Value v(val);
825825
if (parent == tok->previous()) {
826-
if (v.isIntValue())
826+
if (v.isIntValue() || v.isSymbolicValue())
827827
v.intvalue = v.intvalue - 1;
828828
else
829829
v.floatValue = v.floatValue - 1.0;
@@ -2080,7 +2080,7 @@ struct ValueFlowAnalyzer : Analyzer {
20802080
// Check if its assigned to the same value
20812081
if (value && !value->isImpossible() && Token::simpleMatch(tok->astParent(), "=") && astIsLHS(tok) &&
20822082
astIsIntegral(tok->astParent()->astOperand2(), false)) {
2083-
std::vector<int> result = evaluate(Evaluate::Integral, tok->astParent()->astOperand2());
2083+
std::vector<MathLib::bigint> result = evaluate(Evaluate::Integral, tok->astParent()->astOperand2());
20842084
if (!result.empty() && value->equalTo(result.front()))
20852085
return Action::Idempotent;
20862086
}
@@ -2188,22 +2188,48 @@ struct ValueFlowAnalyzer : Analyzer {
21882188
return true;
21892189
}
21902190

2191-
bool isSameSymbolicValue(const Token* tok, ErrorPath* errorPath = nullptr) const
2191+
const Token* findMatch(const Token* tok) const
2192+
{
2193+
return findAstNode(tok, [&](const Token* child) {
2194+
return match(child);
2195+
});
2196+
}
2197+
2198+
bool isSameSymbolicValue(const Token* tok, ValueFlow::Value* value = nullptr) const
21922199
{
21932200
if (!useSymbolicValues())
21942201
return false;
21952202
if (Token::Match(tok, "%assign%"))
21962203
return false;
2204+
const ValueFlow::Value* currValue = getValue(tok);
2205+
if (!currValue)
2206+
return false;
2207+
const bool exact = !currValue->isIntValue() || currValue->isImpossible();
21972208
for (const ValueFlow::Value& v : tok->values()) {
21982209
if (!v.isSymbolicValue())
21992210
continue;
2200-
if (!v.isKnown())
2211+
const bool toImpossible = v.isImpossible() && currValue->isKnown();
2212+
if (!v.isKnown() && !toImpossible)
22012213
continue;
2202-
if (v.intvalue != 0)
2214+
if (exact && v.intvalue != 0)
22032215
continue;
2216+
std::vector<MathLib::bigint> r;
2217+
ValueFlow::Value::Bound bound = currValue->bound;
22042218
if (match(v.tokvalue)) {
2205-
if (errorPath)
2206-
errorPath->insert(errorPath->end(), v.errorPath.begin(), v.errorPath.end());
2219+
r = {currValue->intvalue};
2220+
} else if (!exact && findMatch(v.tokvalue)) {
2221+
r = evaluate(Evaluate::Integral, v.tokvalue, tok);
2222+
if (bound == ValueFlow::Value::Bound::Point)
2223+
bound = v.bound;
2224+
}
2225+
if (!r.empty()) {
2226+
if (value) {
2227+
value->errorPath.insert(value->errorPath.end(), v.errorPath.begin(), v.errorPath.end());
2228+
value->intvalue = r.front() + v.intvalue;
2229+
if (toImpossible)
2230+
value->setImpossible();
2231+
value->bound = bound;
2232+
}
22072233
return true;
22082234
}
22092235
}
@@ -2302,11 +2328,12 @@ struct ValueFlowAnalyzer : Analyzer {
23022328
return Action::None;
23032329
}
23042330

2305-
virtual std::vector<int> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const OVERRIDE {
2331+
virtual std::vector<MathLib::bigint> evaluate(Evaluate e, const Token* tok, const Token* ctx = nullptr) const OVERRIDE
2332+
{
23062333
if (e == Evaluate::Integral) {
23072334
if (tok->hasKnownIntValue())
23082335
return {static_cast<int>(tok->values().front().intvalue)};
2309-
std::vector<int> result;
2336+
std::vector<MathLib::bigint> result;
23102337
ProgramMemory pm = pms.get(tok, ctx, getProgramState());
23112338
if (Token::Match(tok, "&&|%oror%")) {
23122339
if (conditionIsTrue(tok, pm))
@@ -2384,7 +2411,7 @@ struct ValueFlowAnalyzer : Analyzer {
23842411
// Make a copy of the value to modify it
23852412
localValue = *value;
23862413
value = &localValue;
2387-
isSameSymbolicValue(tok, &value->errorPath);
2414+
isSameSymbolicValue(tok, &localValue);
23882415
}
23892416
// Read first when moving forward
23902417
if (d == Direction::Forward && a.isRead())

test/testcondition.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3826,6 +3826,16 @@ class TestCondition : public TestFixture {
38263826
"}\n");
38273827
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:4]: (style) Condition 'z<1' is always false\n", errout.str());
38283828

3829+
check("bool f(int &index, const int s, const double * const array, double & x) {\n"
3830+
" if (index >= s)\n"
3831+
" return false;\n"
3832+
" else {\n"
3833+
" x = array[index];\n"
3834+
" return (index++) >= s;\n"
3835+
" }\n"
3836+
"}\n");
3837+
ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:6]: (style) Condition '(index++)>=s' is always false\n", errout.str());
3838+
38293839
check("struct a {\n"
38303840
" a *b() const;\n"
38313841
"} c;\n"

test/testvalueflow.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6357,6 +6357,77 @@ class TestValueFlow : public TestFixture {
63576357
"}";
63586358
ASSERT_EQUALS(true, testValueOfX(code, 3U, "y", 0));
63596359
ASSERT_EQUALS(true, testValueOfXImpossible(code, 3U, "y", -1));
6360+
6361+
code = "void f(int y) {\n"
6362+
" int x = y - 1;\n"
6363+
" if (y == 1)\n"
6364+
" int a = x;\n"
6365+
"}\n";
6366+
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 0));
6367+
6368+
code = "void f(int y) {\n"
6369+
" int x = y * y;\n"
6370+
" if (y == 2)\n"
6371+
" int a = x;\n"
6372+
"}\n";
6373+
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 4));
6374+
6375+
code = "void f(int x, int y) {\n"
6376+
" if (x == y*y)\n"
6377+
" if (y == 2)\n"
6378+
" int a = x;\n"
6379+
"}\n";
6380+
ASSERT_EQUALS(true, testValueOfXKnown(code, 4U, 4));
6381+
6382+
code = "void f(int x, int y) {\n"
6383+
" if (x > y*y)\n"
6384+
" if (y == 2)\n"
6385+
" int a = x;\n"
6386+
"}\n";
6387+
ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 4));
6388+
6389+
code = "void f(int x, int y) {\n"
6390+
" if (x != y*y)\n"
6391+
" if (y == 2)\n"
6392+
" int a = x;\n"
6393+
"}\n";
6394+
ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 4));
6395+
6396+
code = "void f(int x, int y) {\n"
6397+
" if (x >= y*y)\n"
6398+
" if (y == 2)\n"
6399+
" int a = x;\n"
6400+
"}\n";
6401+
ASSERT_EQUALS(true, testValueOfXImpossible(code, 4U, 3));
6402+
6403+
code = "void f(int x, int y) {\n"
6404+
" if (x == y*y)\n"
6405+
" if (y != 2)\n"
6406+
" int a = x;\n"
6407+
"}\n";
6408+
TODO_ASSERT_EQUALS(true, false, testValueOfXImpossible(code, 4U, 4));
6409+
6410+
code = "void f(int x, int y) {\n"
6411+
" if (x == y*y)\n"
6412+
" if (y > 2)\n"
6413+
" int a = x;\n"
6414+
"}\n";
6415+
ASSERT_EQUALS(true, testValueOfX(code, 4U, 9));
6416+
6417+
code = "struct A {\n"
6418+
" A* b();\n"
6419+
" int c() const;\n"
6420+
"};\n"
6421+
"void f(A *d) {\n"
6422+
" if (!d || d->c() != 1)\n"
6423+
" return;\n"
6424+
" A * y = d;\n"
6425+
" d = d->b();\n"
6426+
" A * x = d;\n"
6427+
" A* z = x;\n"
6428+
"}\n";
6429+
ASSERT_EQUALS(true, testValueOfX(code, 11U, "d", 0));
6430+
ASSERT_EQUALS(false, testValueOfXImpossible(code, 11U, 0));
63606431
}
63616432

63626433
void valueFlowSmartPointer()

0 commit comments

Comments
 (0)