/src/cppcheck/lib/programmemory.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Cppcheck - A tool for static C/C++ code analysis |
3 | | * Copyright (C) 2007-2023 Cppcheck team. |
4 | | * |
5 | | * This program is free software: you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation, either version 3 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | */ |
18 | | |
19 | | #include "programmemory.h" |
20 | | |
21 | | #include "astutils.h" |
22 | | #include "calculate.h" |
23 | | #include "infer.h" |
24 | | #include "library.h" |
25 | | #include "mathlib.h" |
26 | | #include "settings.h" |
27 | | #include "symboldatabase.h" |
28 | | #include "token.h" |
29 | | #include "utils.h" |
30 | | #include "valueflow.h" |
31 | | #include "valueptr.h" |
32 | | |
33 | | #include <algorithm> |
34 | | #include <cassert> |
35 | | #include <cmath> |
36 | | #include <functional> |
37 | | #include <list> |
38 | | #include <memory> |
39 | | #include <string> |
40 | | #include <utility> |
41 | | #include <vector> |
42 | | |
43 | 159k | nonneg int ExprIdToken::getExpressionId() const { |
44 | 159k | return tok ? tok->exprId() : exprid; |
45 | 159k | } |
46 | | |
47 | | std::size_t ExprIdToken::Hash::operator()(ExprIdToken etok) const |
48 | 86.6k | { |
49 | 86.6k | return std::hash<nonneg int>()(etok.getExpressionId()); |
50 | 86.6k | } |
51 | | |
52 | 4.81k | void ProgramMemory::setValue(const Token* expr, const ValueFlow::Value& value) { |
53 | 4.81k | mValues[expr] = value; |
54 | 4.81k | ValueFlow::Value subvalue = value; |
55 | 4.81k | const Token* subexpr = solveExprValue( |
56 | 4.81k | expr, |
57 | 4.81k | [&](const Token* tok) -> std::vector<MathLib::bigint> { |
58 | 756 | if (tok->hasKnownIntValue()) |
59 | 143 | return {tok->values().front().intvalue}; |
60 | 613 | MathLib::bigint result = 0; |
61 | 613 | if (getIntValue(tok->exprId(), result)) |
62 | 25 | return {result}; |
63 | 588 | return {}; |
64 | 613 | }, |
65 | 4.81k | subvalue); |
66 | 4.81k | if (subexpr) |
67 | 4.81k | mValues[subexpr] = subvalue; |
68 | 4.81k | } |
69 | | const ValueFlow::Value* ProgramMemory::getValue(nonneg int exprid, bool impossible) const |
70 | 613 | { |
71 | 613 | const ProgramMemory::Map::const_iterator it = mValues.find(exprid); |
72 | 613 | const bool found = it != mValues.cend() && (impossible || !it->second.isImpossible()); |
73 | 613 | if (found) |
74 | 45 | return &it->second; |
75 | 568 | return nullptr; |
76 | 613 | } |
77 | | |
78 | | // cppcheck-suppress unusedFunction |
79 | | bool ProgramMemory::getIntValue(nonneg int exprid, MathLib::bigint& result) const |
80 | 613 | { |
81 | 613 | const ValueFlow::Value* value = getValue(exprid); |
82 | 613 | if (value && value->isIntValue()) { |
83 | 25 | result = value->intvalue; |
84 | 25 | return true; |
85 | 25 | } |
86 | 588 | return false; |
87 | 613 | } |
88 | | |
89 | | void ProgramMemory::setIntValue(const Token* expr, MathLib::bigint value, bool impossible) |
90 | 218 | { |
91 | 218 | ValueFlow::Value v(value); |
92 | 218 | if (impossible) |
93 | 182 | v.setImpossible(); |
94 | 218 | setValue(expr, v); |
95 | 218 | } |
96 | | |
97 | | bool ProgramMemory::getTokValue(nonneg int exprid, const Token** result) const |
98 | 0 | { |
99 | 0 | const ValueFlow::Value* value = getValue(exprid); |
100 | 0 | if (value && value->isTokValue()) { |
101 | 0 | *result = value->tokvalue; |
102 | 0 | return true; |
103 | 0 | } |
104 | 0 | return false; |
105 | 0 | } |
106 | | |
107 | | // cppcheck-suppress unusedFunction |
108 | | bool ProgramMemory::getContainerSizeValue(nonneg int exprid, MathLib::bigint& result) const |
109 | 0 | { |
110 | 0 | const ValueFlow::Value* value = getValue(exprid); |
111 | 0 | if (value && value->isContainerSizeValue()) { |
112 | 0 | result = value->intvalue; |
113 | 0 | return true; |
114 | 0 | } |
115 | 0 | return false; |
116 | 0 | } |
117 | | bool ProgramMemory::getContainerEmptyValue(nonneg int exprid, MathLib::bigint& result) const |
118 | 0 | { |
119 | 0 | const ValueFlow::Value* value = getValue(exprid, true); |
120 | 0 | if (value && value->isContainerSizeValue()) { |
121 | 0 | if (value->isImpossible() && value->intvalue == 0) { |
122 | 0 | result = false; |
123 | 0 | return true; |
124 | 0 | } |
125 | 0 | if (!value->isImpossible()) { |
126 | 0 | result = (value->intvalue == 0); |
127 | 0 | return true; |
128 | 0 | } |
129 | 0 | } |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | | void ProgramMemory::setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual) |
134 | 0 | { |
135 | 0 | ValueFlow::Value v(value); |
136 | 0 | v.valueType = ValueFlow::Value::ValueType::CONTAINER_SIZE; |
137 | 0 | if (!isEqual) |
138 | 0 | v.valueKind = ValueFlow::Value::ValueKind::Impossible; |
139 | 0 | setValue(expr, v); |
140 | 0 | } |
141 | | |
142 | 312 | void ProgramMemory::setUnknown(const Token* expr) { |
143 | 312 | mValues[expr].valueType = ValueFlow::Value::ValueType::UNINIT; |
144 | 312 | } |
145 | | |
146 | | bool ProgramMemory::hasValue(nonneg int exprid) |
147 | 41.9k | { |
148 | 41.9k | return mValues.find(exprid) != mValues.end(); |
149 | 41.9k | } |
150 | | |
151 | 0 | const ValueFlow::Value& ProgramMemory::at(nonneg int exprid) const { |
152 | 0 | return mValues.at(exprid); |
153 | 0 | } |
154 | 7.79k | ValueFlow::Value& ProgramMemory::at(nonneg int exprid) { |
155 | 7.79k | return mValues.at(exprid); |
156 | 7.79k | } |
157 | | |
158 | | void ProgramMemory::erase_if(const std::function<bool(const ExprIdToken&)>& pred) |
159 | 1.55k | { |
160 | 2.88k | for (auto it = mValues.begin(); it != mValues.end();) { |
161 | 1.33k | if (pred(it->first)) |
162 | 332 | it = mValues.erase(it); |
163 | 999 | else |
164 | 999 | ++it; |
165 | 1.33k | } |
166 | 1.55k | } |
167 | | |
168 | | void ProgramMemory::swap(ProgramMemory &pm) |
169 | 0 | { |
170 | 0 | mValues.swap(pm.mValues); |
171 | 0 | } |
172 | | |
173 | | void ProgramMemory::clear() |
174 | 0 | { |
175 | 0 | mValues.clear(); |
176 | 0 | } |
177 | | |
178 | | bool ProgramMemory::empty() const |
179 | 0 | { |
180 | 0 | return mValues.empty(); |
181 | 0 | } |
182 | | |
183 | | void ProgramMemory::replace(const ProgramMemory &pm) |
184 | 2.00k | { |
185 | 4.35k | for (auto&& p : pm.mValues) { |
186 | 4.35k | mValues[p.first] = p.second; |
187 | 4.35k | } |
188 | 2.00k | } |
189 | | |
190 | | void ProgramMemory::insert(const ProgramMemory &pm) |
191 | 0 | { |
192 | 0 | for (auto&& p : pm) |
193 | 0 | mValues.insert(p); |
194 | 0 | } |
195 | | |
196 | | static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings* settings = nullptr); |
197 | | |
198 | | static bool evaluateCondition(const std::string& op, |
199 | | MathLib::bigint r, |
200 | | const Token* condition, |
201 | | ProgramMemory& pm, |
202 | | const Settings* settings) |
203 | 4.58k | { |
204 | 4.58k | if (!condition) |
205 | 781 | return false; |
206 | 3.80k | if (condition->str() == op) { |
207 | 0 | return evaluateCondition(op, r, condition->astOperand1(), pm, settings) || |
208 | 0 | evaluateCondition(op, r, condition->astOperand2(), pm, settings); |
209 | 0 | } |
210 | 3.80k | MathLib::bigint result = 0; |
211 | 3.80k | bool error = false; |
212 | 3.80k | execute(condition, pm, &result, &error, settings); |
213 | 3.80k | return !error && result == r; |
214 | 3.80k | } |
215 | | |
216 | | bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings* settings) |
217 | 1.37k | { |
218 | 1.37k | return evaluateCondition("&&", 0, condition, pm, settings); |
219 | 1.37k | } |
220 | | |
221 | | bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings* settings) |
222 | 3.20k | { |
223 | 3.20k | return evaluateCondition("||", 1, condition, pm, settings); |
224 | 3.20k | } |
225 | | |
226 | | static bool frontIs(const std::vector<MathLib::bigint>& v, bool i) |
227 | 0 | { |
228 | 0 | if (v.empty()) |
229 | 0 | return false; |
230 | 0 | if (v.front()) |
231 | 0 | return i; |
232 | 0 | return !i; |
233 | 0 | } |
234 | | |
235 | | static bool isTrue(const ValueFlow::Value& v) |
236 | 144 | { |
237 | 144 | if (v.isImpossible()) |
238 | 144 | return v.intvalue == 0; |
239 | 0 | return v.intvalue != 0; |
240 | 144 | } |
241 | | |
242 | | static bool isFalse(const ValueFlow::Value& v) |
243 | 20 | { |
244 | 20 | if (v.isImpossible()) |
245 | 20 | return false; |
246 | 0 | return v.intvalue == 0; |
247 | 20 | } |
248 | | |
249 | | // If the scope is a non-range for loop |
250 | | static bool isBasicForLoop(const Token* tok) |
251 | 781 | { |
252 | 781 | if (!tok) |
253 | 0 | return false; |
254 | 781 | if (Token::simpleMatch(tok, "}")) |
255 | 0 | return isBasicForLoop(tok->link()); |
256 | 781 | if (!Token::simpleMatch(tok->previous(), ") {")) |
257 | 0 | return false; |
258 | 781 | const Token* start = tok->linkAt(-1); |
259 | 781 | if (!start) |
260 | 0 | return false; |
261 | 781 | if (!Token::simpleMatch(start->previous(), "for (")) |
262 | 781 | return false; |
263 | 0 | if (!Token::simpleMatch(start->astOperand2(), ";")) |
264 | 0 | return false; |
265 | 0 | return true; |
266 | 0 | } |
267 | | |
268 | | void programMemoryParseCondition(ProgramMemory& pm, const Token* tok, const Token* endTok, const Settings* settings, bool then) |
269 | 1.48k | { |
270 | 2.27k | auto eval = [&](const Token* t) -> std::vector<MathLib::bigint> { |
271 | 2.27k | if (t->hasKnownIntValue()) |
272 | 195 | return {t->values().front().intvalue}; |
273 | 2.07k | MathLib::bigint result = 0; |
274 | 2.07k | bool error = false; |
275 | 2.07k | execute(t, pm, &result, &error); |
276 | 2.07k | if (!error) |
277 | 79 | return {result}; |
278 | 1.99k | return std::vector<MathLib::bigint>{}; |
279 | 2.07k | }; |
280 | 1.48k | if (Token::Match(tok, "==|>=|<=|<|>|!=")) { |
281 | 1.13k | ValueFlow::Value truevalue; |
282 | 1.13k | ValueFlow::Value falsevalue; |
283 | 1.13k | const Token* vartok = parseCompareInt(tok, truevalue, falsevalue, eval); |
284 | 1.13k | if (!vartok) |
285 | 890 | return; |
286 | 245 | if (vartok->exprId() == 0) |
287 | 0 | return; |
288 | 245 | if (!truevalue.isIntValue()) |
289 | 0 | return; |
290 | 245 | if (endTok && isExpressionChanged(vartok, tok->next(), endTok, settings, true)) |
291 | 69 | return; |
292 | 176 | const bool impossible = (tok->str() == "==" && !then) || (tok->str() == "!=" && then); |
293 | 176 | const ValueFlow::Value& v = then ? truevalue : falsevalue; |
294 | 176 | pm.setValue(vartok, impossible ? asImpossible(v) : v); |
295 | 176 | const Token* containerTok = settings->library.getContainerFromYield(vartok, Library::Container::Yield::SIZE); |
296 | 176 | if (containerTok) |
297 | 0 | pm.setContainerSizeValue(containerTok, v.intvalue, !impossible); |
298 | 347 | } else if (Token::simpleMatch(tok, "!")) { |
299 | 0 | programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, !then); |
300 | 347 | } else if (then && Token::simpleMatch(tok, "&&")) { |
301 | 0 | programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); |
302 | 0 | programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); |
303 | 347 | } else if (!then && Token::simpleMatch(tok, "||")) { |
304 | 0 | programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); |
305 | 0 | programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); |
306 | 347 | } else if (Token::Match(tok, "&&|%oror%")) { |
307 | 0 | std::vector<MathLib::bigint> lhs = eval(tok->astOperand1()); |
308 | 0 | std::vector<MathLib::bigint> rhs = eval(tok->astOperand2()); |
309 | 0 | if (lhs.empty() || rhs.empty()) { |
310 | 0 | if (frontIs(lhs, !then)) |
311 | 0 | programMemoryParseCondition(pm, tok->astOperand2(), endTok, settings, then); |
312 | 0 | if (frontIs(rhs, !then)) |
313 | 0 | programMemoryParseCondition(pm, tok->astOperand1(), endTok, settings, then); |
314 | 0 | } |
315 | 347 | } else if (tok->exprId() > 0) { |
316 | 347 | if (endTok && isExpressionChanged(tok, tok->next(), endTok, settings, true)) |
317 | 129 | return; |
318 | 218 | pm.setIntValue(tok, 0, then); |
319 | 218 | const Token* containerTok = settings->library.getContainerFromYield(tok, Library::Container::Yield::EMPTY); |
320 | 218 | if (containerTok) |
321 | 0 | pm.setContainerSizeValue(containerTok, 0, then); |
322 | 218 | } |
323 | 1.48k | } |
324 | | |
325 | | static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Scope* scope, const Token* endTok, const Settings* settings) |
326 | 3.01k | { |
327 | 3.01k | if (!scope) |
328 | 0 | return; |
329 | 3.01k | if (!scope->isLocal()) |
330 | 1.59k | return; |
331 | 1.42k | assert(scope != scope->nestedIn); |
332 | 0 | fillProgramMemoryFromConditions(pm, scope->nestedIn, endTok, settings); |
333 | 1.42k | if (scope->type == Scope::eIf || scope->type == Scope::eWhile || scope->type == Scope::eElse || scope->type == Scope::eFor) { |
334 | 1.42k | const Token* condTok = getCondTokFromEnd(scope->bodyEnd); |
335 | 1.42k | if (!condTok) |
336 | 0 | return; |
337 | 1.42k | MathLib::bigint result = 0; |
338 | 1.42k | bool error = false; |
339 | 1.42k | execute(condTok, pm, &result, &error); |
340 | 1.42k | if (error) |
341 | 1.07k | programMemoryParseCondition(pm, condTok, endTok, settings, scope->type != Scope::eElse); |
342 | 1.42k | } |
343 | 1.42k | } |
344 | | |
345 | | static void fillProgramMemoryFromConditions(ProgramMemory& pm, const Token* tok, const Settings* settings) |
346 | 1.59k | { |
347 | 1.59k | fillProgramMemoryFromConditions(pm, tok->scope(), tok, settings); |
348 | 1.59k | } |
349 | | |
350 | | static void fillProgramMemoryFromAssignments(ProgramMemory& pm, const Token* tok, const Settings* settings, const ProgramMemory& state, const ProgramMemory::Map& vars) |
351 | 1.59k | { |
352 | 1.59k | int indentlevel = 0; |
353 | 13.8k | for (const Token *tok2 = tok; tok2; tok2 = tok2->previous()) { |
354 | 13.8k | if ((Token::simpleMatch(tok2, "=") || Token::Match(tok2->previous(), "%var% (|{")) && tok2->astOperand1() && |
355 | 13.8k | tok2->astOperand2()) { |
356 | 1.04k | bool setvar = false; |
357 | 1.04k | const Token* vartok = tok2->astOperand1(); |
358 | 1.04k | for (const auto& p:vars) { |
359 | 1.04k | if (p.first != vartok->exprId()) |
360 | 542 | continue; |
361 | 506 | if (vartok == tok) |
362 | 0 | continue; |
363 | 506 | pm.setValue(vartok, p.second); |
364 | 506 | setvar = true; |
365 | 506 | } |
366 | 1.04k | if (!setvar) { |
367 | 542 | if (!pm.hasValue(vartok->exprId())) { |
368 | 424 | const Token* valuetok = tok2->astOperand2(); |
369 | 424 | pm.setValue(vartok, execute(valuetok, pm)); |
370 | 424 | } |
371 | 542 | } |
372 | 12.8k | } else if (tok2->exprId() > 0 && Token::Match(tok2, ".|(|[|*|%var%") && !pm.hasValue(tok2->exprId()) && |
373 | 12.8k | isVariableChanged(tok2, 0, settings, true)) { |
374 | 312 | pm.setUnknown(tok2); |
375 | 312 | } |
376 | | |
377 | 13.8k | if (tok2->str() == "{") { |
378 | 1.67k | if (indentlevel <= 0) { |
379 | 1.58k | const Token* cond = getCondTokFromEnd(tok2->link()); |
380 | | // Keep progressing with anonymous/do scopes and always true branches |
381 | 1.58k | if (!Token::Match(tok2->previous(), "do|; {") && !conditionIsTrue(cond, state) && |
382 | 1.58k | (cond || !isBasicForLoop(tok2))) |
383 | 1.39k | break; |
384 | 1.58k | } else |
385 | 92 | --indentlevel; |
386 | 279 | if (Token::simpleMatch(tok2->previous(), "else {")) |
387 | 20 | tok2 = tok2->linkAt(-2)->previous(); |
388 | 279 | } |
389 | 12.4k | if (tok2->str() == "}") { |
390 | 298 | const Token *cond = getCondTokFromEnd(tok2); |
391 | 298 | const bool inElse = Token::simpleMatch(tok2->link()->previous(), "else {"); |
392 | 298 | if (cond) { |
393 | 298 | if (conditionIsFalse(cond, state)) { |
394 | 54 | if (inElse) { |
395 | 20 | ++indentlevel; |
396 | 20 | continue; |
397 | 20 | } |
398 | 244 | } else if (conditionIsTrue(cond, state)) { |
399 | 76 | if (inElse) |
400 | 22 | tok2 = tok2->link()->tokAt(-2); |
401 | 76 | ++indentlevel; |
402 | 76 | continue; |
403 | 76 | } |
404 | 298 | } |
405 | 202 | break; |
406 | 298 | } |
407 | 12.4k | } |
408 | 1.59k | } |
409 | | |
410 | | static void removeModifiedVars(ProgramMemory& pm, const Token* tok, const Token* origin) |
411 | 0 | { |
412 | 0 | pm.erase_if([&](const ExprIdToken& e) { |
413 | 0 | return isVariableChanged(origin, tok, e.getExpressionId(), false, nullptr, true); |
414 | 0 | }); |
415 | 0 | } |
416 | | |
417 | | static ProgramMemory getInitialProgramState(const Token* tok, |
418 | | const Token* origin, |
419 | | const Settings* settings, |
420 | | const ProgramMemory::Map& vars = ProgramMemory::Map {}) |
421 | 0 | { |
422 | 0 | ProgramMemory pm; |
423 | 0 | if (origin) { |
424 | 0 | fillProgramMemoryFromConditions(pm, origin, nullptr); |
425 | 0 | const ProgramMemory state = pm; |
426 | 0 | fillProgramMemoryFromAssignments(pm, tok, settings, state, vars); |
427 | 0 | removeModifiedVars(pm, tok, origin); |
428 | 0 | } |
429 | 0 | return pm; |
430 | 0 | } |
431 | | |
432 | 8.63k | ProgramMemoryState::ProgramMemoryState(const Settings* s) : settings(s) {} |
433 | | |
434 | | void ProgramMemoryState::insert(const ProgramMemory &pm, const Token* origin) |
435 | 0 | { |
436 | 0 | if (origin) |
437 | 0 | for (auto&& p : pm) |
438 | 0 | origins.insert(std::make_pair(p.first.getExpressionId(), origin)); |
439 | 0 | state.insert(pm); |
440 | 0 | } |
441 | | |
442 | | void ProgramMemoryState::replace(const ProgramMemory &pm, const Token* origin) |
443 | 2.00k | { |
444 | 2.00k | if (origin) |
445 | 2.00k | for (auto&& p : pm) |
446 | 4.35k | origins[p.first.getExpressionId()] = origin; |
447 | 2.00k | state.replace(pm); |
448 | 2.00k | } |
449 | | |
450 | | static void addVars(ProgramMemory& pm, const ProgramMemory::Map& vars) |
451 | 3.19k | { |
452 | 3.19k | for (const auto& p:vars) { |
453 | 3.19k | const ValueFlow::Value &value = p.second; |
454 | 3.19k | pm.setValue(p.first.tok, value); |
455 | 3.19k | } |
456 | 3.19k | } |
457 | | |
458 | | void ProgramMemoryState::addState(const Token* tok, const ProgramMemory::Map& vars) |
459 | 1.59k | { |
460 | 1.59k | ProgramMemory pm = state; |
461 | 1.59k | addVars(pm, vars); |
462 | 1.59k | fillProgramMemoryFromConditions(pm, tok, settings); |
463 | 1.59k | ProgramMemory local = pm; |
464 | 1.59k | fillProgramMemoryFromAssignments(pm, tok, settings, local, vars); |
465 | 1.59k | addVars(pm, vars); |
466 | 1.59k | replace(pm, tok); |
467 | 1.59k | } |
468 | | |
469 | | void ProgramMemoryState::assume(const Token* tok, bool b, bool isEmpty) |
470 | 408 | { |
471 | 408 | ProgramMemory pm = state; |
472 | 408 | if (isEmpty) |
473 | 0 | pm.setContainerSizeValue(tok, 0, b); |
474 | 408 | else |
475 | 408 | programMemoryParseCondition(pm, tok, nullptr, settings, b); |
476 | 408 | const Token* origin = tok; |
477 | 408 | const Token* top = tok->astTop(); |
478 | 408 | if (top && Token::Match(top->previous(), "for|while|if (") && !Token::simpleMatch(tok->astParent(), "?")) { |
479 | 408 | origin = top->link()->next(); |
480 | 408 | if (!b && origin->link()) { |
481 | 92 | origin = origin->link(); |
482 | 92 | } |
483 | 408 | } |
484 | 408 | replace(pm, origin); |
485 | 408 | } |
486 | | |
487 | | void ProgramMemoryState::removeModifiedVars(const Token* tok) |
488 | 1.55k | { |
489 | 1.55k | ProgramMemory pm = state; |
490 | 1.55k | auto eval = [&](const Token* cond) -> std::vector<MathLib::bigint> { |
491 | 1.38k | if (conditionIsTrue(cond, pm)) |
492 | 308 | return {1}; |
493 | 1.07k | if (conditionIsFalse(cond, pm)) |
494 | 188 | return {0}; |
495 | 888 | return {}; |
496 | 1.07k | }; |
497 | 1.55k | state.erase_if([&](const ExprIdToken& e) { |
498 | 1.33k | const Token* start = origins[e.getExpressionId()]; |
499 | 1.33k | const Token* expr = e.tok; |
500 | 1.33k | if (!expr || isExpressionChangedSkipDeadCode(expr, start, tok, settings, true, eval)) { |
501 | 332 | origins.erase(e.getExpressionId()); |
502 | 332 | return true; |
503 | 332 | } |
504 | 999 | return false; |
505 | 1.33k | }); |
506 | 1.55k | } |
507 | | |
508 | | ProgramMemory ProgramMemoryState::get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const |
509 | 831 | { |
510 | 831 | ProgramMemoryState local = *this; |
511 | 831 | if (ctx) |
512 | 4 | local.addState(ctx, vars); |
513 | 831 | const Token* start = previousBeforeAstLeftmostLeaf(tok); |
514 | 831 | if (!start) |
515 | 0 | start = tok; |
516 | | |
517 | 831 | if (!ctx || precedes(start, ctx)) { |
518 | 831 | local.removeModifiedVars(start); |
519 | 831 | local.addState(start, vars); |
520 | 831 | } else { |
521 | 0 | local.removeModifiedVars(ctx); |
522 | 0 | } |
523 | 831 | return local.state; |
524 | 831 | } |
525 | | |
526 | | ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings* settings) |
527 | 0 | { |
528 | 0 | ProgramMemory programMemory; |
529 | 0 | programMemory.replace(getInitialProgramState(tok, value.tokvalue, settings)); |
530 | 0 | programMemory.replace(getInitialProgramState(tok, value.condition, settings)); |
531 | 0 | fillProgramMemoryFromConditions(programMemory, tok, settings); |
532 | 0 | programMemory.setValue(expr, value); |
533 | 0 | const ProgramMemory state = programMemory; |
534 | 0 | fillProgramMemoryFromAssignments(programMemory, tok, settings, state, {{expr, value}}); |
535 | 0 | return programMemory; |
536 | 0 | } |
537 | | |
538 | 5.46k | static bool isNumericValue(const ValueFlow::Value& value) { |
539 | 5.46k | return value.isIntValue() || value.isFloatValue(); |
540 | 5.46k | } |
541 | | |
542 | | static double asFloat(const ValueFlow::Value& value) |
543 | 0 | { |
544 | 0 | return value.isFloatValue() ? value.floatValue : value.intvalue; |
545 | 0 | } |
546 | | |
547 | 0 | static std::string removeAssign(const std::string& assign) { |
548 | 0 | return std::string{assign.cbegin(), assign.cend() - 1}; |
549 | 0 | } |
550 | | |
551 | | struct assign { |
552 | | template<class T, class U> |
553 | | void operator()(T& x, const U& y) const |
554 | 0 | { |
555 | 0 | x = y; |
556 | 0 | } Unexecuted instantiation: void assign::operator()<long long, long long>(long long&, long long const&) const Unexecuted instantiation: void assign::operator()<long long, double>(long long&, double const&) const Unexecuted instantiation: void assign::operator()<double, long long>(double&, long long const&) const Unexecuted instantiation: void assign::operator()<double, double>(double&, double const&) const |
557 | | }; |
558 | | |
559 | | static bool isIntegralValue(const ValueFlow::Value& value) |
560 | 3.18k | { |
561 | 3.18k | return value.isIntValue() || value.isIteratorValue() || value.isSymbolicValue(); |
562 | 3.18k | } |
563 | | |
564 | | static ValueFlow::Value evaluate(const std::string& op, const ValueFlow::Value& lhs, const ValueFlow::Value& rhs) |
565 | 3.42k | { |
566 | 3.42k | ValueFlow::Value result; |
567 | 3.42k | combineValueProperties(lhs, rhs, result); |
568 | 3.42k | if (lhs.isImpossible() && rhs.isImpossible()) |
569 | 94 | return ValueFlow::Value::unknown(); |
570 | 3.33k | if (lhs.isImpossible() || rhs.isImpossible()) { |
571 | | // noninvertible |
572 | 836 | if (contains({"%", "/", "&", "|"}, op)) |
573 | 149 | return ValueFlow::Value::unknown(); |
574 | 687 | result.setImpossible(); |
575 | 687 | } |
576 | 3.18k | if (isNumericValue(lhs) && isNumericValue(rhs)) { |
577 | 1.51k | if (lhs.isFloatValue() || rhs.isFloatValue()) { |
578 | 0 | result.valueType = ValueFlow::Value::ValueType::FLOAT; |
579 | 0 | bool error = false; |
580 | 0 | result.floatValue = calculate(op, asFloat(lhs), asFloat(rhs), &error); |
581 | 0 | if (error) |
582 | 0 | return ValueFlow::Value::unknown(); |
583 | 0 | return result; |
584 | 0 | } |
585 | 1.51k | } |
586 | | // Must be integral types |
587 | 3.18k | if (!isIntegralValue(lhs) && !isIntegralValue(rhs)) |
588 | 0 | return ValueFlow::Value::unknown(); |
589 | | // If not the same type then one must be int |
590 | 3.18k | if (lhs.valueType != rhs.valueType && !lhs.isIntValue() && !rhs.isIntValue()) |
591 | 0 | return ValueFlow::Value::unknown(); |
592 | 3.18k | const bool compareOp = contains({"==", "!=", "<", ">", ">=", "<="}, op); |
593 | | // Comparison must be the same type |
594 | 3.18k | if (compareOp && lhs.valueType != rhs.valueType) |
595 | 512 | return ValueFlow::Value::unknown(); |
596 | | // Only add, subtract, and compare for non-integers |
597 | 2.67k | if (!compareOp && !contains({"+", "-"}, op) && !lhs.isIntValue() && !rhs.isIntValue()) |
598 | 280 | return ValueFlow::Value::unknown(); |
599 | | // Both can't be iterators for non-compare |
600 | 2.39k | if (!compareOp && lhs.isIteratorValue() && rhs.isIteratorValue()) |
601 | 0 | return ValueFlow::Value::unknown(); |
602 | | // Symbolic values must be in the same ring |
603 | 2.39k | if (lhs.isSymbolicValue() && rhs.isSymbolicValue() && lhs.tokvalue != rhs.tokvalue) |
604 | 0 | return ValueFlow::Value::unknown(); |
605 | 2.39k | if (!lhs.isIntValue() && !compareOp) { |
606 | 202 | result.valueType = lhs.valueType; |
607 | 202 | result.tokvalue = lhs.tokvalue; |
608 | 2.19k | } else if (!rhs.isIntValue() && !compareOp) { |
609 | 388 | result.valueType = rhs.valueType; |
610 | 388 | result.tokvalue = rhs.tokvalue; |
611 | 1.80k | } else { |
612 | 1.80k | result.valueType = ValueFlow::Value::ValueType::INT; |
613 | 1.80k | } |
614 | 2.39k | bool error = false; |
615 | 2.39k | result.intvalue = calculate(op, lhs.intvalue, rhs.intvalue, &error); |
616 | 2.39k | if (error) |
617 | 0 | return ValueFlow::Value::unknown(); |
618 | 2.39k | if (result.isImpossible() && op == "!=") { |
619 | 144 | if (isTrue(result)) { |
620 | 124 | result.intvalue = 1; |
621 | 124 | } else if (isFalse(result)) { |
622 | 0 | result.intvalue = 0; |
623 | 20 | } else { |
624 | 20 | return ValueFlow::Value::unknown(); |
625 | 20 | } |
626 | 124 | result.setPossible(); |
627 | 124 | result.bound = ValueFlow::Value::Bound::Point; |
628 | 124 | } |
629 | 2.37k | return result; |
630 | 2.39k | } |
631 | | |
632 | | using BuiltinLibraryFunction = std::function<ValueFlow::Value(const std::vector<ValueFlow::Value>&)>; |
633 | | static std::unordered_map<std::string, BuiltinLibraryFunction> createBuiltinLibraryFunctions() |
634 | 0 | { |
635 | 0 | std::unordered_map<std::string, BuiltinLibraryFunction> functions; |
636 | 0 | functions["strlen"] = [](const std::vector<ValueFlow::Value>& args) { |
637 | 0 | if (args.size() != 1) |
638 | 0 | return ValueFlow::Value::unknown(); |
639 | 0 | ValueFlow::Value v = args[0]; |
640 | 0 | if (!(v.isTokValue() && v.tokvalue->tokType() == Token::eString)) |
641 | 0 | return ValueFlow::Value::unknown(); |
642 | 0 | v.valueType = ValueFlow::Value::ValueType::INT; |
643 | 0 | v.intvalue = Token::getStrLength(v.tokvalue); |
644 | 0 | v.tokvalue = nullptr; |
645 | 0 | return v; |
646 | 0 | }; |
647 | 0 | functions["strcmp"] = [](const std::vector<ValueFlow::Value>& args) { |
648 | 0 | if (args.size() != 2) |
649 | 0 | return ValueFlow::Value::unknown(); |
650 | 0 | const ValueFlow::Value& lhs = args[0]; |
651 | 0 | if (!(lhs.isTokValue() && lhs.tokvalue->tokType() == Token::eString)) |
652 | 0 | return ValueFlow::Value::unknown(); |
653 | 0 | const ValueFlow::Value& rhs = args[1]; |
654 | 0 | if (!(rhs.isTokValue() && rhs.tokvalue->tokType() == Token::eString)) |
655 | 0 | return ValueFlow::Value::unknown(); |
656 | 0 | ValueFlow::Value v(getStringLiteral(lhs.tokvalue->str()).compare(getStringLiteral(rhs.tokvalue->str()))); |
657 | 0 | ValueFlow::combineValueProperties(lhs, rhs, v); |
658 | 0 | return v; |
659 | 0 | }; |
660 | 0 | functions["strncmp"] = [](const std::vector<ValueFlow::Value>& args) { |
661 | 0 | if (args.size() != 3) |
662 | 0 | return ValueFlow::Value::unknown(); |
663 | 0 | const ValueFlow::Value& lhs = args[0]; |
664 | 0 | if (!(lhs.isTokValue() && lhs.tokvalue->tokType() == Token::eString)) |
665 | 0 | return ValueFlow::Value::unknown(); |
666 | 0 | const ValueFlow::Value& rhs = args[1]; |
667 | 0 | if (!(rhs.isTokValue() && rhs.tokvalue->tokType() == Token::eString)) |
668 | 0 | return ValueFlow::Value::unknown(); |
669 | 0 | const ValueFlow::Value& len = args[2]; |
670 | 0 | if (!len.isIntValue()) |
671 | 0 | return ValueFlow::Value::unknown(); |
672 | 0 | ValueFlow::Value v(getStringLiteral(lhs.tokvalue->str()) |
673 | 0 | .compare(0, len.intvalue, getStringLiteral(rhs.tokvalue->str()), 0, len.intvalue)); |
674 | 0 | ValueFlow::combineValueProperties(lhs, rhs, v); |
675 | 0 | return v; |
676 | 0 | }; |
677 | 0 | functions["sin"] = [](const std::vector<ValueFlow::Value>& args) { |
678 | 0 | if (args.size() != 1) |
679 | 0 | return ValueFlow::Value::unknown(); |
680 | 0 | ValueFlow::Value v = args[0]; |
681 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
682 | 0 | return ValueFlow::Value::unknown(); |
683 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
684 | 0 | v.floatValue = std::sin(value); |
685 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
686 | 0 | return v; |
687 | 0 | }; |
688 | 0 | functions["lgamma"] = [](const std::vector<ValueFlow::Value>& args) { |
689 | 0 | if (args.size() != 1) |
690 | 0 | return ValueFlow::Value::unknown(); |
691 | 0 | ValueFlow::Value v = args[0]; |
692 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
693 | 0 | return ValueFlow::Value::unknown(); |
694 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
695 | 0 | v.floatValue = std::lgamma(value); |
696 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
697 | 0 | return v; |
698 | 0 | }; |
699 | 0 | functions["cos"] = [](const std::vector<ValueFlow::Value>& args) { |
700 | 0 | if (args.size() != 1) |
701 | 0 | return ValueFlow::Value::unknown(); |
702 | 0 | ValueFlow::Value v = args[0]; |
703 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
704 | 0 | return ValueFlow::Value::unknown(); |
705 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
706 | 0 | v.floatValue = std::cos(value); |
707 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
708 | 0 | return v; |
709 | 0 | }; |
710 | 0 | functions["tan"] = [](const std::vector<ValueFlow::Value>& args) { |
711 | 0 | if (args.size() != 1) |
712 | 0 | return ValueFlow::Value::unknown(); |
713 | 0 | ValueFlow::Value v = args[0]; |
714 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
715 | 0 | return ValueFlow::Value::unknown(); |
716 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
717 | 0 | v.floatValue = std::tan(value); |
718 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
719 | 0 | return v; |
720 | 0 | }; |
721 | 0 | functions["asin"] = [](const std::vector<ValueFlow::Value>& args) { |
722 | 0 | if (args.size() != 1) |
723 | 0 | return ValueFlow::Value::unknown(); |
724 | 0 | ValueFlow::Value v = args[0]; |
725 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
726 | 0 | return ValueFlow::Value::unknown(); |
727 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
728 | 0 | v.floatValue = std::asin(value); |
729 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
730 | 0 | return v; |
731 | 0 | }; |
732 | 0 | functions["acos"] = [](const std::vector<ValueFlow::Value>& args) { |
733 | 0 | if (args.size() != 1) |
734 | 0 | return ValueFlow::Value::unknown(); |
735 | 0 | ValueFlow::Value v = args[0]; |
736 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
737 | 0 | return ValueFlow::Value::unknown(); |
738 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
739 | 0 | v.floatValue = std::acos(value); |
740 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
741 | 0 | return v; |
742 | 0 | }; |
743 | 0 | functions["atan"] = [](const std::vector<ValueFlow::Value>& args) { |
744 | 0 | if (args.size() != 1) |
745 | 0 | return ValueFlow::Value::unknown(); |
746 | 0 | ValueFlow::Value v = args[0]; |
747 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
748 | 0 | return ValueFlow::Value::unknown(); |
749 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
750 | 0 | v.floatValue = std::atan(value); |
751 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
752 | 0 | return v; |
753 | 0 | }; |
754 | 0 | functions["atan2"] = [](const std::vector<ValueFlow::Value>& args) { |
755 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
756 | 0 | return v.isFloatValue() || v.isIntValue(); |
757 | 0 | })) |
758 | 0 | return ValueFlow::Value::unknown(); |
759 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
760 | 0 | ValueFlow::Value v; |
761 | 0 | combineValueProperties(args[0], args[1], v); |
762 | 0 | v.floatValue = std::atan2(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
763 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
764 | 0 | return v; |
765 | 0 | }; |
766 | 0 | functions["remainder"] = [](const std::vector<ValueFlow::Value>& args) { |
767 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
768 | 0 | return v.isFloatValue() || v.isIntValue(); |
769 | 0 | })) |
770 | 0 | return ValueFlow::Value::unknown(); |
771 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
772 | 0 | ValueFlow::Value v; |
773 | 0 | combineValueProperties(args[0], args[1], v); |
774 | 0 | v.floatValue = std::remainder(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
775 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
776 | 0 | return v; |
777 | 0 | }; |
778 | 0 | functions["nextafter"] = [](const std::vector<ValueFlow::Value>& args) { |
779 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
780 | 0 | return v.isFloatValue() || v.isIntValue(); |
781 | 0 | })) |
782 | 0 | return ValueFlow::Value::unknown(); |
783 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
784 | 0 | ValueFlow::Value v; |
785 | 0 | combineValueProperties(args[0], args[1], v); |
786 | 0 | v.floatValue = std::nextafter(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
787 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
788 | 0 | return v; |
789 | 0 | }; |
790 | 0 | functions["nexttoward"] = [](const std::vector<ValueFlow::Value>& args) { |
791 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
792 | 0 | return v.isFloatValue() || v.isIntValue(); |
793 | 0 | })) |
794 | 0 | return ValueFlow::Value::unknown(); |
795 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
796 | 0 | ValueFlow::Value v; |
797 | 0 | combineValueProperties(args[0], args[1], v); |
798 | 0 | v.floatValue = std::nexttoward(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
799 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
800 | 0 | return v; |
801 | 0 | }; |
802 | 0 | functions["hypot"] = [](const std::vector<ValueFlow::Value>& args) { |
803 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
804 | 0 | return v.isFloatValue() || v.isIntValue(); |
805 | 0 | })) |
806 | 0 | return ValueFlow::Value::unknown(); |
807 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
808 | 0 | ValueFlow::Value v; |
809 | 0 | combineValueProperties(args[0], args[1], v); |
810 | 0 | v.floatValue = std::hypot(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
811 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
812 | 0 | return v; |
813 | 0 | }; |
814 | 0 | functions["fdim"] = [](const std::vector<ValueFlow::Value>& args) { |
815 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
816 | 0 | return v.isFloatValue() || v.isIntValue(); |
817 | 0 | })) |
818 | 0 | return ValueFlow::Value::unknown(); |
819 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
820 | 0 | ValueFlow::Value v; |
821 | 0 | combineValueProperties(args[0], args[1], v); |
822 | 0 | v.floatValue = std::fdim(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
823 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
824 | 0 | return v; |
825 | 0 | }; |
826 | 0 | functions["fmax"] = [](const std::vector<ValueFlow::Value>& args) { |
827 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
828 | 0 | return v.isFloatValue() || v.isIntValue(); |
829 | 0 | })) |
830 | 0 | return ValueFlow::Value::unknown(); |
831 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
832 | 0 | ValueFlow::Value v; |
833 | 0 | combineValueProperties(args[0], args[1], v); |
834 | 0 | v.floatValue = std::fmax(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
835 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
836 | 0 | return v; |
837 | 0 | }; |
838 | 0 | functions["fmin"] = [](const std::vector<ValueFlow::Value>& args) { |
839 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
840 | 0 | return v.isFloatValue() || v.isIntValue(); |
841 | 0 | })) |
842 | 0 | return ValueFlow::Value::unknown(); |
843 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
844 | 0 | ValueFlow::Value v; |
845 | 0 | combineValueProperties(args[0], args[1], v); |
846 | 0 | v.floatValue = std::fmin(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
847 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
848 | 0 | return v; |
849 | 0 | }; |
850 | 0 | functions["fmod"] = [](const std::vector<ValueFlow::Value>& args) { |
851 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
852 | 0 | return v.isFloatValue() || v.isIntValue(); |
853 | 0 | })) |
854 | 0 | return ValueFlow::Value::unknown(); |
855 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
856 | 0 | ValueFlow::Value v; |
857 | 0 | combineValueProperties(args[0], args[1], v); |
858 | 0 | v.floatValue = std::fmod(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
859 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
860 | 0 | return v; |
861 | 0 | }; |
862 | 0 | functions["pow"] = [](const std::vector<ValueFlow::Value>& args) { |
863 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
864 | 0 | return v.isFloatValue() || v.isIntValue(); |
865 | 0 | })) |
866 | 0 | return ValueFlow::Value::unknown(); |
867 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
868 | 0 | ValueFlow::Value v; |
869 | 0 | combineValueProperties(args[0], args[1], v); |
870 | 0 | v.floatValue = std::pow(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
871 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
872 | 0 | return v; |
873 | 0 | }; |
874 | 0 | functions["scalbln"] = [](const std::vector<ValueFlow::Value>& args) { |
875 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
876 | 0 | return v.isFloatValue() || v.isIntValue(); |
877 | 0 | })) |
878 | 0 | return ValueFlow::Value::unknown(); |
879 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
880 | 0 | ValueFlow::Value v; |
881 | 0 | combineValueProperties(args[0], args[1], v); |
882 | 0 | v.floatValue = std::scalbln(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
883 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
884 | 0 | return v; |
885 | 0 | }; |
886 | 0 | functions["ldexp"] = [](const std::vector<ValueFlow::Value>& args) { |
887 | 0 | if (args.size() != 2 || !std::all_of(args.cbegin(), args.cend(), [](const ValueFlow::Value& v) { |
888 | 0 | return v.isFloatValue() || v.isIntValue(); |
889 | 0 | })) |
890 | 0 | return ValueFlow::Value::unknown(); |
891 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
892 | 0 | ValueFlow::Value v; |
893 | 0 | combineValueProperties(args[0], args[1], v); |
894 | 0 | v.floatValue = std::ldexp(value, args[1].isFloatValue() ? args[1].floatValue : args[1].intvalue); |
895 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
896 | 0 | return v; |
897 | 0 | }; |
898 | 0 | functions["ilogb"] = [](const std::vector<ValueFlow::Value>& args) { |
899 | 0 | if (args.size() != 1) |
900 | 0 | return ValueFlow::Value::unknown(); |
901 | 0 | ValueFlow::Value v = args[0]; |
902 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
903 | 0 | return ValueFlow::Value::unknown(); |
904 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
905 | 0 | v.intvalue = std::ilogb(value); |
906 | 0 | v.valueType = ValueFlow::Value::ValueType::INT; |
907 | 0 | return v; |
908 | 0 | }; |
909 | 0 | functions["erf"] = [](const std::vector<ValueFlow::Value>& args) { |
910 | 0 | if (args.size() != 1) |
911 | 0 | return ValueFlow::Value::unknown(); |
912 | 0 | ValueFlow::Value v = args[0]; |
913 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
914 | 0 | return ValueFlow::Value::unknown(); |
915 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
916 | 0 | v.floatValue = std::erf(value); |
917 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
918 | 0 | return v; |
919 | 0 | }; |
920 | 0 | functions["erfc"] = [](const std::vector<ValueFlow::Value>& args) { |
921 | 0 | if (args.size() != 1) |
922 | 0 | return ValueFlow::Value::unknown(); |
923 | 0 | ValueFlow::Value v = args[0]; |
924 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
925 | 0 | return ValueFlow::Value::unknown(); |
926 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
927 | 0 | v.floatValue = std::erfc(value); |
928 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
929 | 0 | return v; |
930 | 0 | }; |
931 | 0 | functions["floor"] = [](const std::vector<ValueFlow::Value>& args) { |
932 | 0 | if (args.size() != 1) |
933 | 0 | return ValueFlow::Value::unknown(); |
934 | 0 | ValueFlow::Value v = args[0]; |
935 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
936 | 0 | return ValueFlow::Value::unknown(); |
937 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
938 | 0 | v.floatValue = std::floor(value); |
939 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
940 | 0 | return v; |
941 | 0 | }; |
942 | 0 | functions["sqrt"] = [](const std::vector<ValueFlow::Value>& args) { |
943 | 0 | if (args.size() != 1) |
944 | 0 | return ValueFlow::Value::unknown(); |
945 | 0 | ValueFlow::Value v = args[0]; |
946 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
947 | 0 | return ValueFlow::Value::unknown(); |
948 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
949 | 0 | v.floatValue = std::sqrt(value); |
950 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
951 | 0 | return v; |
952 | 0 | }; |
953 | 0 | functions["cbrt"] = [](const std::vector<ValueFlow::Value>& args) { |
954 | 0 | if (args.size() != 1) |
955 | 0 | return ValueFlow::Value::unknown(); |
956 | 0 | ValueFlow::Value v = args[0]; |
957 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
958 | 0 | return ValueFlow::Value::unknown(); |
959 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
960 | 0 | v.floatValue = std::cbrt(value); |
961 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
962 | 0 | return v; |
963 | 0 | }; |
964 | 0 | functions["ceil"] = [](const std::vector<ValueFlow::Value>& args) { |
965 | 0 | if (args.size() != 1) |
966 | 0 | return ValueFlow::Value::unknown(); |
967 | 0 | ValueFlow::Value v = args[0]; |
968 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
969 | 0 | return ValueFlow::Value::unknown(); |
970 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
971 | 0 | v.floatValue = std::ceil(value); |
972 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
973 | 0 | return v; |
974 | 0 | }; |
975 | 0 | functions["exp"] = [](const std::vector<ValueFlow::Value>& args) { |
976 | 0 | if (args.size() != 1) |
977 | 0 | return ValueFlow::Value::unknown(); |
978 | 0 | ValueFlow::Value v = args[0]; |
979 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
980 | 0 | return ValueFlow::Value::unknown(); |
981 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
982 | 0 | v.floatValue = std::exp(value); |
983 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
984 | 0 | return v; |
985 | 0 | }; |
986 | 0 | functions["exp2"] = [](const std::vector<ValueFlow::Value>& args) { |
987 | 0 | if (args.size() != 1) |
988 | 0 | return ValueFlow::Value::unknown(); |
989 | 0 | ValueFlow::Value v = args[0]; |
990 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
991 | 0 | return ValueFlow::Value::unknown(); |
992 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
993 | 0 | v.floatValue = std::exp2(value); |
994 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
995 | 0 | return v; |
996 | 0 | }; |
997 | 0 | functions["expm1"] = [](const std::vector<ValueFlow::Value>& args) { |
998 | 0 | if (args.size() != 1) |
999 | 0 | return ValueFlow::Value::unknown(); |
1000 | 0 | ValueFlow::Value v = args[0]; |
1001 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1002 | 0 | return ValueFlow::Value::unknown(); |
1003 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1004 | 0 | v.floatValue = std::expm1(value); |
1005 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1006 | 0 | return v; |
1007 | 0 | }; |
1008 | 0 | functions["fabs"] = [](const std::vector<ValueFlow::Value>& args) { |
1009 | 0 | if (args.size() != 1) |
1010 | 0 | return ValueFlow::Value::unknown(); |
1011 | 0 | ValueFlow::Value v = args[0]; |
1012 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1013 | 0 | return ValueFlow::Value::unknown(); |
1014 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1015 | 0 | v.floatValue = std::fabs(value); |
1016 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1017 | 0 | return v; |
1018 | 0 | }; |
1019 | 0 | functions["log"] = [](const std::vector<ValueFlow::Value>& args) { |
1020 | 0 | if (args.size() != 1) |
1021 | 0 | return ValueFlow::Value::unknown(); |
1022 | 0 | ValueFlow::Value v = args[0]; |
1023 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1024 | 0 | return ValueFlow::Value::unknown(); |
1025 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1026 | 0 | v.floatValue = std::log(value); |
1027 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1028 | 0 | return v; |
1029 | 0 | }; |
1030 | 0 | functions["log10"] = [](const std::vector<ValueFlow::Value>& args) { |
1031 | 0 | if (args.size() != 1) |
1032 | 0 | return ValueFlow::Value::unknown(); |
1033 | 0 | ValueFlow::Value v = args[0]; |
1034 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1035 | 0 | return ValueFlow::Value::unknown(); |
1036 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1037 | 0 | v.floatValue = std::log10(value); |
1038 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1039 | 0 | return v; |
1040 | 0 | }; |
1041 | 0 | functions["log1p"] = [](const std::vector<ValueFlow::Value>& args) { |
1042 | 0 | if (args.size() != 1) |
1043 | 0 | return ValueFlow::Value::unknown(); |
1044 | 0 | ValueFlow::Value v = args[0]; |
1045 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1046 | 0 | return ValueFlow::Value::unknown(); |
1047 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1048 | 0 | v.floatValue = std::log1p(value); |
1049 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1050 | 0 | return v; |
1051 | 0 | }; |
1052 | 0 | functions["log2"] = [](const std::vector<ValueFlow::Value>& args) { |
1053 | 0 | if (args.size() != 1) |
1054 | 0 | return ValueFlow::Value::unknown(); |
1055 | 0 | ValueFlow::Value v = args[0]; |
1056 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1057 | 0 | return ValueFlow::Value::unknown(); |
1058 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1059 | 0 | v.floatValue = std::log2(value); |
1060 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1061 | 0 | return v; |
1062 | 0 | }; |
1063 | 0 | functions["logb"] = [](const std::vector<ValueFlow::Value>& args) { |
1064 | 0 | if (args.size() != 1) |
1065 | 0 | return ValueFlow::Value::unknown(); |
1066 | 0 | ValueFlow::Value v = args[0]; |
1067 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1068 | 0 | return ValueFlow::Value::unknown(); |
1069 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1070 | 0 | v.floatValue = std::logb(value); |
1071 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1072 | 0 | return v; |
1073 | 0 | }; |
1074 | 0 | functions["nearbyint"] = [](const std::vector<ValueFlow::Value>& args) { |
1075 | 0 | if (args.size() != 1) |
1076 | 0 | return ValueFlow::Value::unknown(); |
1077 | 0 | ValueFlow::Value v = args[0]; |
1078 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1079 | 0 | return ValueFlow::Value::unknown(); |
1080 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1081 | 0 | v.floatValue = std::nearbyint(value); |
1082 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1083 | 0 | return v; |
1084 | 0 | }; |
1085 | 0 | functions["sinh"] = [](const std::vector<ValueFlow::Value>& args) { |
1086 | 0 | if (args.size() != 1) |
1087 | 0 | return ValueFlow::Value::unknown(); |
1088 | 0 | ValueFlow::Value v = args[0]; |
1089 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1090 | 0 | return ValueFlow::Value::unknown(); |
1091 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1092 | 0 | v.floatValue = std::sinh(value); |
1093 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1094 | 0 | return v; |
1095 | 0 | }; |
1096 | 0 | functions["cosh"] = [](const std::vector<ValueFlow::Value>& args) { |
1097 | 0 | if (args.size() != 1) |
1098 | 0 | return ValueFlow::Value::unknown(); |
1099 | 0 | ValueFlow::Value v = args[0]; |
1100 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1101 | 0 | return ValueFlow::Value::unknown(); |
1102 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1103 | 0 | v.floatValue = std::cosh(value); |
1104 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1105 | 0 | return v; |
1106 | 0 | }; |
1107 | 0 | functions["tanh"] = [](const std::vector<ValueFlow::Value>& args) { |
1108 | 0 | if (args.size() != 1) |
1109 | 0 | return ValueFlow::Value::unknown(); |
1110 | 0 | ValueFlow::Value v = args[0]; |
1111 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1112 | 0 | return ValueFlow::Value::unknown(); |
1113 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1114 | 0 | v.floatValue = std::tanh(value); |
1115 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1116 | 0 | return v; |
1117 | 0 | }; |
1118 | 0 | functions["asinh"] = [](const std::vector<ValueFlow::Value>& args) { |
1119 | 0 | if (args.size() != 1) |
1120 | 0 | return ValueFlow::Value::unknown(); |
1121 | 0 | ValueFlow::Value v = args[0]; |
1122 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1123 | 0 | return ValueFlow::Value::unknown(); |
1124 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1125 | 0 | v.floatValue = std::asinh(value); |
1126 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1127 | 0 | return v; |
1128 | 0 | }; |
1129 | 0 | functions["acosh"] = [](const std::vector<ValueFlow::Value>& args) { |
1130 | 0 | if (args.size() != 1) |
1131 | 0 | return ValueFlow::Value::unknown(); |
1132 | 0 | ValueFlow::Value v = args[0]; |
1133 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1134 | 0 | return ValueFlow::Value::unknown(); |
1135 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1136 | 0 | v.floatValue = std::acosh(value); |
1137 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1138 | 0 | return v; |
1139 | 0 | }; |
1140 | 0 | functions["atanh"] = [](const std::vector<ValueFlow::Value>& args) { |
1141 | 0 | if (args.size() != 1) |
1142 | 0 | return ValueFlow::Value::unknown(); |
1143 | 0 | ValueFlow::Value v = args[0]; |
1144 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1145 | 0 | return ValueFlow::Value::unknown(); |
1146 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1147 | 0 | v.floatValue = std::atanh(value); |
1148 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1149 | 0 | return v; |
1150 | 0 | }; |
1151 | 0 | functions["round"] = [](const std::vector<ValueFlow::Value>& args) { |
1152 | 0 | if (args.size() != 1) |
1153 | 0 | return ValueFlow::Value::unknown(); |
1154 | 0 | ValueFlow::Value v = args[0]; |
1155 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1156 | 0 | return ValueFlow::Value::unknown(); |
1157 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1158 | 0 | v.floatValue = std::round(value); |
1159 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1160 | 0 | return v; |
1161 | 0 | }; |
1162 | 0 | functions["tgamma"] = [](const std::vector<ValueFlow::Value>& args) { |
1163 | 0 | if (args.size() != 1) |
1164 | 0 | return ValueFlow::Value::unknown(); |
1165 | 0 | ValueFlow::Value v = args[0]; |
1166 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1167 | 0 | return ValueFlow::Value::unknown(); |
1168 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1169 | 0 | v.floatValue = std::tgamma(value); |
1170 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1171 | 0 | return v; |
1172 | 0 | }; |
1173 | 0 | functions["trunc"] = [](const std::vector<ValueFlow::Value>& args) { |
1174 | 0 | if (args.size() != 1) |
1175 | 0 | return ValueFlow::Value::unknown(); |
1176 | 0 | ValueFlow::Value v = args[0]; |
1177 | 0 | if (!v.isFloatValue() && !v.isIntValue()) |
1178 | 0 | return ValueFlow::Value::unknown(); |
1179 | 0 | const double value = args[0].isFloatValue() ? args[0].floatValue : args[0].intvalue; |
1180 | 0 | v.floatValue = std::trunc(value); |
1181 | 0 | v.valueType = ValueFlow::Value::ValueType::FLOAT; |
1182 | 0 | return v; |
1183 | 0 | }; |
1184 | 0 | return functions; |
1185 | 0 | } |
1186 | | |
1187 | | static BuiltinLibraryFunction getBuiltinLibraryFunction(const std::string& name) |
1188 | 0 | { |
1189 | 0 | static const std::unordered_map<std::string, BuiltinLibraryFunction> functions = createBuiltinLibraryFunctions(); |
1190 | 0 | auto it = functions.find(name); |
1191 | 0 | if (it == functions.end()) |
1192 | 0 | return nullptr; |
1193 | 0 | return it->second; |
1194 | 0 | } |
1195 | | |
1196 | | struct Executor { |
1197 | | ProgramMemory* pm = nullptr; |
1198 | | const Settings* settings = nullptr; |
1199 | | int fdepth = 4; |
1200 | | |
1201 | 9.07k | explicit Executor(ProgramMemory* pm = nullptr, const Settings* settings = nullptr) : pm(pm), settings(settings) {} |
1202 | | |
1203 | | ValueFlow::Value executeImpl(const Token* expr) |
1204 | 32.7k | { |
1205 | 32.7k | ValueFlow::Value unknown = ValueFlow::Value::unknown(); |
1206 | 32.7k | const ValueFlow::Value* value = nullptr; |
1207 | 32.7k | if (!expr) |
1208 | 0 | return unknown; |
1209 | 32.7k | if (expr->hasKnownIntValue() && !expr->isAssignmentOp() && expr->str() != ",") |
1210 | 3.87k | return expr->values().front(); |
1211 | 28.9k | if ((value = expr->getKnownValue(ValueFlow::Value::ValueType::FLOAT)) || |
1212 | 28.9k | (value = expr->getKnownValue(ValueFlow::Value::ValueType::TOK)) || |
1213 | 28.9k | (value = expr->getKnownValue(ValueFlow::Value::ValueType::ITERATOR_START)) || |
1214 | 28.9k | (value = expr->getKnownValue(ValueFlow::Value::ValueType::ITERATOR_END)) || |
1215 | 28.9k | (value = expr->getKnownValue(ValueFlow::Value::ValueType::CONTAINER_SIZE))) { |
1216 | 0 | return *value; |
1217 | 0 | } |
1218 | 28.9k | if (expr->isNumber()) { |
1219 | 0 | if (MathLib::isFloat(expr->str())) |
1220 | 0 | return unknown; |
1221 | 0 | MathLib::bigint i = MathLib::toLongNumber(expr->str()); |
1222 | 0 | if (i < 0 && astIsUnsigned(expr)) |
1223 | 0 | return unknown; |
1224 | 0 | return ValueFlow::Value{i}; |
1225 | 0 | } |
1226 | 28.9k | if (expr->isBoolean()) |
1227 | 0 | return ValueFlow::Value{expr->str() == "true"}; |
1228 | 28.9k | if (Token::Match(expr->tokAt(-2), ". %name% (") && astIsContainer(expr->tokAt(-2)->astOperand1())) { |
1229 | 0 | const Token* containerTok = expr->tokAt(-2)->astOperand1(); |
1230 | 0 | const Library::Container::Yield yield = containerTok->valueType()->container->getYield(expr->strAt(-1)); |
1231 | 0 | if (yield == Library::Container::Yield::SIZE) { |
1232 | 0 | ValueFlow::Value v = execute(containerTok); |
1233 | 0 | if (!v.isContainerSizeValue()) |
1234 | 0 | return unknown; |
1235 | 0 | v.valueType = ValueFlow::Value::ValueType::INT; |
1236 | 0 | return v; |
1237 | 0 | } |
1238 | 0 | if (yield == Library::Container::Yield::EMPTY) { |
1239 | 0 | ValueFlow::Value v = execute(containerTok); |
1240 | 0 | if (!v.isContainerSizeValue()) |
1241 | 0 | return unknown; |
1242 | 0 | if (v.isImpossible() && v.intvalue == 0) |
1243 | 0 | return ValueFlow::Value{0}; |
1244 | 0 | if (!v.isImpossible()) |
1245 | 0 | return ValueFlow::Value{v.intvalue == 0}; |
1246 | 0 | } |
1247 | 28.9k | } else if (expr->isAssignmentOp() && expr->astOperand1() && expr->astOperand2() && |
1248 | 28.9k | expr->astOperand1()->exprId() > 0) { |
1249 | 513 | ValueFlow::Value rhs = execute(expr->astOperand2()); |
1250 | 513 | if (rhs.isUninitValue()) |
1251 | 208 | return unknown; |
1252 | 305 | if (expr->str() != "=") { |
1253 | 0 | if (!pm->hasValue(expr->astOperand1()->exprId())) |
1254 | 0 | return unknown; |
1255 | 0 | ValueFlow::Value& lhs = pm->at(expr->astOperand1()->exprId()); |
1256 | 0 | rhs = evaluate(removeAssign(expr->str()), lhs, rhs); |
1257 | 0 | if (lhs.isIntValue()) |
1258 | 0 | ValueFlow::Value::visitValue(rhs, std::bind(assign{}, std::ref(lhs.intvalue), std::placeholders::_1)); |
1259 | 0 | else if (lhs.isFloatValue()) |
1260 | 0 | ValueFlow::Value::visitValue(rhs, |
1261 | 0 | std::bind(assign{}, std::ref(lhs.floatValue), std::placeholders::_1)); |
1262 | 0 | else |
1263 | 0 | return unknown; |
1264 | 0 | return lhs; |
1265 | 0 | } |
1266 | 305 | pm->setValue(expr->astOperand1(), rhs); |
1267 | 305 | return rhs; |
1268 | 28.3k | } else if (expr->str() == "&&" && expr->astOperand1() && expr->astOperand2()) { |
1269 | 0 | ValueFlow::Value lhs = execute(expr->astOperand1()); |
1270 | 0 | if (!lhs.isIntValue()) |
1271 | 0 | return unknown; |
1272 | 0 | if (isFalse(lhs)) |
1273 | 0 | return lhs; |
1274 | 0 | if (isTrue(lhs)) |
1275 | 0 | return execute(expr->astOperand2()); |
1276 | 0 | return unknown; |
1277 | 28.3k | } else if (expr->str() == "||" && expr->astOperand1() && expr->astOperand2()) { |
1278 | 0 | ValueFlow::Value lhs = execute(expr->astOperand1()); |
1279 | 0 | if (!lhs.isIntValue() || lhs.isImpossible()) |
1280 | 0 | return unknown; |
1281 | 0 | if (isTrue(lhs)) |
1282 | 0 | return lhs; |
1283 | 0 | if (isFalse(lhs)) |
1284 | 0 | return execute(expr->astOperand2()); |
1285 | 0 | return unknown; |
1286 | 28.3k | } else if (expr->str() == "," && expr->astOperand1() && expr->astOperand2()) { |
1287 | 0 | execute(expr->astOperand1()); |
1288 | 0 | return execute(expr->astOperand2()); |
1289 | 28.3k | } else if (expr->tokType() == Token::eIncDecOp && expr->astOperand1() && expr->astOperand1()->exprId() != 0) { |
1290 | 3.99k | if (!pm->hasValue(expr->astOperand1()->exprId())) |
1291 | 2.45k | return unknown; |
1292 | 1.53k | ValueFlow::Value& lhs = pm->at(expr->astOperand1()->exprId()); |
1293 | 1.53k | if (!lhs.isIntValue()) |
1294 | 1.05k | return unknown; |
1295 | | // overflow |
1296 | 481 | if (!lhs.isImpossible() && lhs.intvalue == 0 && expr->str() == "--" && astIsUnsigned(expr->astOperand1())) |
1297 | 0 | return unknown; |
1298 | | |
1299 | 481 | if (expr->str() == "++") |
1300 | 201 | lhs.intvalue++; |
1301 | 280 | else |
1302 | 280 | lhs.intvalue--; |
1303 | 481 | return lhs; |
1304 | 24.4k | } else if (expr->str() == "[" && expr->astOperand1() && expr->astOperand2()) { |
1305 | 0 | const Token* tokvalue = nullptr; |
1306 | 0 | if (!pm->getTokValue(expr->astOperand1()->exprId(), &tokvalue)) { |
1307 | 0 | auto tokvalue_it = std::find_if(expr->astOperand1()->values().cbegin(), |
1308 | 0 | expr->astOperand1()->values().cend(), |
1309 | 0 | std::mem_fn(&ValueFlow::Value::isTokValue)); |
1310 | 0 | if (tokvalue_it == expr->astOperand1()->values().cend() || !tokvalue_it->isKnown()) { |
1311 | 0 | return unknown; |
1312 | 0 | } |
1313 | 0 | tokvalue = tokvalue_it->tokvalue; |
1314 | 0 | } |
1315 | 0 | if (!tokvalue || !tokvalue->isLiteral()) { |
1316 | 0 | return unknown; |
1317 | 0 | } |
1318 | 0 | const std::string strValue = tokvalue->strValue(); |
1319 | 0 | ValueFlow::Value rhs = execute(expr->astOperand2()); |
1320 | 0 | if (!rhs.isIntValue()) |
1321 | 0 | return unknown; |
1322 | 0 | const MathLib::bigint index = rhs.intvalue; |
1323 | 0 | if (index >= 0 && index < strValue.size()) |
1324 | 0 | return ValueFlow::Value{strValue[index]}; |
1325 | 0 | if (index == strValue.size()) |
1326 | 0 | return ValueFlow::Value{}; |
1327 | 24.4k | } else if (Token::Match(expr, "%cop%") && expr->astOperand1() && expr->astOperand2()) { |
1328 | 11.5k | ValueFlow::Value lhs = execute(expr->astOperand1()); |
1329 | 11.5k | ValueFlow::Value rhs = execute(expr->astOperand2()); |
1330 | 11.5k | ValueFlow::Value r = unknown; |
1331 | 11.5k | if (!lhs.isUninitValue() && !rhs.isUninitValue()) |
1332 | 3.42k | r = evaluate(expr->str(), lhs, rhs); |
1333 | 11.5k | if (expr->isComparisonOp() && (r.isUninitValue() || r.isImpossible())) { |
1334 | 5.42k | if (rhs.isIntValue()) { |
1335 | 934 | std::vector<ValueFlow::Value> result = |
1336 | 934 | infer(ValueFlow::makeIntegralInferModel(), expr->str(), expr->astOperand1()->values(), {rhs}); |
1337 | 934 | if (!result.empty() && result.front().isKnown()) |
1338 | 59 | return result.front(); |
1339 | 934 | } |
1340 | 5.36k | if (lhs.isIntValue()) { |
1341 | 1.30k | std::vector<ValueFlow::Value> result = |
1342 | 1.30k | infer(ValueFlow::makeIntegralInferModel(), expr->str(), {lhs}, expr->astOperand2()->values()); |
1343 | 1.30k | if (!result.empty() && result.front().isKnown()) |
1344 | 52 | return result.front(); |
1345 | 1.30k | } |
1346 | 5.31k | return unknown; |
1347 | 5.36k | } |
1348 | 6.17k | return r; |
1349 | 11.5k | } |
1350 | | // Unary ops |
1351 | 12.8k | else if (Token::Match(expr, "!|+|-") && expr->astOperand1() && !expr->astOperand2()) { |
1352 | 0 | ValueFlow::Value lhs = execute(expr->astOperand1()); |
1353 | 0 | if (!lhs.isIntValue()) |
1354 | 0 | return unknown; |
1355 | 0 | if (expr->str() == "!") { |
1356 | 0 | if (isTrue(lhs)) { |
1357 | 0 | lhs.intvalue = 0; |
1358 | 0 | } else if (isFalse(lhs)) { |
1359 | 0 | lhs.intvalue = 1; |
1360 | 0 | } else { |
1361 | 0 | return unknown; |
1362 | 0 | } |
1363 | 0 | lhs.setPossible(); |
1364 | 0 | lhs.bound = ValueFlow::Value::Bound::Point; |
1365 | 0 | } |
1366 | 0 | if (expr->str() == "-") |
1367 | 0 | lhs.intvalue = -lhs.intvalue; |
1368 | 0 | return lhs; |
1369 | 12.8k | } else if (expr->str() == "?" && expr->astOperand1() && expr->astOperand2()) { |
1370 | 0 | ValueFlow::Value cond = execute(expr->astOperand1()); |
1371 | 0 | if (!cond.isIntValue()) |
1372 | 0 | return unknown; |
1373 | 0 | const Token* child = expr->astOperand2(); |
1374 | 0 | if (isFalse(cond)) |
1375 | 0 | return execute(child->astOperand2()); |
1376 | 0 | if (isTrue(cond)) |
1377 | 0 | return execute(child->astOperand1()); |
1378 | | |
1379 | 0 | return unknown; |
1380 | 12.8k | } else if (expr->str() == "(" && expr->isCast()) { |
1381 | 0 | if (Token::simpleMatch(expr->previous(), ">") && expr->previous()->link()) |
1382 | 0 | return execute(expr->astOperand2()); |
1383 | 0 | return execute(expr->astOperand1()); |
1384 | 0 | } |
1385 | 12.8k | if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) { |
1386 | 5.30k | ValueFlow::Value result = pm->at(expr->exprId()); |
1387 | 5.30k | if (result.isImpossible() && result.isIntValue() && result.intvalue == 0 && isUsedAsBool(expr)) { |
1388 | 0 | result.intvalue = !result.intvalue; |
1389 | 0 | result.setKnown(); |
1390 | 0 | } |
1391 | 5.30k | return result; |
1392 | 5.30k | } |
1393 | | |
1394 | 7.50k | if (Token::Match(expr->previous(), ">|%name% {|(")) { |
1395 | 0 | const Token* ftok = expr->previous(); |
1396 | 0 | const Function* f = ftok->function(); |
1397 | 0 | ValueFlow::Value result = unknown; |
1398 | 0 | if (settings && expr->str() == "(") { |
1399 | 0 | std::vector<const Token*> tokArgs = getArguments(expr); |
1400 | 0 | std::vector<ValueFlow::Value> args(tokArgs.size()); |
1401 | 0 | std::transform(tokArgs.cbegin(), tokArgs.cend(), args.begin(), [&](const Token* tok) { |
1402 | 0 | return execute(tok); |
1403 | 0 | }); |
1404 | 0 | if (f) { |
1405 | 0 | if (fdepth >= 0 && !f->isImplicitlyVirtual()) { |
1406 | 0 | ProgramMemory functionState; |
1407 | 0 | for (std::size_t i = 0; i < args.size(); ++i) { |
1408 | 0 | const Variable* const arg = f->getArgumentVar(i); |
1409 | 0 | if (!arg) |
1410 | 0 | return unknown; |
1411 | 0 | functionState.setValue(arg->nameToken(), args[i]); |
1412 | 0 | } |
1413 | 0 | Executor ex = *this; |
1414 | 0 | ex.pm = &functionState; |
1415 | 0 | ex.fdepth--; |
1416 | 0 | auto r = ex.execute(f->functionScope); |
1417 | 0 | if (!r.empty()) |
1418 | 0 | result = r.front(); |
1419 | | // TODO: Track values changed by reference |
1420 | 0 | } |
1421 | 0 | } else { |
1422 | 0 | BuiltinLibraryFunction lf = getBuiltinLibraryFunction(ftok->str()); |
1423 | 0 | if (lf) |
1424 | 0 | return lf(args); |
1425 | 0 | const std::string& returnValue = settings->library.returnValue(ftok); |
1426 | 0 | if (!returnValue.empty()) { |
1427 | 0 | std::unordered_map<nonneg int, ValueFlow::Value> arg_map; |
1428 | 0 | int argn = 0; |
1429 | 0 | for (const ValueFlow::Value& v : args) { |
1430 | 0 | if (!v.isUninitValue()) |
1431 | 0 | arg_map[argn] = v; |
1432 | 0 | argn++; |
1433 | 0 | } |
1434 | 0 | return evaluateLibraryFunction(arg_map, returnValue, settings); |
1435 | 0 | } |
1436 | 0 | } |
1437 | 0 | } |
1438 | | // Check if function modifies argument |
1439 | 0 | visitAstNodes(expr->astOperand2(), [&](const Token* child) { |
1440 | 0 | if (child->exprId() > 0 && pm->hasValue(child->exprId())) { |
1441 | 0 | ValueFlow::Value& v = pm->at(child->exprId()); |
1442 | 0 | if (v.valueType == ValueFlow::Value::ValueType::CONTAINER_SIZE) { |
1443 | 0 | if (ValueFlow::isContainerSizeChanged(child, v.indirect, settings)) |
1444 | 0 | v = unknown; |
1445 | 0 | } else if (v.valueType != ValueFlow::Value::ValueType::UNINIT) { |
1446 | 0 | if (isVariableChanged(child, v.indirect, settings, true)) |
1447 | 0 | v = unknown; |
1448 | 0 | } |
1449 | 0 | } |
1450 | 0 | return ChildrenToVisit::op1_and_op2; |
1451 | 0 | }); |
1452 | 0 | return result; |
1453 | 0 | } |
1454 | | |
1455 | 7.50k | return unknown; |
1456 | 7.50k | } |
1457 | | static const ValueFlow::Value* getImpossibleValue(const Token* tok) |
1458 | 19.8k | { |
1459 | 19.8k | if (!tok) |
1460 | 0 | return nullptr; |
1461 | 19.8k | std::vector<const ValueFlow::Value*> values; |
1462 | 19.8k | for (const ValueFlow::Value& v : tok->values()) { |
1463 | 11.0k | if (!v.isImpossible()) |
1464 | 525 | continue; |
1465 | 10.5k | if (v.isContainerSizeValue() || v.isIntValue()) { |
1466 | 10.5k | values.push_back(std::addressof(v)); |
1467 | 10.5k | } |
1468 | 10.5k | } |
1469 | 19.8k | auto it = |
1470 | 19.8k | std::max_element(values.begin(), values.end(), [](const ValueFlow::Value* x, const ValueFlow::Value* y) { |
1471 | 5.17k | return x->intvalue < y->intvalue; |
1472 | 5.17k | }); |
1473 | 19.8k | if (it == values.end()) |
1474 | 14.5k | return nullptr; |
1475 | 5.32k | return *it; |
1476 | 19.8k | } |
1477 | | |
1478 | | ValueFlow::Value execute(const Token* expr) |
1479 | 32.7k | { |
1480 | 32.7k | ValueFlow::Value v = executeImpl(expr); |
1481 | 32.7k | if (!v.isUninitValue()) |
1482 | 11.9k | return v; |
1483 | 20.7k | if (!expr) |
1484 | 0 | return v; |
1485 | 20.7k | if (expr->exprId() > 0 && pm->hasValue(expr->exprId())) |
1486 | 956 | return pm->at(expr->exprId()); |
1487 | 19.8k | if (const ValueFlow::Value* value = getImpossibleValue(expr)) |
1488 | 5.32k | return *value; |
1489 | 14.5k | return v; |
1490 | 19.8k | } |
1491 | | |
1492 | | std::vector<ValueFlow::Value> execute(const Scope* scope) |
1493 | 0 | { |
1494 | 0 | static const std::vector<ValueFlow::Value> unknown = {ValueFlow::Value::unknown()}; |
1495 | 0 | if (!scope) |
1496 | 0 | return unknown; |
1497 | 0 | if (!scope->bodyStart) |
1498 | 0 | return unknown; |
1499 | 0 | for (const Token* tok = scope->bodyStart->next(); precedes(tok, scope->bodyEnd); tok = tok->next()) { |
1500 | 0 | const Token* top = tok->astTop(); |
1501 | 0 | if (!top) |
1502 | 0 | return unknown; |
1503 | | |
1504 | 0 | if (Token::simpleMatch(top, "return") && top->astOperand1()) |
1505 | 0 | return {execute(top->astOperand1())}; |
1506 | | |
1507 | 0 | if (Token::Match(top, "%op%")) { |
1508 | 0 | if (execute(top).isUninitValue()) |
1509 | 0 | return unknown; |
1510 | 0 | const Token* next = nextAfterAstRightmostLeaf(top); |
1511 | 0 | if (!next) |
1512 | 0 | return unknown; |
1513 | 0 | tok = next; |
1514 | 0 | } else if (Token::simpleMatch(top->previous(), "if (")) { |
1515 | 0 | const Token* condTok = top->astOperand2(); |
1516 | 0 | ValueFlow::Value v = execute(condTok); |
1517 | 0 | if (!v.isIntValue()) |
1518 | 0 | return unknown; |
1519 | 0 | const Token* thenStart = top->link()->next(); |
1520 | 0 | const Token* next = thenStart->link(); |
1521 | 0 | const Token* elseStart = nullptr; |
1522 | 0 | if (Token::simpleMatch(thenStart->link(), "} else {")) { |
1523 | 0 | elseStart = thenStart->link()->tokAt(2); |
1524 | 0 | next = elseStart->link(); |
1525 | 0 | } |
1526 | 0 | std::vector<ValueFlow::Value> result; |
1527 | 0 | if (isTrue(v)) { |
1528 | 0 | result = execute(thenStart->scope()); |
1529 | 0 | } else if (isFalse(v)) { |
1530 | 0 | if (elseStart) |
1531 | 0 | result = execute(elseStart->scope()); |
1532 | 0 | } else { |
1533 | 0 | return unknown; |
1534 | 0 | } |
1535 | 0 | if (!result.empty()) |
1536 | 0 | return result; |
1537 | 0 | tok = next; |
1538 | 0 | } else { |
1539 | 0 | return unknown; |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | return {}; |
1543 | 0 | } |
1544 | | }; |
1545 | | |
1546 | | static ValueFlow::Value execute(const Token* expr, ProgramMemory& pm, const Settings* settings) |
1547 | 9.07k | { |
1548 | 9.07k | Executor ex{&pm, settings}; |
1549 | 9.07k | return ex.execute(expr); |
1550 | 9.07k | } |
1551 | | |
1552 | | std::vector<ValueFlow::Value> execute(const Scope* scope, ProgramMemory& pm, const Settings* settings) |
1553 | 0 | { |
1554 | 0 | Executor ex{&pm, settings}; |
1555 | 0 | return ex.execute(scope); |
1556 | 0 | } |
1557 | | |
1558 | | ValueFlow::Value evaluateLibraryFunction(const std::unordered_map<nonneg int, ValueFlow::Value>& args, |
1559 | | const std::string& returnValue, |
1560 | | const Settings* settings) |
1561 | 0 | { |
1562 | 0 | thread_local static std::unordered_map<std::string, |
1563 | 0 | std::function<ValueFlow::Value(const std::unordered_map<nonneg int, ValueFlow::Value>& arg)>> |
1564 | 0 | functions = {}; |
1565 | 0 | if (functions.count(returnValue) == 0) { |
1566 | |
|
1567 | 0 | std::unordered_map<nonneg int, const Token*> lookupVarId; |
1568 | 0 | std::shared_ptr<Token> expr = createTokenFromExpression(returnValue, settings, &lookupVarId); |
1569 | |
|
1570 | 0 | functions[returnValue] = |
1571 | 0 | [lookupVarId, expr, settings](const std::unordered_map<nonneg int, ValueFlow::Value>& xargs) { |
1572 | 0 | if (!expr) |
1573 | 0 | return ValueFlow::Value::unknown(); |
1574 | 0 | ProgramMemory pm{}; |
1575 | 0 | for (const auto& p : xargs) { |
1576 | 0 | auto it = lookupVarId.find(p.first); |
1577 | 0 | if (it != lookupVarId.end()) |
1578 | 0 | pm.setValue(it->second, p.second); |
1579 | 0 | } |
1580 | 0 | return execute(expr.get(), pm, settings); |
1581 | 0 | }; |
1582 | 0 | } |
1583 | 0 | return functions.at(returnValue)(args); |
1584 | 0 | } |
1585 | | |
1586 | | void execute(const Token* expr, |
1587 | | ProgramMemory& programMemory, |
1588 | | MathLib::bigint* result, |
1589 | | bool* error, |
1590 | | const Settings* settings) |
1591 | 8.64k | { |
1592 | 8.64k | ValueFlow::Value v = execute(expr, programMemory, settings); |
1593 | 8.64k | if (!v.isIntValue() || v.isImpossible()) { |
1594 | 6.96k | if (error) |
1595 | 6.96k | *error = true; |
1596 | 6.96k | } else if (result) |
1597 | 1.68k | *result = v.intvalue; |
1598 | 8.64k | } |