Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/checksizeof.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 "checksizeof.h"
22
23
#include "errortypes.h"
24
#include "library.h"
25
#include "settings.h"
26
#include "symboldatabase.h"
27
#include "token.h"
28
#include "tokenize.h"
29
30
#include <algorithm>
31
#include <iterator>
32
#include <map>
33
#include <vector>
34
35
//---------------------------------------------------------------------------
36
37
// Register this check class (by creating a static instance of it)
38
namespace {
39
    CheckSizeof instance;
40
}
41
42
// CWE IDs used:
43
static const struct CWE CWE398(398U);   // Indicator of Poor Code Quality
44
static const struct CWE CWE467(467U);   // Use of sizeof() on a Pointer Type
45
static const struct CWE CWE682(682U);   // Incorrect Calculation
46
//---------------------------------------------------------------------------
47
//---------------------------------------------------------------------------
48
void CheckSizeof::checkSizeofForNumericParameter()
49
1.36k
{
50
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
51
0
        return;
52
53
1.36k
    logChecker("CheckSizeof::checkSizeofForNumericParameter"); // warning
54
55
1.36k
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
56
1.73k
    for (const Scope * scope : symbolDatabase->functionScopes) {
57
35.9k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
58
34.1k
            if (Token::Match(tok, "sizeof ( %num% )") ||
59
34.1k
                Token::Match(tok, "sizeof %num%")) {
60
0
                sizeofForNumericParameterError(tok);
61
0
            }
62
34.1k
        }
63
1.73k
    }
64
1.36k
}
65
66
void CheckSizeof::sizeofForNumericParameterError(const Token *tok)
67
0
{
68
0
    reportError(tok, Severity::warning,
69
0
                "sizeofwithnumericparameter", "Suspicious usage of 'sizeof' with a numeric constant as parameter.\n"
70
0
                "It is unusual to use a constant value with sizeof. For example, 'sizeof(10)'"
71
0
                " returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 10. 'sizeof('A')'"
72
0
                " and 'sizeof(char)' can return different results.", CWE682, Certainty::normal);
73
0
}
74
75
76
//---------------------------------------------------------------------------
77
//---------------------------------------------------------------------------
78
void CheckSizeof::checkSizeofForArrayParameter()
79
1.36k
{
80
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
81
0
        return;
82
83
1.36k
    logChecker("CheckSizeof::checkSizeofForArrayParameter"); // warning
84
85
1.36k
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
86
1.73k
    for (const Scope * scope : symbolDatabase->functionScopes) {
87
35.9k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
88
34.1k
            if (Token::Match(tok, "sizeof ( %var% )") ||
89
34.1k
                Token::Match(tok, "sizeof %var% !![")) {
90
0
                const Token* varTok = tok->next();
91
0
                if (varTok->str() == "(") {
92
0
                    varTok = varTok->next();
93
0
                }
94
95
0
                const Variable *var = varTok->variable();
96
0
                if (var && var->isArray() && var->isArgument() && !var->isReference())
97
0
                    sizeofForArrayParameterError(tok);
98
0
            }
99
34.1k
        }
100
1.73k
    }
101
1.36k
}
102
103
void CheckSizeof::sizeofForArrayParameterError(const Token *tok)
104
0
{
105
0
    reportError(tok, Severity::warning,
106
0
                "sizeofwithsilentarraypointer", "Using 'sizeof' on array given as function argument "
107
0
                "returns size of a pointer.\n"
108
0
                "Using 'sizeof' for array given as function argument returns the size of a pointer. "
109
0
                "It does not return the size of the whole array in bytes as might be "
110
0
                "expected. For example, this code:\n"
111
0
                "     int f(char a[100]) {\n"
112
0
                "         return sizeof(a);\n"
113
0
                "     }\n"
114
0
                "returns 4 (in 32-bit systems) or 8 (in 64-bit systems) instead of 100 (the "
115
0
                "size of the array in bytes).", CWE467, Certainty::normal
116
0
                );
117
0
}
118
119
void CheckSizeof::checkSizeofForPointerSize()
120
1.36k
{
121
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
122
0
        return;
123
124
1.36k
    logChecker("CheckSizeof::checkSizeofForPointerSize"); // warning
125
126
1.36k
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
127
1.73k
    for (const Scope * scope : symbolDatabase->functionScopes) {
128
37.6k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
129
35.9k
            const Token* tokSize;
130
35.9k
            const Token* tokFunc;
131
35.9k
            const Token *variable = nullptr;
132
35.9k
            const Token *variable2 = nullptr;
133
134
            // Find any function that may use sizeof on a pointer
135
            // Once leaving those tests, it is mandatory to have:
136
            // - variable matching the used pointer
137
            // - tokVar pointing on the argument where sizeof may be used
138
35.9k
            if (Token::Match(tok->tokAt(2), "%name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2))) {
139
0
                if (Token::Match(tok, "%var% ="))
140
0
                    variable = tok;
141
0
                else if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-2), "%var% ="))
142
0
                    variable = tok->linkAt(1)->tokAt(-2);
143
0
                else if (tok->link() && Token::Match(tok, "> ( %name% (") && mSettings->library.getAllocFuncInfo(tok->tokAt(2)) && Token::Match(tok->link()->tokAt(-3), "%var% ="))
144
0
                    variable = tok->link()->tokAt(-3);
145
0
                tokSize = tok->tokAt(4);
146
0
                tokFunc = tok->tokAt(2);
147
35.9k
            } else if (Token::simpleMatch(tok, "memset (") && tok->strAt(-1) != ".") {
148
0
                variable = tok->tokAt(2);
149
0
                tokSize = variable->nextArgument();
150
0
                if (tokSize)
151
0
                    tokSize = tokSize->nextArgument();
152
0
                tokFunc = tok;
153
35.9k
            } else if (Token::Match(tok, "memcpy|memcmp|memmove|strncpy|strncmp|strncat (") && tok->strAt(-1) != ".") {
154
0
                variable = tok->tokAt(2);
155
0
                variable2 = variable->nextArgument();
156
0
                if (!variable2)
157
0
                    continue;
158
0
                tokSize = variable2->nextArgument();
159
0
                tokFunc = tok;
160
35.9k
            } else {
161
35.9k
                continue;
162
35.9k
            }
163
164
0
            if (tokSize && tokFunc->str() == "calloc")
165
0
                tokSize = tokSize->nextArgument();
166
167
0
            if (tokSize) {
168
0
                const Token * const paramsListEndTok = tokFunc->linkAt(1);
169
0
                for (const Token* tok2 = tokSize; tok2 != paramsListEndTok; tok2 = tok2->next()) {
170
0
                    if (Token::simpleMatch(tok2, "/ sizeof")) {
171
                        // Allow division with sizeof(char)
172
0
                        if (Token::simpleMatch(tok2->next(), "sizeof (")) {
173
0
                            const Token *sztok = tok2->tokAt(2)->astOperand2();
174
0
                            const ValueType *vt = ((sztok != nullptr) ? sztok->valueType() : nullptr);
175
0
                            if (vt && vt->type == ValueType::CHAR && vt->pointer == 0)
176
0
                                continue;
177
0
                        }
178
0
                        auto hasMultiplication = [](const Token* parTok) -> bool {
179
0
                            while (parTok) { // Allow division if followed by multiplication
180
0
                                if (parTok->isArithmeticalOp() && parTok->str() == "*") {
181
0
                                    const Token* szToks[] = { parTok->astOperand1(), parTok->astOperand2() };
182
0
                                    if (std::any_of(std::begin(szToks), std::end(szToks), [](const Token* szTok) {
183
0
                                        return Token::simpleMatch(szTok, "(") && Token::simpleMatch(szTok->previous(), "sizeof");
184
0
                                    }))
185
0
                                        return true;
186
0
                                }
187
0
                                parTok = parTok->astParent();
188
0
                            }
189
0
                            return false;
190
0
                        };
191
0
                        if (hasMultiplication(tok2->astParent()))
192
0
                            continue;
193
194
0
                        divideBySizeofError(tok2, tokFunc->str());
195
0
                    }
196
0
                }
197
0
            }
198
199
0
            if (!variable || !tokSize)
200
0
                continue;
201
202
0
            while (Token::Match(variable, "%var% ::|."))
203
0
                variable = variable->tokAt(2);
204
205
0
            while (Token::Match(variable2, "%var% ::|."))
206
0
                variable2 = variable2->tokAt(2);
207
208
0
            if (!variable)
209
0
                continue;
210
211
            // Ensure the variables are in the symbol database
212
            // Also ensure the variables are pointers
213
            // Only keep variables which are pointers
214
0
            const Variable *var = variable->variable();
215
0
            if (!var || !var->isPointer() || var->isArray()) {
216
0
                variable = nullptr;
217
0
            }
218
219
0
            if (variable2) {
220
0
                var = variable2->variable();
221
0
                if (!var || !var->isPointer() || var->isArray()) {
222
0
                    variable2 = nullptr;
223
0
                }
224
0
            }
225
226
            // If there are no pointer variable at this point, there is
227
            // no need to continue
228
0
            if (variable == nullptr && variable2 == nullptr) {
229
0
                continue;
230
0
            }
231
232
            // Jump to the next sizeof token in the function and in the parameter
233
            // This is to allow generic operations with sizeof
234
0
            for (; tokSize && tokSize->str() != ")" && tokSize->str() != "," && tokSize->str() != "sizeof"; tokSize = tokSize->next()) {}
235
236
0
            if (tokSize->str() != "sizeof")
237
0
                continue;
238
239
            // Now check for the sizeof usage: Does the level of pointer indirection match?
240
0
            if (tokSize->linkAt(1)->strAt(-1) == "*") {
241
0
                if (variable && variable->valueType() && variable->valueType()->pointer == 1 && variable->valueType()->type != ValueType::VOID)
242
0
                    sizeofForPointerError(variable, variable->str());
243
0
                else if (variable2 && variable2->valueType() && variable2->valueType()->pointer == 1 && variable2->valueType()->type != ValueType::VOID)
244
0
                    sizeofForPointerError(variable2, variable2->str());
245
0
            }
246
247
0
            if (Token::simpleMatch(tokSize, "sizeof ( &"))
248
0
                tokSize = tokSize->tokAt(3);
249
0
            else if (Token::Match(tokSize, "sizeof (|&"))
250
0
                tokSize = tokSize->tokAt(2);
251
0
            else
252
0
                tokSize = tokSize->next();
253
254
0
            while (Token::Match(tokSize, "%var% ::|."))
255
0
                tokSize = tokSize->tokAt(2);
256
257
0
            if (Token::Match(tokSize, "%var% [|("))
258
0
                continue;
259
260
            // Now check for the sizeof usage again. Once here, everything using sizeof(varid) or sizeof(&varid)
261
            // looks suspicious
262
0
            if (variable && tokSize->varId() == variable->varId())
263
0
                sizeofForPointerError(variable, variable->str());
264
0
            if (variable2 && tokSize->varId() == variable2->varId())
265
0
                sizeofForPointerError(variable2, variable2->str());
266
0
        }
267
1.73k
    }
268
1.36k
}
269
270
void CheckSizeof::sizeofForPointerError(const Token *tok, const std::string &varname)
271
0
{
272
0
    reportError(tok, Severity::warning, "pointerSize",
273
0
                "Size of pointer '" + varname + "' used instead of size of its data.\n"
274
0
                "Size of pointer '" + varname + "' used instead of size of its data. "
275
0
                "This is likely to lead to a buffer overflow. You probably intend to "
276
0
                "write 'sizeof(*" + varname + ")'.", CWE467, Certainty::normal);
277
0
}
278
279
void CheckSizeof::divideBySizeofError(const Token *tok, const std::string &memfunc)
280
0
{
281
0
    reportError(tok, Severity::warning, "sizeofDivisionMemfunc",
282
0
                "Division by result of sizeof(). " + memfunc + "() expects a size in bytes, did you intend to multiply instead?", CWE682, Certainty::normal);
283
0
}
284
285
//-----------------------------------------------------------------------------
286
//-----------------------------------------------------------------------------
287
void CheckSizeof::sizeofsizeof()
288
1.36k
{
289
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
290
0
        return;
291
292
1.36k
    logChecker("CheckSizeof::sizeofsizeof"); // warning
293
294
93.5k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
295
92.2k
        if (Token::Match(tok, "sizeof (| sizeof")) {
296
0
            sizeofsizeofError(tok);
297
0
            tok = tok->next();
298
0
        }
299
92.2k
    }
300
1.36k
}
301
302
void CheckSizeof::sizeofsizeofError(const Token *tok)
303
0
{
304
0
    reportError(tok, Severity::warning,
305
0
                "sizeofsizeof", "Calling 'sizeof' on 'sizeof'.\n"
306
0
                "Calling sizeof for 'sizeof looks like a suspicious code and "
307
0
                "most likely there should be just one 'sizeof'. The current "
308
0
                "code is equivalent to 'sizeof(size_t)'", CWE682, Certainty::normal);
309
0
}
310
311
//-----------------------------------------------------------------------------
312
313
void CheckSizeof::sizeofCalculation()
314
1.36k
{
315
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
316
0
        return;
317
318
1.36k
    logChecker("CheckSizeof::sizeofCalculation"); // warning
319
320
1.36k
    const bool printInconclusive = mSettings->certainty.isEnabled(Certainty::inconclusive);
321
322
93.5k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
323
92.2k
        if (!Token::simpleMatch(tok, "sizeof ("))
324
92.2k
            continue;
325
326
        // ignore if the `sizeof` result is cast to void inside a macro, i.e. the calculation is
327
        // expected to be parsed but skipped, such as in a disabled custom ASSERT() macro
328
0
        if (tok->isExpandedMacro() && tok->previous()) {
329
0
            const Token *cast_end = (tok->previous()->str() == "(") ? tok->previous() : tok;
330
0
            if (Token::simpleMatch(cast_end->tokAt(-3), "( void )") ||
331
0
                Token::simpleMatch(cast_end->tokAt(-4), "static_cast < void >")) {
332
0
                continue;
333
0
            }
334
0
        }
335
336
0
        const Token *argument = tok->next()->astOperand2();
337
0
        if (!argument || !argument->isCalculation())
338
0
            continue;
339
340
0
        bool inconclusive = false;
341
0
        if (argument->isExpandedMacro())
342
0
            inconclusive = true;
343
0
        else if (tok->next()->isExpandedMacro())
344
0
            inconclusive = true;
345
346
0
        if (!inconclusive || printInconclusive)
347
0
            sizeofCalculationError(argument, inconclusive);
348
0
    }
349
1.36k
}
350
351
void CheckSizeof::sizeofCalculationError(const Token *tok, bool inconclusive)
352
0
{
353
0
    reportError(tok, Severity::warning,
354
0
                "sizeofCalculation", "Found calculation inside sizeof().", CWE682, inconclusive ? Certainty::inconclusive : Certainty::normal);
355
0
}
356
357
//-----------------------------------------------------------------------------
358
359
void CheckSizeof::sizeofFunction()
360
1.36k
{
361
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning))
362
0
        return;
363
364
1.36k
    logChecker("CheckSizeof::sizeofFunction"); // warning
365
366
93.5k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
367
92.2k
        if (Token::simpleMatch(tok, "sizeof (")) {
368
369
            // ignore if the `sizeof` result is cast to void inside a macro, i.e. the calculation is
370
            // expected to be parsed but skipped, such as in a disabled custom ASSERT() macro
371
0
            if (tok->isExpandedMacro() && tok->previous()) {
372
0
                const Token *cast_end = (tok->previous()->str() == "(") ? tok->previous() : tok;
373
0
                if (Token::simpleMatch(cast_end->tokAt(-3), "( void )") ||
374
0
                    Token::simpleMatch(cast_end->tokAt(-4), "static_cast < void >")) {
375
0
                    continue;
376
0
                }
377
0
            }
378
379
0
            if (const Token *argument = tok->next()->astOperand2()) {
380
0
                const Token *checkToken = argument->previous();
381
0
                if (checkToken->tokType() == Token::eName)
382
0
                    break;
383
0
                const Function * fun = checkToken->function();
384
                // Don't report error if the function is overloaded
385
0
                if (fun && fun->nestedIn->functionMap.count(checkToken->str()) == 1) {
386
0
                    sizeofFunctionError(tok);
387
0
                }
388
0
            }
389
0
        }
390
92.2k
    }
391
1.36k
}
392
393
void CheckSizeof::sizeofFunctionError(const Token *tok)
394
0
{
395
0
    reportError(tok, Severity::warning,
396
0
                "sizeofFunctionCall", "Found function call inside sizeof().", CWE682, Certainty::normal);
397
0
}
398
399
//-----------------------------------------------------------------------------
400
// Check for code like sizeof()*sizeof() or sizeof(ptr)/value
401
//-----------------------------------------------------------------------------
402
void CheckSizeof::suspiciousSizeofCalculation()
403
1.36k
{
404
1.36k
    if (!mSettings->severity.isEnabled(Severity::warning) || !mSettings->certainty.isEnabled(Certainty::inconclusive))
405
0
        return;
406
407
1.36k
    logChecker("CheckSizeof::suspiciousSizeofCalculation"); // warning,inconclusive
408
409
93.5k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
410
92.2k
        if (Token::simpleMatch(tok, "sizeof (")) {
411
0
            const Token* lPar = tok->astParent();
412
0
            if (lPar && lPar->str() == "(") {
413
0
                const Token* const rPar = lPar->link();
414
0
                const Token* varTok = lPar->astOperand2();
415
0
                int derefCount = 0;
416
0
                while (Token::Match(varTok, "[|*")) {
417
0
                    ++derefCount;
418
0
                    varTok = varTok->astOperand1();
419
0
                }
420
0
                if (lPar->astParent() && lPar->astParent()->str() == "/") {
421
0
                    const Variable* var = varTok ? varTok->variable() : nullptr;
422
0
                    if (var && var->isPointer() && !var->isArray() && !(var->valueType() && var->valueType()->pointer <= derefCount))
423
0
                        divideSizeofError(tok);
424
0
                }
425
0
                else if (Token::simpleMatch(rPar, ") * sizeof") && rPar->next()->astOperand1() == tok->next())
426
0
                    multiplySizeofError(tok);
427
0
            }
428
0
        }
429
92.2k
    }
430
1.36k
}
431
432
void CheckSizeof::multiplySizeofError(const Token *tok)
433
0
{
434
0
    reportError(tok, Severity::warning,
435
0
                "multiplySizeof", "Multiplying sizeof() with sizeof() indicates a logic error.", CWE682, Certainty::inconclusive);
436
0
}
437
438
void CheckSizeof::divideSizeofError(const Token *tok)
439
0
{
440
0
    reportError(tok, Severity::warning,
441
0
                "divideSizeof", "Division of result of sizeof() on pointer type.\n"
442
0
                "Division of result of sizeof() on pointer type. sizeof() returns the size of the pointer, "
443
0
                "not the size of the memory area it points to.", CWE682, Certainty::inconclusive);
444
0
}
445
446
void CheckSizeof::sizeofVoid()
447
1.36k
{
448
1.36k
    if (!mSettings->severity.isEnabled(Severity::portability))
449
0
        return;
450
451
1.36k
    logChecker("CheckSizeof::sizeofVoid"); // portability
452
453
93.5k
    for (const Token *tok = mTokenizer->tokens(); tok; tok = tok->next()) {
454
92.2k
        if (Token::simpleMatch(tok, "sizeof ( void )")) {
455
0
            sizeofVoidError(tok);
456
92.2k
        } else if (Token::simpleMatch(tok, "sizeof (") && tok->next()->astOperand2()) {
457
0
            const ValueType *vt = tok->next()->astOperand2()->valueType();
458
0
            if (vt && vt->type == ValueType::Type::VOID && vt->pointer == 0U)
459
0
                sizeofDereferencedVoidPointerError(tok, tok->strAt(3));
460
92.2k
        } else if (tok->str() == "-") {
461
            // only warn for: 'void *' - 'integral'
462
248
            const ValueType *vt1  = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
463
248
            const ValueType *vt2  = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
464
248
            const bool op1IsvoidPointer = (vt1 && vt1->type == ValueType::Type::VOID && vt1->pointer == 1U);
465
248
            const bool op2IsIntegral    = (vt2 && vt2->isIntegral() && vt2->pointer == 0U);
466
248
            if (op1IsvoidPointer && op2IsIntegral)
467
0
                arithOperationsOnVoidPointerError(tok, tok->astOperand1()->expressionString(), vt1->str());
468
91.9k
        } else if (Token::Match(tok, "+|++|--|+=|-=")) { // Arithmetic operations on variable of type "void*"
469
1.72k
            const ValueType *vt1 = tok->astOperand1() ? tok->astOperand1()->valueType() : nullptr;
470
1.72k
            const ValueType *vt2 = tok->astOperand2() ? tok->astOperand2()->valueType() : nullptr;
471
472
1.72k
            const bool voidpointer1 = (vt1 && vt1->type == ValueType::Type::VOID && vt1->pointer == 1U);
473
1.72k
            const bool voidpointer2 = (vt2 && vt2->type == ValueType::Type::VOID && vt2->pointer == 1U);
474
475
1.72k
            if (voidpointer1)
476
0
                arithOperationsOnVoidPointerError(tok, tok->astOperand1()->expressionString(), vt1->str());
477
478
1.72k
            if (!tok->isAssignmentOp() && voidpointer2)
479
0
                arithOperationsOnVoidPointerError(tok, tok->astOperand2()->expressionString(), vt2->str());
480
1.72k
        }
481
92.2k
    }
482
1.36k
}
483
484
void CheckSizeof::sizeofVoidError(const Token *tok)
485
0
{
486
0
    const std::string message = "Behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
487
0
    const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
488
0
    reportError(tok, Severity::portability, "sizeofVoid", message + "\n" + verbose, CWE682, Certainty::normal);
489
0
}
490
491
void CheckSizeof::sizeofDereferencedVoidPointerError(const Token *tok, const std::string &varname)
492
0
{
493
0
    const std::string message = "'*" + varname + "' is of type 'void', the behaviour of 'sizeof(void)' is not covered by the ISO C standard.";
494
0
    const std::string verbose = message + " A value for 'sizeof(void)' is defined only as part of a GNU C extension, which defines 'sizeof(void)' to be 1.";
495
0
    reportError(tok, Severity::portability, "sizeofDereferencedVoidPointer", message + "\n" + verbose, CWE682, Certainty::normal);
496
0
}
497
498
void CheckSizeof::arithOperationsOnVoidPointerError(const Token* tok, const std::string &varname, const std::string &vartype)
499
0
{
500
0
    const std::string message = "'$symbol' is of type '" + vartype + "'. When using void pointers in calculations, the behaviour is undefined.";
501
0
    const std::string verbose = message + " Arithmetic operations on 'void *' is a GNU C extension, which defines the 'sizeof(void)' to be 1.";
502
0
    reportError(tok, Severity::portability, "arithOperationsOnVoidPointer", "$symbol:" + varname + '\n' + message + '\n' + verbose, CWE467, Certainty::normal);
503
0
}