Skip to content

Commit 8b26ecb

Browse files
authored
Extend ProgramMemory to handle expressions (#3069)
1 parent d399564 commit 8b26ecb

5 files changed

Lines changed: 111 additions & 103 deletions

File tree

lib/programmemory.cpp

Lines changed: 78 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,67 @@
11

22
#include "programmemory.h"
3-
#include "mathlib.h"
4-
#include "token.h"
53
#include "astutils.h"
4+
#include "mathlib.h"
65
#include "symboldatabase.h"
6+
#include "token.h"
77
#include <algorithm>
88
#include <cassert>
9+
#include <cstdio>
910
#include <limits>
1011
#include <memory>
1112

12-
void ProgramMemory::setValue(nonneg int varid, const ValueFlow::Value &value)
13-
{
14-
values[varid] = value;
15-
}
16-
const ValueFlow::Value* ProgramMemory::getValue(nonneg int varid) const
13+
void ProgramMemory::setValue(MathLib::bigint exprid, const ValueFlow::Value& value) { values[exprid] = value; }
14+
const ValueFlow::Value* ProgramMemory::getValue(MathLib::bigint exprid) const
1715
{
18-
const ProgramMemory::Map::const_iterator it = values.find(varid);
16+
const ProgramMemory::Map::const_iterator it = values.find(exprid);
1917
const bool found = it != values.end() && !it->second.isImpossible();
2018
if (found)
2119
return &it->second;
2220
else
2321
return nullptr;
2422
}
2523

26-
bool ProgramMemory::getIntValue(nonneg int varid, MathLib::bigint* result) const
24+
bool ProgramMemory::getIntValue(MathLib::bigint exprid, MathLib::bigint* result) const
2725
{
28-
const ValueFlow::Value* value = getValue(varid);
26+
const ValueFlow::Value* value = getValue(exprid);
2927
if (value && value->isIntValue()) {
3028
*result = value->intvalue;
3129
return true;
3230
}
3331
return false;
3432
}
3533

36-
void ProgramMemory::setIntValue(nonneg int varid, MathLib::bigint value)
34+
void ProgramMemory::setIntValue(MathLib::bigint exprid, MathLib::bigint value)
3735
{
38-
values[varid] = ValueFlow::Value(value);
36+
values[exprid] = ValueFlow::Value(value);
3937
}
4038

41-
bool ProgramMemory::getTokValue(nonneg int varid, const Token** result) const
39+
bool ProgramMemory::getTokValue(MathLib::bigint exprid, const Token** result) const
4240
{
43-
const ValueFlow::Value* value = getValue(varid);
41+
const ValueFlow::Value* value = getValue(exprid);
4442
if (value && value->isTokValue()) {
4543
*result = value->tokvalue;
4644
return true;
4745
}
4846
return false;
4947
}
5048

51-
bool ProgramMemory::getContainerSizeValue(nonneg int varid, MathLib::bigint* result) const
49+
bool ProgramMemory::getContainerSizeValue(MathLib::bigint exprid, MathLib::bigint* result) const
5250
{
53-
const ValueFlow::Value* value = getValue(varid);
51+
const ValueFlow::Value* value = getValue(exprid);
5452
if (value && value->isContainerSizeValue()) {
5553
*result = value->intvalue;
5654
return true;
5755
}
5856
return false;
5957
}
6058

61-
void ProgramMemory::setUnknown(nonneg int varid)
59+
void ProgramMemory::setUnknown(MathLib::bigint exprid)
6260
{
63-
values[varid].valueType = ValueFlow::Value::ValueType::UNINIT;
61+
values[exprid].valueType = ValueFlow::Value::ValueType::UNINIT;
6462
}
6563

66-
bool ProgramMemory::hasValue(nonneg int varid)
67-
{
68-
return values.find(varid) != values.end();
69-
}
64+
bool ProgramMemory::hasValue(MathLib::bigint exprid) { return values.find(exprid) != values.end(); }
7065

7166
void ProgramMemory::swap(ProgramMemory &pm)
7267
{
@@ -85,8 +80,9 @@ bool ProgramMemory::empty() const
8580

8681
void ProgramMemory::replace(const ProgramMemory &pm)
8782
{
88-
for (auto&& p:pm.values)
83+
for (auto&& p : pm.values) {
8984
values[p.first] = p.second;
85+
}
9086
}
9187

9288
void ProgramMemory::insert(const ProgramMemory &pm)
@@ -146,21 +142,13 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
146142
});
147143
if (!vartok)
148144
return;
149-
if (vartok->varId() == 0)
145+
if (vartok->exprId() == 0)
150146
return;
151147
if (!truevalue.isIntValue())
152148
return;
153-
if (endTok && isVariableChanged(tok->next(), endTok, vartok->varId(), false, settings, true))
154-
return;
155-
pm.setIntValue(vartok->varId(), then ? truevalue.intvalue : falsevalue.intvalue);
156-
} else if (Token::Match(tok, "%var%")) {
157-
if (tok->varId() == 0)
149+
if (endTok && isExpressionChanged(vartok, tok->next(), endTok, settings, true))
158150
return;
159-
if (then && !astIsPointer(tok) && !astIsBool(tok))
160-
return;
161-
if (endTok && isVariableChanged(tok->next(), endTok, tok->varId(), false, settings, true))
162-
return;
163-
pm.setIntValue(tok->varId(), then);
151+
pm.setIntValue(vartok->exprId(), then ? truevalue.intvalue : falsevalue.intvalue);
164152
} else if (Token::simpleMatch(tok, "!")) {
165153
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then);
166154
} else if (then && Token::simpleMatch(tok, "&&")) {
@@ -169,6 +157,12 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
169157
} else if (!then && Token::simpleMatch(tok, "||")) {
170158
programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then);
171159
programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then);
160+
} else if (tok->exprId() > 0) {
161+
if (then && !astIsPointer(tok) && !astIsBool(tok))
162+
return;
163+
if (endTok && isExpressionChanged(tok, tok->next(), endTok, settings, true))
164+
return;
165+
pm.setIntValue(tok->exprId(), then);
172166
}
173167
}
174168

@@ -197,36 +191,33 @@ static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok
197191
{
198192
int indentlevel = 0;
199193
for (const Token *tok2 = tok; tok2; tok2 = tok2->previous()) {
200-
bool setvar = false;
201-
if (Token::Match(tok2, "[;{}] %var% = %var% ;")) {
194+
if ((Token::simpleMatch(tok2, "=") || Token::Match(tok2->previous(), "%var% (|{")) && tok2->astOperand1() &&
195+
tok2->astOperand2()) {
196+
bool setvar = false;
197+
const Token* vartok = tok2->astOperand1();
198+
const Token* valuetok = tok2->astOperand2();
202199
for (const auto& p:vars) {
203-
if (p.first != tok2->next()->varId())
200+
if (p.first != vartok->exprId())
204201
continue;
205-
const Token *vartok = tok2->tokAt(3);
206202
if (vartok == tok)
207203
continue;
208-
pm.setValue(vartok->varId(), p.second);
204+
pm.setValue(vartok->exprId(), p.second);
209205
setvar = true;
210206
}
211-
}
212-
if (!setvar && (Token::Match(tok2, ";|{|}|%type% %var% =") || Token::Match(tok2, "[;{}] const| %type% %var% (") ||
213-
Token::Match(tok2->previous(), "for ( %var% ="))) {
214-
const Token *vartok = tok2->next();
215-
while (vartok->next()->isName())
216-
vartok = vartok->next();
217-
if (!pm.hasValue(vartok->varId())) {
218-
MathLib::bigint result = 0;
219-
bool error = false;
220-
execute(vartok->next()->astOperand2(), &pm, &result, &error);
221-
if (!error)
222-
pm.setIntValue(vartok->varId(), result);
223-
else
224-
pm.setUnknown(vartok->varId());
207+
if (!setvar) {
208+
if (!pm.hasValue(vartok->exprId())) {
209+
MathLib::bigint result = 0;
210+
bool error = false;
211+
execute(valuetok, &pm, &result, &error);
212+
if (!error)
213+
pm.setIntValue(vartok->exprId(), result);
214+
else
215+
pm.setUnknown(vartok->exprId());
216+
}
225217
}
226-
} else if (!setvar && Token::Match(tok2, "%var% !!=") && isVariableChanged(tok2, 0, nullptr, true)) {
227-
const Token *vartok = tok2;
228-
if (!pm.hasValue(vartok->varId()))
229-
pm.setUnknown(vartok->varId());
218+
} else if (tok2->exprId() > 0 && Token::Match(tok2, ".|(|[|*|%var%") && !pm.hasValue(tok2->exprId()) &&
219+
isVariableChanged(tok2, 0, nullptr, true)) {
220+
pm.setUnknown(tok2->exprId());
230221
}
231222

232223
if (tok2->str() == "{") {
@@ -291,12 +282,12 @@ void ProgramMemoryState::replace(const ProgramMemory &pm, const Token* origin)
291282

292283
void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& vars)
293284
{
294-
ProgramMemory pm;
285+
ProgramMemory pm = state;
295286
fillProgramMemoryFromConditions(pm, tok, nullptr);
296287
for (const auto& p:vars) {
297-
nonneg int varid = p.first;
288+
MathLib::bigint exprid = p.first;
298289
const ValueFlow::Value &value = p.second;
299-
pm.setValue(varid, value);
290+
pm.setValue(exprid, value);
300291
if (value.varId)
301292
pm.setIntValue(value.varId, value.varvalue);
302293
}
@@ -343,9 +334,9 @@ ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars)
343334
fillProgramMemoryFromConditions(programMemory, tok, nullptr);
344335
ProgramMemory state;
345336
for (const auto& p:vars) {
346-
nonneg int varid = p.first;
337+
MathLib::bigint exprid = p.first;
347338
const ValueFlow::Value &value = p.second;
348-
programMemory.setValue(varid, value);
339+
programMemory.setValue(exprid, value);
349340
if (value.varId)
350341
programMemory.setIntValue(value.varId, value.varvalue);
351342
}
@@ -354,17 +345,17 @@ ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars)
354345
return programMemory;
355346
}
356347

357-
ProgramMemory getProgramMemory(const Token *tok, nonneg int varid, const ValueFlow::Value &value)
348+
ProgramMemory getProgramMemory(const Token* tok, MathLib::bigint exprid, const ValueFlow::Value& value)
358349
{
359350
ProgramMemory programMemory;
360351
programMemory.replace(getInitialProgramState(tok, value.tokvalue));
361352
programMemory.replace(getInitialProgramState(tok, value.condition));
362353
fillProgramMemoryFromConditions(programMemory, tok, nullptr);
363-
programMemory.setValue(varid, value);
354+
programMemory.setValue(exprid, value);
364355
if (value.varId)
365356
programMemory.setIntValue(value.varId, value.varvalue);
366357
const ProgramMemory state = programMemory;
367-
fillProgramMemoryFromAssignments(programMemory, tok, state, {{varid, value}});
358+
fillProgramMemoryFromAssignments(programMemory, tok, state, {{exprid, value}});
368359
return programMemory;
369360
}
370361

@@ -391,6 +382,11 @@ void execute(const Token *expr,
391382
*error = true;
392383
}
393384

385+
else if (expr->exprId() > 0 && programMemory->hasValue(expr->exprId())) {
386+
if (!programMemory->getIntValue(expr->exprId(), result))
387+
*error = true;
388+
}
389+
394390
else if (expr->isComparisonOp()) {
395391
MathLib::bigint result1(0), result2(0);
396392
execute(expr->astOperand1(), programMemory, &result1, error);
@@ -411,45 +407,45 @@ void execute(const Token *expr,
411407

412408
else if (expr->isAssignmentOp()) {
413409
execute(expr->astOperand2(), programMemory, result, error);
414-
if (!expr->astOperand1() || !expr->astOperand1()->varId())
410+
if (!expr->astOperand1() || !expr->astOperand1()->exprId())
415411
*error = true;
416412
if (*error)
417413
return;
418414

419415
if (expr->str() == "=") {
420-
programMemory->setIntValue(expr->astOperand1()->varId(), *result);
416+
programMemory->setIntValue(expr->astOperand1()->exprId(), *result);
421417
return;
422418
}
423419

424420
long long intValue;
425-
if (!programMemory->getIntValue(expr->astOperand1()->varId(), &intValue)) {
421+
if (!programMemory->getIntValue(expr->astOperand1()->exprId(), &intValue)) {
426422
*error = true;
427423
return;
428424
}
429425
if (expr->str() == "+=")
430-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue + *result);
426+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue + *result);
431427
else if (expr->str() == "-=")
432-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue - *result);
428+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue - *result);
433429
else if (expr->str() == "*=")
434-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue * *result);
430+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue * *result);
435431
else if (expr->str() == "/=" && *result != 0)
436-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue / *result);
432+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue / *result);
437433
else if (expr->str() == "%=" && *result != 0)
438-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue % *result);
434+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue % *result);
439435
else if (expr->str() == "&=")
440-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue & *result);
436+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue & *result);
441437
else if (expr->str() == "|=")
442-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue | *result);
438+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue | *result);
443439
else if (expr->str() == "^=")
444-
programMemory->setIntValue(expr->astOperand1()->varId(), intValue ^ *result);
440+
programMemory->setIntValue(expr->astOperand1()->exprId(), intValue ^ *result);
445441
}
446442

447443
else if (Token::Match(expr, "++|--")) {
448-
if (!expr->astOperand1() || expr->astOperand1()->varId() == 0U)
444+
if (!expr->astOperand1() || expr->astOperand1()->exprId() == 0U)
449445
*error = true;
450446
else {
451447
long long intValue;
452-
if (!programMemory->getIntValue(expr->astOperand1()->varId(), &intValue))
448+
if (!programMemory->getIntValue(expr->astOperand1()->exprId(), &intValue))
453449
*error = true;
454450
else {
455451
if (intValue == 0 &&
@@ -458,7 +454,7 @@ void execute(const Token *expr,
458454
expr->astOperand1()->variable()->isUnsigned())
459455
*error = true; // overflow
460456
*result = intValue + (expr->str() == "++" ? 1 : -1);
461-
programMemory->setIntValue(expr->astOperand1()->varId(), *result);
457+
programMemory->setIntValue(expr->astOperand1()->exprId(), *result);
462458
}
463459
}
464460
}
@@ -530,7 +526,7 @@ void execute(const Token *expr,
530526

531527
else if (expr->str() == "[" && expr->astOperand1() && expr->astOperand2()) {
532528
const Token *tokvalue = nullptr;
533-
if (!programMemory->getTokValue(expr->astOperand1()->varId(), &tokvalue)) {
529+
if (!programMemory->getTokValue(expr->astOperand1()->exprId(), &tokvalue)) {
534530
auto tokvalue_it = std::find_if(expr->astOperand1()->values().begin(),
535531
expr->astOperand1()->values().end(),
536532
std::mem_fn(&ValueFlow::Value::isTokValue));
@@ -558,11 +554,11 @@ void execute(const Token *expr,
558554
if (astIsContainer(containerTok)) {
559555
Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1));
560556
if (yield == Library::Container::Yield::SIZE) {
561-
if (!programMemory->getContainerSizeValue(containerTok->varId(), result))
557+
if (!programMemory->getContainerSizeValue(containerTok->exprId(), result))
562558
*error = true;
563559
} else if (yield == Library::Container::Yield::EMPTY) {
564560
MathLib::bigint size = 0;
565-
if (!programMemory->getContainerSizeValue(containerTok->varId(), &size))
561+
if (!programMemory->getContainerSizeValue(containerTok->exprId(), &size))
566562
*error = true;
567563
*result = (size == 0);
568564
} else {

lib/programmemory.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,21 @@
1111
class Token;
1212

1313
struct ProgramMemory {
14-
using Map = std::unordered_map<nonneg int, ValueFlow::Value>;
14+
using Map = std::unordered_map<MathLib::bigint, ValueFlow::Value>;
1515
Map values;
1616

17-
void setValue(nonneg int varid, const ValueFlow::Value &value);
18-
const ValueFlow::Value* getValue(nonneg int varid) const;
17+
void setValue(MathLib::bigint exprid, const ValueFlow::Value& value);
18+
const ValueFlow::Value* getValue(MathLib::bigint exprid) const;
1919

20-
bool getIntValue(nonneg int varid, MathLib::bigint* result) const;
21-
void setIntValue(nonneg int varid, MathLib::bigint value);
20+
bool getIntValue(MathLib::bigint exprid, MathLib::bigint* result) const;
21+
void setIntValue(MathLib::bigint exprid, MathLib::bigint value);
2222

23-
bool getContainerSizeValue(nonneg int varid, MathLib::bigint* result) const;
23+
bool getContainerSizeValue(MathLib::bigint exprid, MathLib::bigint* result) const;
2424

25-
void setUnknown(nonneg int varid);
25+
void setUnknown(MathLib::bigint exprid);
2626

27-
bool getTokValue(nonneg int varid, const Token** result) const;
28-
bool hasValue(nonneg int varid);
27+
bool getTokValue(MathLib::bigint exprid, const Token** result) const;
28+
bool hasValue(MathLib::bigint exprid);
2929

3030
void swap(ProgramMemory &pm);
3131

@@ -42,7 +42,7 @@ void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Toke
4242

4343
struct ProgramMemoryState {
4444
ProgramMemory state;
45-
std::map<nonneg int, const Token*> origins;
45+
std::map<MathLib::bigint, const Token*> origins;
4646

4747
void insert(const ProgramMemory &pm, const Token* origin = nullptr);
4848
void replace(const ProgramMemory &pm, const Token* origin = nullptr);
@@ -79,7 +79,7 @@ bool conditionIsTrue(const Token *condition, const ProgramMemory &programMemory)
7979
/**
8080
* Get program memory by looking backwards from given token.
8181
*/
82-
ProgramMemory getProgramMemory(const Token *tok, nonneg int varid, const ValueFlow::Value &value);
82+
ProgramMemory getProgramMemory(const Token* tok, MathLib::bigint exprid, const ValueFlow::Value& value);
8383

8484
ProgramMemory getProgramMemory(const Token *tok, const ProgramMemory::Map& vars);
8585

0 commit comments

Comments
 (0)