Coverage Report

Created: 2023-09-25 06:15

/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
}