Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/ctu.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
20
//---------------------------------------------------------------------------
21
#include "ctu.h"
22
23
#include "astutils.h"
24
#include "errortypes.h"
25
#include "settings.h"
26
#include "symboldatabase.h"
27
#include "token.h"
28
#include "tokenize.h"
29
#include "tokenlist.h"
30
#include "utils.h"
31
32
#include <algorithm>
33
#include <cstdint>
34
#include <cstring>
35
#include <iterator>  // back_inserter
36
#include <sstream>
37
#include <utility>
38
39
#include <tinyxml2.h>
40
//---------------------------------------------------------------------------
41
42
static const char ATTR_CALL_ID[] = "call-id";
43
static const char ATTR_CALL_FUNCNAME[] = "call-funcname";
44
static const char ATTR_CALL_ARGNR[] = "call-argnr";
45
static const char ATTR_CALL_ARGEXPR[] = "call-argexpr";
46
static const char ATTR_CALL_ARGVALUETYPE[] = "call-argvaluetype";
47
static const char ATTR_CALL_ARGVALUE[] = "call-argvalue";
48
static const char ATTR_WARNING[] = "warning";
49
static const char ATTR_LOC_FILENAME[] = "file";
50
static const char ATTR_LOC_LINENR[] = "line";
51
static const char ATTR_LOC_COLUMN[] = "col";
52
static const char ATTR_INFO[] = "info";
53
static const char ATTR_MY_ID[] = "my-id";
54
static const char ATTR_MY_ARGNR[] = "my-argnr";
55
static const char ATTR_MY_ARGNAME[] = "my-argname";
56
static const char ATTR_VALUE[] = "value";
57
58
int CTU::maxCtuDepth = 2;
59
60
std::string CTU::getFunctionId(const Tokenizer *tokenizer, const Function *function)
61
0
{
62
0
    return tokenizer->list.file(function->tokenDef) + ':' + std::to_string(function->tokenDef->linenr()) + ':' + std::to_string(function->tokenDef->column());
63
0
}
64
65
CTU::FileInfo::Location::Location(const Tokenizer *tokenizer, const Token *tok)
66
    : fileName(tokenizer->list.file(tok))
67
    , lineNumber(tok->linenr())
68
    , column(tok->column())
69
0
{}
70
71
std::string CTU::FileInfo::toString() const
72
0
{
73
0
    std::ostringstream out;
74
75
    // Function calls..
76
0
    for (const CTU::FileInfo::FunctionCall &functionCall : functionCalls) {
77
0
        out << functionCall.toXmlString();
78
0
    }
79
80
    // Nested calls..
81
0
    for (const CTU::FileInfo::NestedCall &nestedCall : nestedCalls) {
82
0
        out << nestedCall.toXmlString() << "\n";
83
0
    }
84
85
0
    return out.str();
86
0
}
87
88
std::string CTU::FileInfo::CallBase::toBaseXmlString() const
89
0
{
90
0
    std::ostringstream out;
91
0
    out << " " << ATTR_CALL_ID << "=\"" << callId << "\""
92
0
        << " " << ATTR_CALL_FUNCNAME << "=\"" << ErrorLogger::toxml(callFunctionName) << "\""
93
0
        << " " << ATTR_CALL_ARGNR << "=\"" << callArgNr << "\""
94
0
        << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(location.fileName) << "\""
95
0
        << " " << ATTR_LOC_LINENR << "=\"" << location.lineNumber << "\""
96
0
        << " " << ATTR_LOC_COLUMN << "=\"" << location.column << "\"";
97
0
    return out.str();
98
0
}
99
100
std::string CTU::FileInfo::FunctionCall::toXmlString() const
101
0
{
102
0
    std::ostringstream out;
103
0
    out << "<function-call"
104
0
        << toBaseXmlString()
105
0
        << " " << ATTR_CALL_ARGEXPR << "=\"" << ErrorLogger::toxml(callArgumentExpression) << "\""
106
0
        << " " << ATTR_CALL_ARGVALUETYPE << "=\"" << static_cast<int>(callValueType) << "\""
107
0
        << " " << ATTR_CALL_ARGVALUE << "=\"" << callArgValue << "\"";
108
0
    if (warning)
109
0
        out << " " << ATTR_WARNING << "=\"true\"";
110
0
    if (callValuePath.empty())
111
0
        out << "/>";
112
0
    else {
113
0
        out << ">\n";
114
0
        for (const ErrorMessage::FileLocation &loc : callValuePath)
115
0
            out << "  <path"
116
0
                << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(loc.getfile()) << "\""
117
0
                << " " << ATTR_LOC_LINENR << "=\"" << loc.line << "\""
118
0
                << " " << ATTR_LOC_COLUMN << "=\"" << loc.column << "\""
119
0
                << " " << ATTR_INFO << "=\"" << ErrorLogger::toxml(loc.getinfo()) << "\"/>\n";
120
0
        out << "</function-call>";
121
0
    }
122
0
    return out.str();
123
0
}
124
125
std::string CTU::FileInfo::NestedCall::toXmlString() const
126
0
{
127
0
    std::ostringstream out;
128
0
    out << "<function-call"
129
0
        << toBaseXmlString()
130
0
        << " " << ATTR_MY_ID << "=\"" << myId << "\""
131
0
        << " " << ATTR_MY_ARGNR << "=\"" << myArgNr << "\""
132
0
        << "/>";
133
0
    return out.str();
134
0
}
135
136
std::string CTU::FileInfo::UnsafeUsage::toString() const
137
0
{
138
0
    std::ostringstream out;
139
0
    out << "    <unsafe-usage"
140
0
        << " " << ATTR_MY_ID << "=\"" << myId << '\"'
141
0
        << " " << ATTR_MY_ARGNR << "=\"" << myArgNr << '\"'
142
0
        << " " << ATTR_MY_ARGNAME << "=\"" << myArgumentName << '\"'
143
0
        << " " << ATTR_LOC_FILENAME << "=\"" << ErrorLogger::toxml(location.fileName) << '\"'
144
0
        << " " << ATTR_LOC_LINENR << "=\"" << location.lineNumber << '\"'
145
0
        << " " << ATTR_LOC_COLUMN << "=\"" << location.column << '\"'
146
0
        << " " << ATTR_VALUE << "=\"" << value << "\""
147
0
        << "/>\n";
148
0
    return out.str();
149
0
}
150
151
std::string CTU::toString(const std::list<CTU::FileInfo::UnsafeUsage> &unsafeUsage)
152
0
{
153
0
    std::ostringstream ret;
154
0
    for (const CTU::FileInfo::UnsafeUsage &u : unsafeUsage)
155
0
        ret << u.toString();
156
0
    return ret.str();
157
0
}
158
159
CTU::FileInfo::CallBase::CallBase(const Tokenizer *tokenizer, const Token *callToken)
160
    : callId(getFunctionId(tokenizer, callToken->function()))
161
    , callFunctionName(callToken->next()->astOperand1()->expressionString())
162
    , location(CTU::FileInfo::Location(tokenizer, callToken))
163
0
{}
164
165
CTU::FileInfo::NestedCall::NestedCall(const Tokenizer *tokenizer, const Function *myFunction, const Token *callToken)
166
    : CallBase(tokenizer, callToken)
167
    , myId(getFunctionId(tokenizer, myFunction))
168
0
{}
169
170
static std::string readAttrString(const tinyxml2::XMLElement *e, const char *attr, bool *error)
171
0
{
172
0
    const char *value = e->Attribute(attr);
173
0
    if (!value && error)
174
0
        *error = true;
175
0
    return value ? value : "";
176
0
}
177
178
static long long readAttrInt(const tinyxml2::XMLElement *e, const char *attr, bool *error)
179
0
{
180
0
    int64_t value = 0;
181
0
    const bool err = (e->QueryInt64Attribute(attr, &value) != tinyxml2::XML_SUCCESS);
182
0
    if (error)
183
0
        *error = err;
184
0
    return value;
185
0
}
186
187
bool CTU::FileInfo::CallBase::loadBaseFromXml(const tinyxml2::XMLElement *xmlElement)
188
0
{
189
0
    bool error = false;
190
0
    callId = readAttrString(xmlElement, ATTR_CALL_ID, &error);
191
0
    callFunctionName = readAttrString(xmlElement, ATTR_CALL_FUNCNAME, &error);
192
0
    callArgNr = readAttrInt(xmlElement, ATTR_CALL_ARGNR, &error);
193
0
    location.fileName = readAttrString(xmlElement, ATTR_LOC_FILENAME, &error);
194
0
    location.lineNumber = readAttrInt(xmlElement, ATTR_LOC_LINENR, &error);
195
0
    location.column = readAttrInt(xmlElement, ATTR_LOC_COLUMN, &error);
196
0
    return !error;
197
0
}
198
199
bool CTU::FileInfo::FunctionCall::loadFromXml(const tinyxml2::XMLElement *xmlElement)
200
0
{
201
0
    if (!loadBaseFromXml(xmlElement))
202
0
        return false;
203
0
    bool error=false;
204
0
    callArgumentExpression = readAttrString(xmlElement, ATTR_CALL_ARGEXPR, &error);
205
0
    callValueType = (ValueFlow::Value::ValueType)readAttrInt(xmlElement, ATTR_CALL_ARGVALUETYPE, &error);
206
0
    callArgValue = readAttrInt(xmlElement, ATTR_CALL_ARGVALUE, &error);
207
0
    const char *w = xmlElement->Attribute(ATTR_WARNING);
208
0
    warning = w && std::strcmp(w, "true") == 0;
209
0
    for (const tinyxml2::XMLElement *e2 = xmlElement->FirstChildElement(); !error && e2; e2 = e2->NextSiblingElement()) {
210
0
        if (std::strcmp(e2->Name(), "path") != 0)
211
0
            continue;
212
0
        ErrorMessage::FileLocation loc;
213
0
        loc.setfile(readAttrString(e2, ATTR_LOC_FILENAME, &error));
214
0
        loc.line = readAttrInt(e2, ATTR_LOC_LINENR, &error);
215
0
        loc.column = readAttrInt(e2, ATTR_LOC_COLUMN, &error);
216
0
        loc.setinfo(readAttrString(e2, ATTR_INFO, &error));
217
0
    }
218
0
    return !error;
219
0
}
220
221
bool CTU::FileInfo::NestedCall::loadFromXml(const tinyxml2::XMLElement *xmlElement)
222
0
{
223
0
    if (!loadBaseFromXml(xmlElement))
224
0
        return false;
225
0
    bool error = false;
226
0
    myId = readAttrString(xmlElement, ATTR_MY_ID, &error);
227
0
    myArgNr = readAttrInt(xmlElement, ATTR_MY_ARGNR, &error);
228
0
    return !error;
229
0
}
230
231
void CTU::FileInfo::loadFromXml(const tinyxml2::XMLElement *xmlElement)
232
0
{
233
0
    for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
234
0
        if (std::strcmp(e->Name(), "function-call") == 0) {
235
0
            FunctionCall functionCall;
236
0
            if (functionCall.loadFromXml(e))
237
0
                functionCalls.push_back(std::move(functionCall));
238
0
        } else if (std::strcmp(e->Name(), "nested-call") == 0) {
239
0
            NestedCall nestedCall;
240
0
            if (nestedCall.loadFromXml(e))
241
0
                nestedCalls.push_back(std::move(nestedCall));
242
0
        }
243
0
    }
244
0
}
245
246
std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> CTU::FileInfo::getCallsMap() const
247
0
{
248
0
    std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> ret;
249
0
    for (const CTU::FileInfo::NestedCall &nc : nestedCalls)
250
0
        ret[nc.callId].push_back(&nc);
251
0
    for (const CTU::FileInfo::FunctionCall &fc : functionCalls)
252
0
        ret[fc.callId].push_back(&fc);
253
0
    return ret;
254
0
}
255
256
std::list<CTU::FileInfo::UnsafeUsage> CTU::loadUnsafeUsageListFromXml(const tinyxml2::XMLElement *xmlElement)
257
0
{
258
0
    std::list<CTU::FileInfo::UnsafeUsage> ret;
259
0
    for (const tinyxml2::XMLElement *e = xmlElement->FirstChildElement(); e; e = e->NextSiblingElement()) {
260
0
        if (std::strcmp(e->Name(), "unsafe-usage") != 0)
261
0
            continue;
262
0
        bool error = false;
263
0
        FileInfo::UnsafeUsage unsafeUsage;
264
0
        unsafeUsage.myId = readAttrString(e, ATTR_MY_ID, &error);
265
0
        unsafeUsage.myArgNr = readAttrInt(e, ATTR_MY_ARGNR, &error);
266
0
        unsafeUsage.myArgumentName = readAttrString(e, ATTR_MY_ARGNAME, &error);
267
0
        unsafeUsage.location.fileName = readAttrString(e, ATTR_LOC_FILENAME, &error);
268
0
        unsafeUsage.location.lineNumber = readAttrInt(e, ATTR_LOC_LINENR, &error);
269
0
        unsafeUsage.location.column = readAttrInt(e, ATTR_LOC_COLUMN, &error);
270
0
        unsafeUsage.value = readAttrInt(e, ATTR_VALUE, &error);
271
272
0
        if (!error)
273
0
            ret.push_back(std::move(unsafeUsage));
274
0
    }
275
0
    return ret;
276
0
}
277
278
static int isCallFunction(const Scope *scope, int argnr, const Token **tok)
279
0
{
280
0
    const Variable * const argvar = scope->function->getArgumentVar(argnr);
281
0
    if (!argvar->isPointer())
282
0
        return -1;
283
0
    for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
284
0
        if (tok2->variable() != argvar)
285
0
            continue;
286
0
        if (!Token::Match(tok2->previous(), "[(,] %var% [,)]"))
287
0
            break;
288
0
        int argnr2 = 1;
289
0
        const Token *prev = tok2;
290
0
        while (prev && prev->str() != "(") {
291
0
            if (Token::Match(prev,"]|)"))
292
0
                prev = prev->link();
293
0
            else if (prev->str() == ",")
294
0
                ++argnr2;
295
0
            prev = prev->previous();
296
0
        }
297
0
        if (!prev || !Token::Match(prev->previous(), "%name% ("))
298
0
            break;
299
0
        if (!prev->astOperand1() || !prev->astOperand1()->function())
300
0
            break;
301
0
        *tok = prev->previous();
302
0
        return argnr2;
303
0
    }
304
0
    return -1;
305
0
}
306
307
308
CTU::FileInfo *CTU::getFileInfo(const Tokenizer *tokenizer)
309
1.36k
{
310
1.36k
    const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
311
312
1.36k
    FileInfo *fileInfo = new FileInfo;
313
314
    // Parse all functions in TU
315
4.94k
    for (const Scope &scope : symbolDatabase->scopeList) {
316
4.94k
        if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
317
3.20k
            continue;
318
1.73k
        const Function *const scopeFunction = scope.function;
319
320
        // source function calls
321
37.6k
        for (const Token *tok = scope.bodyStart; tok != scope.bodyEnd; tok = tok->next()) {
322
35.9k
            if (tok->str() != "(" || !tok->astOperand1() || !tok->astOperand2())
323
34.5k
                continue;
324
1.38k
            const Function* tokFunction = tok->astOperand1()->function();
325
1.38k
            if (!tokFunction)
326
1.38k
                continue;
327
0
            const std::vector<const Token *> args(getArguments(tok->previous()));
328
0
            for (int argnr = 0; argnr < args.size(); ++argnr) {
329
0
                const Token *argtok = args[argnr];
330
0
                if (!argtok)
331
0
                    continue;
332
0
                for (const ValueFlow::Value &value : argtok->values()) {
333
0
                    if ((!value.isIntValue() || value.intvalue != 0 || value.isInconclusive()) && !value.isBufferSizeValue())
334
0
                        continue;
335
                    // Skip impossible values since they cannot be represented
336
0
                    if (value.isImpossible())
337
0
                        continue;
338
0
                    FileInfo::FunctionCall functionCall;
339
0
                    functionCall.callValueType = value.valueType;
340
0
                    functionCall.callId = getFunctionId(tokenizer, tokFunction);
341
0
                    functionCall.callFunctionName = tok->astOperand1()->expressionString();
342
0
                    functionCall.location = FileInfo::Location(tokenizer,tok);
343
0
                    functionCall.callArgNr = argnr + 1;
344
0
                    functionCall.callArgumentExpression = argtok->expressionString();
345
0
                    functionCall.callArgValue = value.intvalue;
346
0
                    functionCall.warning = !value.errorSeverity();
347
0
                    for (const ErrorPathItem &i : value.errorPath) {
348
0
                        ErrorMessage::FileLocation loc;
349
0
                        loc.setfile(tokenizer->list.file(i.first));
350
0
                        loc.line = i.first->linenr();
351
0
                        loc.column = i.first->column();
352
0
                        loc.setinfo(i.second);
353
0
                        functionCall.callValuePath.push_back(std::move(loc));
354
0
                    }
355
0
                    fileInfo->functionCalls.push_back(std::move(functionCall));
356
0
                }
357
                // array
358
0
                if (argtok->variable() && argtok->variable()->isArray() && argtok->variable()->dimensions().size() == 1 && argtok->variable()->dimensionKnown(0)) {
359
0
                    FileInfo::FunctionCall functionCall;
360
0
                    functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
361
0
                    functionCall.callId = getFunctionId(tokenizer, tokFunction);
362
0
                    functionCall.callFunctionName = tok->astOperand1()->expressionString();
363
0
                    functionCall.location = FileInfo::Location(tokenizer, tok);
364
0
                    functionCall.callArgNr = argnr + 1;
365
0
                    functionCall.callArgumentExpression = argtok->expressionString();
366
0
                    const auto typeSize = argtok->valueType()->typeSize(tokenizer->getSettings()->platform);
367
0
                    functionCall.callArgValue = typeSize > 0 ? argtok->variable()->dimension(0) * typeSize : -1;
368
0
                    functionCall.warning = false;
369
0
                    fileInfo->functionCalls.push_back(std::move(functionCall));
370
0
                }
371
                // &var => buffer
372
0
                if (argtok->isUnaryOp("&") && argtok->astOperand1()->variable() && argtok->astOperand1()->valueType() && !argtok->astOperand1()->variable()->isArray()) {
373
0
                    FileInfo::FunctionCall functionCall;
374
0
                    functionCall.callValueType = ValueFlow::Value::ValueType::BUFFER_SIZE;
375
0
                    functionCall.callId = getFunctionId(tokenizer, tokFunction);
376
0
                    functionCall.callFunctionName = tok->astOperand1()->expressionString();
377
0
                    functionCall.location = FileInfo::Location(tokenizer, tok);
378
0
                    functionCall.callArgNr = argnr + 1;
379
0
                    functionCall.callArgumentExpression = argtok->expressionString();
380
0
                    functionCall.callArgValue = argtok->astOperand1()->valueType()->typeSize(tokenizer->getSettings()->platform);
381
0
                    functionCall.warning = false;
382
0
                    fileInfo->functionCalls.push_back(std::move(functionCall));
383
0
                }
384
                // pointer/reference to uninitialized data
385
0
                auto isAddressOfArg = [](const Token* argtok) -> const Token* {
386
0
                    if (!argtok->isUnaryOp("&"))
387
0
                        return nullptr;
388
0
                    argtok = argtok->astOperand1();
389
0
                    if (!argtok || !argtok->valueType() || argtok->valueType()->pointer != 0)
390
0
                        return nullptr;
391
0
                    return argtok;
392
0
                };
393
0
                auto isReferenceArg = [&](const Token* argtok) -> const Token* {
394
0
                    const Variable* argvar = tokFunction->getArgumentVar(argnr);
395
0
                    if (!argvar || !argvar->valueType() || argvar->valueType()->reference == Reference::None)
396
0
                        return nullptr;
397
0
                    return argtok;
398
0
                };
399
0
                const Token* addr = isAddressOfArg(argtok);
400
0
                argtok = addr ? addr : isReferenceArg(argtok);
401
0
                if (!argtok || argtok->values().size() != 1U)
402
0
                    continue;
403
0
                if (argtok->variable() && argtok->variable()->isClass())
404
0
                    continue;
405
406
0
                const ValueFlow::Value &v = argtok->values().front();
407
0
                if (v.valueType == ValueFlow::Value::ValueType::UNINIT && !v.isInconclusive()) {
408
0
                    FileInfo::FunctionCall functionCall;
409
0
                    functionCall.callValueType = ValueFlow::Value::ValueType::UNINIT;
410
0
                    functionCall.callId = getFunctionId(tokenizer, tokFunction);
411
0
                    functionCall.callFunctionName = tok->astOperand1()->expressionString();
412
0
                    functionCall.location = FileInfo::Location(tokenizer, tok);
413
0
                    functionCall.callArgNr = argnr + 1;
414
0
                    functionCall.callArgValue = 0;
415
0
                    functionCall.callArgumentExpression = argtok->expressionString();
416
0
                    functionCall.warning = false;
417
0
                    fileInfo->functionCalls.push_back(std::move(functionCall));
418
0
                    continue;
419
0
                }
420
0
            }
421
0
        }
422
423
        // Nested function calls
424
1.73k
        for (int argnr = 0; argnr < scopeFunction->argCount(); ++argnr) {
425
0
            const Token *tok;
426
0
            const int argnr2 = isCallFunction(&scope, argnr, &tok);
427
0
            if (argnr2 > 0) {
428
0
                FileInfo::NestedCall nestedCall(tokenizer, scopeFunction, tok);
429
0
                nestedCall.myArgNr = argnr + 1;
430
0
                nestedCall.callArgNr = argnr2;
431
0
                fileInfo->nestedCalls.push_back(std::move(nestedCall));
432
0
            }
433
0
        }
434
1.73k
    }
435
436
1.36k
    return fileInfo;
437
1.36k
}
438
439
static std::list<std::pair<const Token *, MathLib::bigint>> getUnsafeFunction(const Tokenizer *tokenizer, const Settings *settings, const Scope *scope, int argnr, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok, MathLib::bigint *value))
440
0
{
441
0
    std::list<std::pair<const Token *, MathLib::bigint>> ret;
442
0
    const Variable * const argvar = scope->function->getArgumentVar(argnr);
443
0
    if (!argvar->isArrayOrPointer() && !argvar->isReference())
444
0
        return ret;
445
0
    for (const Token *tok2 = scope->bodyStart; tok2 != scope->bodyEnd; tok2 = tok2->next()) {
446
0
        if (Token::Match(tok2, ")|else {")) {
447
0
            tok2 = tok2->linkAt(1);
448
0
            if (Token::findmatch(tok2->link(), "return|throw", tok2))
449
0
                return ret;
450
0
            int indirect = 0;
451
0
            if (argvar->valueType())
452
0
                indirect = argvar->valueType()->pointer;
453
0
            if (isVariableChanged(tok2->link(), tok2, indirect, argvar->declarationId(), false, settings, tokenizer->isCPP()))
454
0
                return ret;
455
0
        }
456
0
        if (Token::Match(tok2, "%oror%|&&|?")) {
457
0
            tok2 = tok2->findExpressionStartEndTokens().second;
458
0
            continue;
459
0
        }
460
0
        if (tok2->variable() != argvar)
461
0
            continue;
462
0
        MathLib::bigint value = 0;
463
0
        if (!isUnsafeUsage(check, tok2, &value))
464
0
            return ret; // TODO: Is this a read? then continue..
465
0
        ret.emplace_back(tok2, value);
466
0
        return ret;
467
0
    }
468
0
    return ret;
469
0
}
470
471
std::list<CTU::FileInfo::UnsafeUsage> CTU::getUnsafeUsage(const Tokenizer *tokenizer, const Settings *settings, const Check *check, bool (*isUnsafeUsage)(const Check *check, const Token *argtok, MathLib::bigint *value))
472
5.44k
{
473
5.44k
    std::list<CTU::FileInfo::UnsafeUsage> unsafeUsage;
474
475
    // Parse all functions in TU
476
5.44k
    const SymbolDatabase * const symbolDatabase = tokenizer->getSymbolDatabase();
477
478
19.7k
    for (const Scope &scope : symbolDatabase->scopeList) {
479
19.7k
        if (!scope.isExecutable() || scope.type != Scope::eFunction || !scope.function)
480
12.8k
            continue;
481
6.95k
        const Function *const function = scope.function;
482
483
        // "Unsafe" functions unconditionally reads data before it is written..
484
6.95k
        for (int argnr = 0; argnr < function->argCount(); ++argnr) {
485
0
            for (const std::pair<const Token *, MathLib::bigint> &v : getUnsafeFunction(tokenizer, settings, &scope, argnr, check, isUnsafeUsage)) {
486
0
                const Token *tok = v.first;
487
0
                const MathLib::bigint val = v.second;
488
0
                unsafeUsage.emplace_back(CTU::getFunctionId(tokenizer, function), argnr+1, tok->str(), CTU::FileInfo::Location(tokenizer,tok), val);
489
0
            }
490
0
        }
491
6.95k
    }
492
493
5.44k
    return unsafeUsage;
494
5.44k
}
495
496
static bool findPath(const std::string &callId,
497
                     nonneg int callArgNr,
498
                     MathLib::bigint unsafeValue,
499
                     CTU::FileInfo::InvalidValueType invalidValue,
500
                     const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
501
                     const CTU::FileInfo::CallBase *path[10],
502
                     int index,
503
                     bool warning)
504
0
{
505
0
    if (index >= CTU::maxCtuDepth || index >= 10)
506
0
        return false;
507
508
0
    const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>>::const_iterator it = callsMap.find(callId);
509
0
    if (it == callsMap.end())
510
0
        return false;
511
512
0
    for (const CTU::FileInfo::CallBase *c : it->second) {
513
0
        if (c->callArgNr != callArgNr)
514
0
            continue;
515
516
0
        const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(c);
517
0
        if (functionCall) {
518
0
            if (!warning && functionCall->warning)
519
0
                continue;
520
0
            switch (invalidValue) {
521
0
            case CTU::FileInfo::InvalidValueType::null:
522
0
                if (functionCall->callValueType != ValueFlow::Value::ValueType::INT || functionCall->callArgValue != 0)
523
0
                    continue;
524
0
                break;
525
0
            case CTU::FileInfo::InvalidValueType::uninit:
526
0
                if (functionCall->callValueType != ValueFlow::Value::ValueType::UNINIT)
527
0
                    continue;
528
0
                break;
529
0
            case CTU::FileInfo::InvalidValueType::bufferOverflow:
530
0
                if (functionCall->callValueType != ValueFlow::Value::ValueType::BUFFER_SIZE)
531
0
                    continue;
532
0
                if (unsafeValue < 0 || (unsafeValue >= functionCall->callArgValue && functionCall->callArgValue >= 0))
533
0
                    break;
534
0
                continue;
535
0
            }
536
0
            path[index] = functionCall;
537
0
            return true;
538
0
        }
539
540
0
        const CTU::FileInfo::NestedCall *nestedCall = dynamic_cast<const CTU::FileInfo::NestedCall *>(c);
541
0
        if (!nestedCall)
542
0
            continue;
543
544
0
        if (findPath(nestedCall->myId, nestedCall->myArgNr, unsafeValue, invalidValue, callsMap, path, index + 1, warning)) {
545
0
            path[index] = nestedCall;
546
0
            return true;
547
0
        }
548
0
    }
549
550
0
    return false;
551
0
}
552
553
std::list<ErrorMessage::FileLocation> CTU::FileInfo::getErrorPath(InvalidValueType invalidValue,
554
                                                                  const CTU::FileInfo::UnsafeUsage &unsafeUsage,
555
                                                                  const std::map<std::string, std::list<const CTU::FileInfo::CallBase *>> &callsMap,
556
                                                                  const char info[],
557
                                                                  const FunctionCall ** const functionCallPtr,
558
                                                                  bool warning)
559
0
{
560
0
    std::list<ErrorMessage::FileLocation> locationList;
561
562
0
    const CTU::FileInfo::CallBase *path[10] = {nullptr};
563
564
0
    if (!findPath(unsafeUsage.myId, unsafeUsage.myArgNr, unsafeUsage.value, invalidValue, callsMap, path, 0, warning))
565
0
        return locationList;
566
567
0
    const std::string value1 = (invalidValue == InvalidValueType::null) ? "null" : "uninitialized";
568
569
0
    for (int index = 9; index >= 0; index--) {
570
0
        if (!path[index])
571
0
            continue;
572
573
0
        const CTU::FileInfo::FunctionCall *functionCall = dynamic_cast<const CTU::FileInfo::FunctionCall *>(path[index]);
574
575
0
        if (functionCall) {
576
0
            if (functionCallPtr)
577
0
                *functionCallPtr = functionCall;
578
0
            std::copy(functionCall->callValuePath.cbegin(), functionCall->callValuePath.cend(), std::back_inserter(locationList));
579
0
        }
580
581
0
        ErrorMessage::FileLocation fileLoc(path[index]->location.fileName, path[index]->location.lineNumber, path[index]->location.column);
582
0
        fileLoc.setinfo("Calling function " + path[index]->callFunctionName + ", " + std::to_string(path[index]->callArgNr) + getOrdinalText(path[index]->callArgNr) + " argument is " + value1);
583
0
        locationList.push_back(std::move(fileLoc));
584
0
    }
585
586
0
    ErrorMessage::FileLocation fileLoc2(unsafeUsage.location.fileName, unsafeUsage.location.lineNumber, unsafeUsage.location.column);
587
0
    fileLoc2.setinfo(replaceStr(info, "ARG", unsafeUsage.myArgumentName));
588
0
    locationList.push_back(std::move(fileLoc2));
589
590
0
    return locationList;
591
0
}