Coverage Report

Created: 2025-01-24 06:31

/src/cppcheck/oss-fuzz/build/checkbool.cpp
Line
Count
Source (jump to first uncovered line)
1
#include "matchcompiler.h"
2
#include <string>
3
#include <cstring>
4
#include "errorlogger.h"
5
#include "token.h"
6
// pattern: bool|_Bool
7
1.51k
static inline bool match1(const Token* tok) {
8
1.51k
    if (!tok || !((tok->str() == MatchCompiler::makeConstString("bool")) || (tok->str() == MatchCompiler::makeConstString("_Bool"))))
9
1.51k
        return false;
10
0
    return true;
11
1.51k
}
12
// pattern: if|while (
13
18
static inline bool match2(const Token* tok) {
14
18
    if (!tok || !(((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("if")) || ((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("while"))))
15
4
        return false;
16
14
    tok = tok->next();
17
14
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
18
0
        return false;
19
14
    return true;
20
14
}
21
// pattern: %name% (
22
0
static inline bool match3(const Token* tok) {
23
0
    if (!tok || !tok->isName())
24
0
        return false;
25
0
    tok = tok->next();
26
0
    if (!tok || !((tok->tokType() == Token::eExtendedOp) && tok->str() == MatchCompiler::makeConstString("(")))
27
0
        return false;
28
0
    return true;
29
0
}
30
// pattern: !
31
1.25k
static inline bool match4(const Token* tok) {
32
1.25k
    if (!tok || !((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("!")))
33
1.25k
        return false;
34
0
    return true;
35
1.25k
}
36
// pattern: ==|!=
37
112
static inline bool match5(const Token* tok) {
38
112
    if (!tok || !(((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!="))))
39
81
        return false;
40
31
    return true;
41
112
}
42
// pattern: >|==|!=
43
2
static inline bool match6(const Token* tok) {
44
2
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString(">")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!="))))
45
1
        return false;
46
1
    return true;
47
2
}
48
// pattern: <|==|!=
49
1
static inline bool match7(const Token* tok) {
50
1
    if (!tok || !(((tok->tokType() == Token::eBracket || tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("<")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("==")) || ((tok->tokType() == Token::eComparisonOp) && tok->str() == MatchCompiler::makeConstString("!="))))
51
0
        return false;
52
1
    return true;
53
1
}
54
// pattern: ;
55
0
template<class T> static inline T * findmatch8(T * start_tok) {
56
0
    for (; start_tok; start_tok = start_tok->next()) {
57
58
0
    T * tok = start_tok;
59
0
    if (!tok || !(tok->str() == MatchCompiler::makeConstString(";")))
60
0
        continue;
61
0
    return start_tok;
62
0
    }
63
0
    return nullptr;
64
0
}
65
// pattern: &&|%oror%
66
652
static inline bool match9(const Token* tok) {
67
652
    if (!tok || !(((tok->tokType() == Token::eLogicalOp) && tok->str() == MatchCompiler::makeConstString("&&")) || (tok->tokType() == Token::eLogicalOp && tok->str() == MatchCompiler::makeConstString("||"))))
68
652
        return false;
69
0
    return true;
70
652
}
71
// pattern: return
72
0
static inline bool match10(const Token* tok) {
73
0
    if (!tok || !((tok->tokType() == Token::eKeyword) && tok->str() == MatchCompiler::makeConstString("return")))
74
0
        return false;
75
0
    return true;
76
0
}
77
// pattern: &|%or%
78
0
static inline bool match11(const Token* tok) {
79
0
    if (!tok || !(((tok->tokType() == Token::eBitOp) && tok->str() == MatchCompiler::makeConstString("&")) || (tok->tokType() == Token::eBitOp && tok->str() == MatchCompiler::makeConstString("|") )))
80
0
        return false;
81
0
    return true;
82
0
}
83
/*
84
 * Cppcheck - A tool for static C/C++ code analysis
85
 * Copyright (C) 2007-2024 Cppcheck team.
86
 *
87
 * This program is free software: you can redistribute it and/or modify
88
 * it under the terms of the GNU General Public License as published by
89
 * the Free Software Foundation, either version 3 of the License, or
90
 * (at your option) any later version.
91
 *
92
 * This program is distributed in the hope that it will be useful,
93
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
94
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
95
 * GNU General Public License for more details.
96
 *
97
 * You should have received a copy of the GNU General Public License
98
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
99
 */
100
101
102
//---------------------------------------------------------------------------
103
#include "checkbool.h"
104
105
#include "astutils.h"
106
#include "errortypes.h"
107
#include "settings.h"
108
#include "symboldatabase.h"
109
#include "token.h"
110
#include "tokenize.h"
111
#include "vfvalue.h"
112
113
#include <list>
114
#include <vector>
115
//---------------------------------------------------------------------------
116
117
// Register this check class (by creating a static instance of it)
118
namespace {
119
    CheckBool instance;
120
}
121
122
static const CWE CWE398(398U);  // Indicator of Poor Code Quality
123
static const CWE CWE571(571U);  // Expression is Always True
124
static const CWE CWE587(587U);  // Assignment of a Fixed Address to a Pointer
125
static const CWE CWE704(704U);  // Incorrect Type Conversion or Cast
126
127
static bool isBool(const Variable* var)
128
412
{
129
412
    return (var && match1(var->typeEndToken()));
130
412
}
131
132
//---------------------------------------------------------------------------
133
void CheckBool::checkIncrementBoolean()
134
764
{
135
764
    if (!mSettings->severity.isEnabled(Severity::style) && !mSettings->isPremiumEnabled("incrementboolean"))
136
0
        return;
137
138
764
    logChecker("CheckBool::checkIncrementBoolean"); // style
139
140
764
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
141
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
142
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
143
21.5k
            if (astIsBool(tok) && tok->astParent() && tok->astParent()->str() == MatchCompiler::makeConstString("++")) {
144
0
                incrementBooleanError(tok);
145
0
            }
146
21.5k
        }
147
1.10k
    }
148
764
}
149
150
void CheckBool::incrementBooleanError(const Token *tok)
151
0
{
152
0
    reportError(
153
0
        tok,
154
0
        Severity::style,
155
0
        "incrementboolean",
156
0
        "Incrementing a variable of type 'bool' with postfix operator++ is deprecated by the C++ Standard. You should assign it the value 'true' instead.\n"
157
0
        "The operand of a postfix increment operator may be of type bool but it is deprecated by C++ Standard (Annex D-1) and the operand is always set to true. You should assign it the value 'true' instead.",
158
0
        CWE398, Certainty::normal
159
0
        );
160
0
}
161
162
static bool isConvertedToBool(const Token* tok)
163
18
{
164
18
    if (!tok->astParent())
165
0
        return false;
166
18
    return astIsBool(tok->astParent()) || match2(tok->astParent()->previous());
167
18
}
168
169
//---------------------------------------------------------------------------
170
// if (bool & bool) -> if (bool && bool)
171
// if (bool | bool) -> if (bool || bool)
172
//---------------------------------------------------------------------------
173
void CheckBool::checkBitwiseOnBoolean()
174
764
{
175
764
    if (!mSettings->severity.isEnabled(Severity::style))
176
0
        return;
177
178
    // danmar: this is inconclusive because I don't like that there are
179
    //         warnings for calculations. Example: set_flag(a & b);
180
764
    if (!mSettings->certainty.isEnabled(Certainty::inconclusive))
181
0
        return;
182
183
764
    logChecker("CheckBool::checkBitwiseOnBoolean"); // style,inconclusive
184
185
764
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
186
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
187
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
188
21.5k
            if (tok->isBinaryOp()) {
189
4.52k
                bool isCompound{};
190
4.52k
                if (tok->str() == MatchCompiler::makeConstString("&") || tok->str() == MatchCompiler::makeConstString("|"))
191
200
                    isCompound = false;
192
4.32k
                else if (tok->str() == MatchCompiler::makeConstString("&=") || tok->str() == MatchCompiler::makeConstString("|="))
193
0
                    isCompound = true;
194
4.32k
                else
195
4.32k
                    continue;
196
200
                const bool isBoolOp1 = astIsBool(tok->astOperand1());
197
200
                const bool isBoolOp2 = astIsBool(tok->astOperand2());
198
200
                if (!tok->astOperand1()->valueType() || !tok->astOperand2()->valueType())
199
94
                    continue;
200
106
                if (!(isBoolOp1 || isBoolOp2))
201
56
                    continue;
202
50
                if (isCompound && (!isBoolOp1 || isBoolOp2))
203
0
                    continue;
204
50
                if (tok->str() == MatchCompiler::makeConstString("|") && !isConvertedToBool(tok) && !(isBoolOp1 && isBoolOp2))
205
4
                    continue;
206
                // first operand will always be evaluated
207
46
                if (!isConstExpression(tok->astOperand2(), mSettings->library))
208
11
                    continue;
209
35
                if (tok->astOperand2()->variable() && tok->astOperand2()->variable()->nameToken() == tok->astOperand2())
210
0
                    continue;
211
35
                const std::string expression = (isBoolOp1 ? tok->astOperand1() : tok->astOperand2())->expressionString();
212
35
                bitwiseOnBooleanError(tok, expression, tok->str() == MatchCompiler::makeConstString("&") ? "&&" : "||", isCompound);
213
35
            }
214
21.5k
        }
215
1.10k
    }
216
764
}
217
218
void CheckBool::bitwiseOnBooleanError(const Token* tok, const std::string& expression, const std::string& op, bool isCompound)
219
35
{
220
35
    std::string msg = "Boolean expression '" + expression + "' is used in bitwise operation.";
221
35
    if (!isCompound)
222
35
        msg += " Did you mean '" + op + "'?";
223
35
    reportError(tok,
224
35
                Severity::style,
225
35
                "bitwiseOnBoolean",
226
35
                msg,
227
35
                CWE398,
228
35
                Certainty::inconclusive);
229
35
}
230
231
//---------------------------------------------------------------------------
232
//    if (!x==3) <- Probably meant to be "x!=3"
233
//---------------------------------------------------------------------------
234
235
void CheckBool::checkComparisonOfBoolWithInt()
236
764
{
237
764
    if (!mSettings->severity.isEnabled(Severity::warning) || !mTokenizer->isCPP())
238
0
        return;
239
240
764
    logChecker("CheckBool::checkComparisonOfBoolWithInt"); // warning,c++
241
242
764
    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
243
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
244
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
245
21.5k
            if (!tok->isComparisonOp() || !tok->isBinaryOp())
246
20.6k
                continue;
247
932
            const Token* const left = tok->astOperand1();
248
932
            const Token* const right = tok->astOperand2();
249
932
            if (left->isBoolean() && right->varId()) { // Comparing boolean constant with variable
250
0
                if (tok->str() != MatchCompiler::makeConstString("==") && tok->str() != MatchCompiler::makeConstString("!=")) {
251
0
                    comparisonOfBoolWithInvalidComparator(right, left->str());
252
0
                }
253
932
            } else if (left->varId() && right->isBoolean()) { // Comparing variable with boolean constant
254
0
                if (tok->str() != MatchCompiler::makeConstString("==") && tok->str() != MatchCompiler::makeConstString("!=")) {
255
0
                    comparisonOfBoolWithInvalidComparator(right, left->str());
256
0
                }
257
0
            }
258
932
        }
259
1.10k
    }
260
764
}
261
262
void CheckBool::comparisonOfBoolWithInvalidComparator(const Token *tok, const std::string &expression)
263
0
{
264
0
    reportError(tok, Severity::warning, "comparisonOfBoolWithInvalidComparator",
265
0
                "Comparison of a boolean value using relational operator (<, >, <= or >=).\n"
266
0
                "The result of the expression '" + expression + "' is of type 'bool'. "
267
0
                "Comparing 'bool' value using relational (<, >, <= or >=)"
268
0
                " operator could cause unexpected results.");
269
0
}
270
271
//-------------------------------------------------------------------------------
272
// Comparing functions which are returning value of type bool
273
//-------------------------------------------------------------------------------
274
275
static bool tokenIsFunctionReturningBool(const Token* tok)
276
1.25k
{
277
1.25k
    const Function* func = tok ? tok->function() : nullptr;
278
1.25k
    if (func && match3(tok)) {
279
0
        if (func->tokenDef && match1(func->tokenDef->previous())) {
280
0
            return true;
281
0
        }
282
0
    }
283
1.25k
    return false;
284
1.25k
}
285
286
void CheckBool::checkComparisonOfFuncReturningBool()
287
764
{
288
764
    if (!mSettings->severity.isEnabled(Severity::style))
289
0
        return;
290
291
764
    if (!mTokenizer->isCPP())
292
0
        return;
293
294
764
    logChecker("CheckBool::checkComparisonOfFuncReturningBool"); // style,c++
295
296
764
    const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
297
1.25k
    auto getFunctionTok = [](const Token* tok) -> const Token* {
298
1.25k
        while (match4(tok) || (tok && tok->isCast() && !isCPPCast(tok)))
299
0
            tok = tok->astOperand1();
300
1.25k
        if (isCPPCast(tok))
301
0
            tok = tok->astOperand2();
302
1.25k
        if (tok)
303
1.25k
            return tok->previous();
304
0
        return nullptr;
305
1.25k
    };
306
307
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
308
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
309
21.5k
            if (!tok->isComparisonOp() || tok->str() == MatchCompiler::makeConstString("==") || tok->str() == MatchCompiler::makeConstString("!="))
310
20.9k
                continue;
311
312
627
            const Token* firstToken = getFunctionTok(tok->astOperand1());
313
627
            const Token* secondToken = getFunctionTok(tok->astOperand2());
314
627
            if (!firstToken || !secondToken)
315
0
                continue;
316
317
627
            const bool firstIsFunctionReturningBool = tokenIsFunctionReturningBool(firstToken);
318
627
            const bool secondIsFunctionReturningBool = tokenIsFunctionReturningBool(secondToken);
319
627
            if (firstIsFunctionReturningBool && secondIsFunctionReturningBool) {
320
0
                comparisonOfTwoFuncsReturningBoolError(firstToken->next(), firstToken->str(), secondToken->str());
321
627
            } else if (firstIsFunctionReturningBool) {
322
0
                comparisonOfFuncReturningBoolError(firstToken->next(), firstToken->str());
323
627
            } else if (secondIsFunctionReturningBool) {
324
0
                comparisonOfFuncReturningBoolError(secondToken->previous(), secondToken->str());
325
0
            }
326
627
        }
327
1.10k
    }
328
764
}
329
330
void CheckBool::comparisonOfFuncReturningBoolError(const Token *tok, const std::string &expression)
331
0
{
332
0
    reportError(tok, Severity::style, "comparisonOfFuncReturningBoolError",
333
0
                "Comparison of a function returning boolean value using relational (<, >, <= or >=) operator.\n"
334
0
                "The return type of function '" + expression + "' is 'bool' "
335
0
                "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)"
336
0
                " operator could cause unexpected results.", CWE398, Certainty::normal);
337
0
}
338
339
void CheckBool::comparisonOfTwoFuncsReturningBoolError(const Token *tok, const std::string &expression1, const std::string &expression2)
340
0
{
341
0
    reportError(tok, Severity::style, "comparisonOfTwoFuncsReturningBoolError",
342
0
                "Comparison of two functions returning boolean value using relational (<, >, <= or >=) operator.\n"
343
0
                "The return type of function '" + expression1 + "' and function '" + expression2 + "' is 'bool' "
344
0
                "and result is of type 'bool'. Comparing 'bool' value using relational (<, >, <= or >=)"
345
0
                " operator could cause unexpected results.", CWE398, Certainty::normal);
346
0
}
347
348
//-------------------------------------------------------------------------------
349
// Comparison of bool with bool
350
//-------------------------------------------------------------------------------
351
352
void CheckBool::checkComparisonOfBoolWithBool()
353
764
{
354
764
    if (!mSettings->severity.isEnabled(Severity::style))
355
0
        return;
356
357
764
    if (!mTokenizer->isCPP())
358
0
        return;
359
360
764
    logChecker("CheckBool::checkComparisonOfBoolWithBool"); // style,c++
361
362
764
    const SymbolDatabase* const symbolDatabase = mTokenizer->getSymbolDatabase();
363
364
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
365
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
366
21.5k
            if (!tok->isComparisonOp() || tok->str() == MatchCompiler::makeConstString("==") || tok->str() == MatchCompiler::makeConstString("!="))
367
20.9k
                continue;
368
627
            bool firstTokenBool = false;
369
370
627
            const Token *firstToken = tok->previous();
371
627
            if (firstToken->varId()) {
372
412
                if (isBool(firstToken->variable())) {
373
0
                    firstTokenBool = true;
374
0
                }
375
412
            }
376
627
            if (!firstTokenBool)
377
627
                continue;
378
379
0
            bool secondTokenBool = false;
380
0
            const Token *secondToken = tok->next();
381
0
            if (secondToken->varId()) {
382
0
                if (isBool(secondToken->variable())) {
383
0
                    secondTokenBool = true;
384
0
                }
385
0
            }
386
0
            if (secondTokenBool) {
387
0
                comparisonOfBoolWithBoolError(firstToken->next(), secondToken->str());
388
0
            }
389
0
        }
390
1.10k
    }
391
764
}
392
393
void CheckBool::comparisonOfBoolWithBoolError(const Token *tok, const std::string &expression)
394
0
{
395
0
    reportError(tok, Severity::style, "comparisonOfBoolWithBoolError",
396
0
                "Comparison of a variable having boolean value using relational (<, >, <= or >=) operator.\n"
397
0
                "The variable '" + expression + "' is of type 'bool' "
398
0
                "and comparing 'bool' value using relational (<, >, <= or >=)"
399
0
                " operator could cause unexpected results.", CWE398, Certainty::normal);
400
0
}
401
402
//-----------------------------------------------------------------------------
403
void CheckBool::checkAssignBoolToPointer()
404
764
{
405
764
    logChecker("CheckBool::checkAssignBoolToPointer");
406
764
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
407
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
408
23.7k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
409
22.6k
            if (tok->str() == MatchCompiler::makeConstString("=") && astIsPointer(tok->astOperand1()) && astIsBool(tok->astOperand2())) {
410
0
                assignBoolToPointerError(tok);
411
0
            }
412
22.6k
        }
413
1.10k
    }
414
764
}
415
416
void CheckBool::assignBoolToPointerError(const Token *tok)
417
0
{
418
0
    reportError(tok, Severity::error, "assignBoolToPointer",
419
0
                "Boolean value assigned to pointer.", CWE587, Certainty::normal);
420
0
}
421
422
//-----------------------------------------------------------------------------
423
//-----------------------------------------------------------------------------
424
void CheckBool::checkComparisonOfBoolExpressionWithInt()
425
764
{
426
764
    if (!mSettings->severity.isEnabled(Severity::warning) && !mSettings->isPremiumEnabled("compareBoolExpressionWithInt"))
427
0
        return;
428
429
764
    logChecker("CheckBool::checkComparisonOfBoolExpressionWithInt"); // warning
430
431
764
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
432
433
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
434
22.6k
        for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
435
21.5k
            if (!tok->isComparisonOp())
436
20.6k
                continue;
437
438
932
            const Token* numTok = nullptr;
439
932
            const Token* boolExpr = nullptr;
440
932
            bool numInRhs;
441
932
            if (astIsBool(tok->astOperand1())) {
442
119
                boolExpr = tok->astOperand1();
443
119
                numTok = tok->astOperand2();
444
119
                numInRhs = true;
445
813
            } else if (astIsBool(tok->astOperand2())) {
446
18
                boolExpr = tok->astOperand2();
447
18
                numTok = tok->astOperand1();
448
18
                numInRhs = false;
449
795
            } else {
450
795
                continue;
451
795
            }
452
453
137
            if (!numTok || !boolExpr)
454
0
                continue;
455
456
137
            if (boolExpr->isOp() && numTok->isName() && match5(tok))
457
                // there is weird code such as:  ((a<b)==c)
458
                // but it is probably written this way by design.
459
31
                continue;
460
461
106
            if (astIsBool(numTok))
462
1
                continue;
463
464
105
            const ValueFlow::Value *minval = numTok->getValueLE(0, *mSettings);
465
105
            if (minval && minval->intvalue == 0 &&
466
105
                (numInRhs ? match6(tok)
467
2
                 : match7(tok)))
468
1
                minval = nullptr;
469
470
105
            const ValueFlow::Value *maxval = numTok->getValueGE(1, *mSettings);
471
105
            if (maxval && maxval->intvalue == 1 &&
472
105
                (numInRhs ? match7(tok)
473
1
                 : match6(tok)))
474
1
                maxval = nullptr;
475
476
105
            if (minval || maxval) {
477
1
                const bool not0or1 = (minval && minval->intvalue < 0) || (maxval && maxval->intvalue > 1);
478
1
                comparisonOfBoolExpressionWithIntError(tok, not0or1);
479
1
            }
480
105
        }
481
1.10k
    }
482
764
}
483
484
void CheckBool::comparisonOfBoolExpressionWithIntError(const Token *tok, bool not0or1)
485
1
{
486
1
    if (not0or1)
487
0
        reportError(tok, Severity::warning, "compareBoolExpressionWithInt",
488
0
                    "Comparison of a boolean expression with an integer other than 0 or 1.", CWE398, Certainty::normal);
489
1
    else
490
1
        reportError(tok, Severity::warning, "compareBoolExpressionWithInt",
491
1
                    "Comparison of a boolean expression with an integer.", CWE398, Certainty::normal);
492
1
}
493
494
495
void CheckBool::pointerArithBool()
496
764
{
497
764
    logChecker("CheckBool::pointerArithBool");
498
499
764
    const SymbolDatabase* symbolDatabase = mTokenizer->getSymbolDatabase();
500
501
2.79k
    for (const Scope &scope : symbolDatabase->scopeList) {
502
2.79k
        if (scope.type != Scope::eIf && !scope.isLoopScope())
503
2.14k
            continue;
504
652
        const Token* tok = scope.classDef->next()->astOperand2();
505
652
        if (scope.type == Scope::eFor) {
506
0
            tok = findmatch8(scope.classDef->tokAt(2)) ;
507
0
            if (tok)
508
0
                tok = tok->astOperand2();
509
0
            if (tok)
510
0
                tok = tok->astOperand1();
511
652
        } else if (scope.type == Scope::eDo)
512
0
            tok = (scope.bodyEnd->tokAt(2)) ? scope.bodyEnd->tokAt(2)->astOperand2() : nullptr;
513
514
652
        pointerArithBoolCond(tok);
515
652
    }
516
764
}
517
518
void CheckBool::pointerArithBoolCond(const Token *tok)
519
652
{
520
652
    if (!tok)
521
0
        return;
522
652
    if (match9(tok)) {
523
0
        pointerArithBoolCond(tok->astOperand1());
524
0
        pointerArithBoolCond(tok->astOperand2());
525
0
        return;
526
0
    }
527
652
    if (tok->str() != MatchCompiler::makeConstString("+") && tok->str() != MatchCompiler::makeConstString("-"))
528
652
        return;
529
530
0
    if (tok->isBinaryOp() &&
531
0
        tok->astOperand1()->isName() &&
532
0
        tok->astOperand1()->variable() &&
533
0
        tok->astOperand1()->variable()->isPointer() &&
534
0
        tok->astOperand2()->isNumber())
535
0
        pointerArithBoolError(tok);
536
0
}
537
538
void CheckBool::pointerArithBoolError(const Token *tok)
539
0
{
540
0
    reportError(tok,
541
0
                Severity::error,
542
0
                "pointerArithBool",
543
0
                "Converting pointer arithmetic result to bool. The bool is always true unless there is undefined behaviour.\n"
544
0
                "Converting pointer arithmetic result to bool. The boolean result is always true unless there is pointer arithmetic overflow, and overflow is undefined behaviour. Probably a dereference is forgotten.", CWE571, Certainty::normal);
545
0
}
546
547
void CheckBool::checkAssignBoolToFloat()
548
764
{
549
764
    if (!mTokenizer->isCPP())
550
0
        return;
551
764
    if (!mSettings->severity.isEnabled(Severity::style))
552
0
        return;
553
764
    logChecker("CheckBool::checkAssignBoolToFloat"); // style,c++
554
764
    const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
555
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
556
23.7k
        for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
557
22.6k
            if (tok->str() == MatchCompiler::makeConstString("=") && astIsFloat(tok->astOperand1(), false) && astIsBool(tok->astOperand2())) {
558
0
                assignBoolToFloatError(tok);
559
0
            }
560
22.6k
        }
561
1.10k
    }
562
764
}
563
564
void CheckBool::assignBoolToFloatError(const Token *tok)
565
0
{
566
0
    reportError(tok, Severity::style, "assignBoolToFloat",
567
0
                "Boolean value assigned to floating point variable.", CWE704, Certainty::normal);
568
0
}
569
570
void CheckBool::returnValueOfFunctionReturningBool()
571
764
{
572
764
    if (!mSettings->severity.isEnabled(Severity::style))
573
0
        return;
574
575
764
    logChecker("CheckBool::returnValueOfFunctionReturningBool"); // style
576
577
764
    const SymbolDatabase * const symbolDatabase = mTokenizer->getSymbolDatabase();
578
579
1.10k
    for (const Scope * scope : symbolDatabase->functionScopes) {
580
1.10k
        if (!(scope->function && match1(scope->function->retDef)))
581
1.10k
            continue;
582
583
0
        for (const Token* tok = scope->bodyStart->next(); tok && (tok != scope->bodyEnd); tok = tok->next()) {
584
            // Skip lambdas
585
0
            const Token* tok2 = findLambdaEndToken(tok);
586
0
            if (tok2)
587
0
                tok = tok2;
588
0
            else if (tok->scope() && tok->scope()->isClassOrStruct())
589
0
                tok = tok->scope()->bodyEnd;
590
0
            else if (match10(tok) && tok->astOperand1() &&
591
0
                     (tok->astOperand1()->getValueGE(2, *mSettings) || tok->astOperand1()->getValueLE(-1, *mSettings)) &&
592
0
                     !(tok->astOperand1()->astOperand1() && match11(tok->astOperand1())))
593
0
                returnValueBoolError(tok);
594
0
        }
595
0
    }
596
764
}
597
598
void CheckBool::returnValueBoolError(const Token *tok)
599
0
{
600
0
    reportError(tok, Severity::style, "returnNonBoolInBooleanFunction", "Non-boolean value returned from function returning bool");
601
0
}
602
603
void CheckBool::runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger)
604
764
{
605
764
    CheckBool checkBool(&tokenizer, &tokenizer.getSettings(), errorLogger);
606
607
    // Checks
608
764
    checkBool.checkComparisonOfBoolExpressionWithInt();
609
764
    checkBool.checkComparisonOfBoolWithInt();
610
764
    checkBool.checkAssignBoolToFloat();
611
764
    checkBool.pointerArithBool();
612
764
    checkBool.returnValueOfFunctionReturningBool();
613
764
    checkBool.checkComparisonOfFuncReturningBool();
614
764
    checkBool.checkComparisonOfBoolWithBool();
615
764
    checkBool.checkIncrementBoolean();
616
764
    checkBool.checkAssignBoolToPointer();
617
764
    checkBool.checkBitwiseOnBoolean();
618
764
}
619
620
void CheckBool::getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const
621
0
{
622
0
    CheckBool c(nullptr, settings, errorLogger);
623
0
    c.assignBoolToPointerError(nullptr);
624
0
    c.assignBoolToFloatError(nullptr);
625
0
    c.comparisonOfFuncReturningBoolError(nullptr, "func_name");
626
0
    c.comparisonOfTwoFuncsReturningBoolError(nullptr, "func_name1", "func_name2");
627
0
    c.comparisonOfBoolWithBoolError(nullptr, "var_name");
628
0
    c.incrementBooleanError(nullptr);
629
0
    c.bitwiseOnBooleanError(nullptr, "expression", "&&");
630
0
    c.comparisonOfBoolExpressionWithIntError(nullptr, true);
631
0
    c.pointerArithBoolError(nullptr);
632
0
    c.comparisonOfBoolWithInvalidComparator(nullptr, "expression");
633
0
    c.returnValueBoolError(nullptr);
634
0
}