Coverage Report

Created: 2023-09-25 06:15

/src/cppcheck/lib/checkother.h
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
#ifndef checkotherH
22
#define checkotherH
23
//---------------------------------------------------------------------------
24
25
#include "check.h"
26
#include "config.h"
27
#include "errortypes.h"
28
#include "tokenize.h"
29
30
#include <string>
31
#include <vector>
32
33
namespace ValueFlow {
34
    class Value;
35
}
36
37
class Settings;
38
class Token;
39
class Function;
40
class Variable;
41
class ErrorLogger;
42
43
/// @addtogroup Checks
44
/// @{
45
46
47
/** @brief Various small checks */
48
49
class CPPCHECKLIB CheckOther : public Check {
50
    friend class TestCharVar;
51
    friend class TestIncompleteStatement;
52
    friend class TestOther;
53
54
public:
55
    /** @brief This constructor is used when registering the CheckClass */
56
2
    CheckOther() : Check(myName()) {}
57
58
    /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is less than zero? */
59
    static bool comparisonNonZeroExpressionLessThanZero(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr);
60
61
    /** Is expression a comparison that checks if a nonzero (unsigned/pointer) expression is positive? */
62
    static bool testIfNonZeroExpressionIsPositive(const Token *tok, const ValueFlow::Value **zeroValue, const Token **nonZeroExpr);
63
64
private:
65
    /** @brief This constructor is used when running checks. */
66
    CheckOther(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
67
1.36k
        : Check(myName(), tokenizer, settings, errorLogger) {}
68
69
70
    /** @brief Run checks against the normal token list */
71
1.36k
    void runChecks(const Tokenizer &tokenizer, ErrorLogger *errorLogger) override {
72
1.36k
        CheckOther checkOther(&tokenizer, tokenizer.getSettings(), errorLogger);
73
74
        // Checks
75
1.36k
        checkOther.warningOldStylePointerCast();
76
1.36k
        checkOther.invalidPointerCast();
77
1.36k
        checkOther.checkCharVariable();
78
1.36k
        checkOther.checkRedundantAssignment();
79
1.36k
        checkOther.redundantBitwiseOperationInSwitchError();
80
1.36k
        checkOther.checkSuspiciousCaseInSwitch();
81
1.36k
        checkOther.checkDuplicateBranch();
82
1.36k
        checkOther.checkDuplicateExpression();
83
1.36k
        checkOther.checkUnreachableCode();
84
1.36k
        checkOther.checkSuspiciousSemicolon();
85
1.36k
        checkOther.checkVariableScope();
86
1.36k
        checkOther.checkSignOfUnsignedVariable();  // don't ignore casts (#3574)
87
1.36k
        checkOther.checkIncompleteArrayFill();
88
1.36k
        checkOther.checkVarFuncNullUB();
89
1.36k
        checkOther.checkNanInArithmeticExpression();
90
1.36k
        checkOther.checkCommaSeparatedReturn();
91
1.36k
        checkOther.checkRedundantPointerOp();
92
1.36k
        checkOther.checkZeroDivision();
93
1.36k
        checkOther.checkNegativeBitwiseShift();
94
1.36k
        checkOther.checkInterlockedDecrement();
95
1.36k
        checkOther.checkUnusedLabel();
96
1.36k
        checkOther.checkEvaluationOrder();
97
1.36k
        checkOther.checkFuncArgNamesDifferent();
98
1.36k
        checkOther.checkShadowVariables();
99
1.36k
        checkOther.checkKnownArgument();
100
1.36k
        checkOther.checkKnownPointerToBool();
101
1.36k
        checkOther.checkComparePointers();
102
1.36k
        checkOther.checkIncompleteStatement();
103
1.36k
        checkOther.checkRedundantCopy();
104
1.36k
        checkOther.clarifyCalculation();
105
1.36k
        checkOther.checkPassByReference();
106
1.36k
        checkOther.checkConstVariable();
107
1.36k
        checkOther.checkConstPointer();
108
1.36k
        checkOther.checkComparisonFunctionIsAlwaysTrueOrFalse();
109
1.36k
        checkOther.checkInvalidFree();
110
1.36k
        checkOther.clarifyStatement();
111
1.36k
        checkOther.checkCastIntToCharAndBack();
112
1.36k
        checkOther.checkMisusedScopedObject();
113
1.36k
        checkOther.checkAccessOfMovedVariable();
114
1.36k
        checkOther.checkModuloOfOne();
115
1.36k
        checkOther.checkOverlappingWrite();
116
1.36k
    }
117
118
    /** @brief Clarify calculation for ".. a * b ? .." */
119
    void clarifyCalculation();
120
121
    /** @brief Suspicious statement like '*A++;' */
122
    void clarifyStatement();
123
124
    /** @brief Are there C-style pointer casts in a c++ file? */
125
    void warningOldStylePointerCast();
126
127
    /** @brief Check for pointer casts to a type with an incompatible binary data representation */
128
    void invalidPointerCast();
129
130
    /** @brief %Check scope of variables */
131
    void checkVariableScope();
132
    bool checkInnerScope(const Token *tok, const Variable* var, bool& used) const;
133
134
    /** @brief %Check for comma separated statements in return */
135
    void checkCommaSeparatedReturn();
136
137
    /** @brief %Check for function parameters that should be passed by reference */
138
    void checkPassByReference();
139
140
    void checkConstVariable();
141
    void checkConstPointer();
142
143
    /** @brief Using char variable as array index / as operand in bit operation */
144
    void checkCharVariable();
145
146
    /** @brief Incomplete statement. A statement that only contains a constant or variable */
147
    void checkIncompleteStatement();
148
149
    /** @brief %Check zero division*/
150
    void checkZeroDivision();
151
152
    /** @brief Check for NaN (not-a-number) in an arithmetic expression */
153
    void checkNanInArithmeticExpression();
154
155
    /** @brief copying to memory or assigning to a variable twice */
156
    void checkRedundantAssignment();
157
158
    /** @brief %Check for redundant bitwise operation in switch statement*/
159
    void redundantBitwiseOperationInSwitchError();
160
161
    /** @brief %Check for code like 'case A||B:'*/
162
    void checkSuspiciousCaseInSwitch();
163
164
    /** @brief %Check for objects that are destroyed immediately */
165
    void checkMisusedScopedObject();
166
167
    /** @brief %Check for suspicious code where if and else branch are the same (e.g "if (a) b = true; else b = true;") */
168
    void checkDuplicateBranch();
169
170
    /** @brief %Check for suspicious code with the same expression on both sides of operator (e.g "if (a && a)") */
171
    void checkDuplicateExpression();
172
173
    /** @brief %Check for code that gets never executed, such as duplicate break statements */
174
    void checkUnreachableCode();
175
176
    /** @brief %Check for testing sign of unsigned variable */
177
    void checkSignOfUnsignedVariable();
178
179
    /** @brief %Check for suspicious use of semicolon */
180
    void checkSuspiciousSemicolon();
181
182
    /** @brief %Check for free() operations on invalid memory locations */
183
    void checkInvalidFree();
184
    void invalidFreeError(const Token *tok, const std::string &allocation, bool inconclusive);
185
186
    /** @brief %Check for code creating redundant copies */
187
    void checkRedundantCopy();
188
189
    /** @brief %Check for bitwise shift with negative right operand */
190
    void checkNegativeBitwiseShift();
191
192
    /** @brief %Check for buffers that are filled incompletely with memset and similar functions */
193
    void checkIncompleteArrayFill();
194
195
    /** @brief %Check that variadic function calls don't use NULL. If NULL is \#defined as 0 and the function expects a pointer, the behaviour is undefined. */
196
    void checkVarFuncNullUB();
197
198
    /** @brief %Check to avoid casting a return value to unsigned char and then back to integer type.  */
199
    void checkCastIntToCharAndBack();
200
201
    /** @brief %Check for using of comparison functions evaluating always to true or false. */
202
    void checkComparisonFunctionIsAlwaysTrueOrFalse();
203
204
    /** @brief %Check for redundant pointer operations */
205
    void checkRedundantPointerOp();
206
207
    /** @brief %Check for race condition with non-interlocked access after InterlockedDecrement() */
208
    void checkInterlockedDecrement();
209
210
    /** @brief %Check for unused labels */
211
    void checkUnusedLabel();
212
213
    /** @brief %Check for expression that depends on order of evaluation of side effects */
214
    void checkEvaluationOrder();
215
216
    /** @brief %Check for access of moved or forwarded variable */
217
    void checkAccessOfMovedVariable();
218
219
    /** @brief %Check if function declaration and definition argument names different */
220
    void checkFuncArgNamesDifferent();
221
222
    /** @brief %Check for shadow variables. Less noisy than gcc/clang -Wshadow. */
223
    void checkShadowVariables();
224
225
    void checkKnownArgument();
226
227
    void checkKnownPointerToBool();
228
229
    void checkComparePointers();
230
231
    void checkModuloOfOne();
232
233
    void checkOverlappingWrite();
234
    void overlappingWriteUnion(const Token *tok);
235
    void overlappingWriteFunction(const Token *tok);
236
237
    // Error messages..
238
    void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &functionName, const std::string &varName, const bool result);
239
    void checkCastIntToCharAndBackError(const Token *tok, const std::string &strFunctionName);
240
    void clarifyCalculationError(const Token *tok, const std::string &op);
241
    void clarifyStatementError(const Token* tok);
242
    void cstyleCastError(const Token *tok);
243
    void invalidPointerCastError(const Token* tok, const std::string& from, const std::string& to, bool inconclusive, bool toIsInt);
244
    void passedByValueError(const Token *tok, const std::string &parname, bool inconclusive);
245
    void constVariableError(const Variable *var, const Function *function);
246
    void constStatementError(const Token *tok, const std::string &type, bool inconclusive);
247
    void signedCharArrayIndexError(const Token *tok);
248
    void unknownSignCharArrayIndexError(const Token *tok);
249
    void charBitOpError(const Token *tok);
250
    void variableScopeError(const Token *tok, const std::string &varname);
251
    void zerodivError(const Token *tok, const ValueFlow::Value *value);
252
    void nanInArithmeticExpressionError(const Token *tok);
253
    void redundantAssignmentError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive);
254
    void redundantInitializationError(const Token *tok1, const Token* tok2, const std::string& var, bool inconclusive);
255
    void redundantAssignmentInSwitchError(const Token *tok1, const Token *tok2, const std::string &var);
256
    void redundantCopyError(const Token *tok1, const Token* tok2, const std::string& var);
257
    void redundantBitwiseOperationInSwitchError(const Token *tok, const std::string &varname);
258
    void suspiciousCaseInSwitchError(const Token* tok, const std::string& operatorString);
259
    void selfAssignmentError(const Token *tok, const std::string &varname);
260
    void misusedScopeObjectError(const Token *tok, const std::string &varname, bool isAssignment = false);
261
    void duplicateBranchError(const Token *tok1, const Token *tok2, ErrorPath errors);
262
    void duplicateAssignExpressionError(const Token *tok1, const Token *tok2, bool inconclusive);
263
    void oppositeExpressionError(const Token *opTok, ErrorPath errors);
264
    void duplicateExpressionError(const Token *tok1, const Token *tok2, const Token *opTok, ErrorPath errors, bool hasMultipleExpr = false);
265
    void duplicateValueTernaryError(const Token *tok);
266
    void duplicateExpressionTernaryError(const Token *tok, ErrorPath errors);
267
    void duplicateBreakError(const Token *tok, bool inconclusive);
268
    void unreachableCodeError(const Token* tok, const Token* noreturn, bool inconclusive);
269
    void redundantContinueError(const Token* tok);
270
    void unsignedLessThanZeroError(const Token *tok, const ValueFlow::Value *v, const std::string &varname);
271
    void pointerLessThanZeroError(const Token *tok, const ValueFlow::Value *v);
272
    void unsignedPositiveError(const Token *tok, const ValueFlow::Value *v, const std::string &varname);
273
    void pointerPositiveError(const Token *tok, const ValueFlow::Value *v);
274
    void suspiciousSemicolonError(const Token *tok);
275
    void negativeBitwiseShiftError(const Token *tok, int op);
276
    void redundantCopyError(const Token *tok, const std::string &varname);
277
    void incompleteArrayFillError(const Token* tok, const std::string& buffer, const std::string& function, bool boolean);
278
    void varFuncNullUBError(const Token *tok);
279
    void commaSeparatedReturnError(const Token *tok);
280
    void redundantPointerOpError(const Token* tok, const std::string& varname, bool inconclusive, bool addressOfDeref);
281
    void raceAfterInterlockedDecrementError(const Token* tok);
282
    void unusedLabelError(const Token* tok, bool inSwitch, bool hasIfdef);
283
    void unknownEvaluationOrder(const Token* tok);
284
    void accessMovedError(const Token *tok, const std::string &varname, const ValueFlow::Value *value, bool inconclusive);
285
    void funcArgNamesDifferent(const std::string & functionName, nonneg int index, const Token* declaration, const Token* definition);
286
    void funcArgOrderDifferent(const std::string & functionName, const Token * declaration, const Token * definition, const std::vector<const Token*> & declarations, const std::vector<const Token*> & definitions);
287
    void shadowError(const Token *var, const Token *shadowed, std::string type);
288
    void knownArgumentError(const Token *tok, const Token *ftok, const ValueFlow::Value *value, const std::string &varexpr, bool isVariableExpressionHidden);
289
    void knownPointerToBoolError(const Token* tok, const ValueFlow::Value* value);
290
    void comparePointersError(const Token *tok, const ValueFlow::Value *v1, const ValueFlow::Value *v2);
291
    void checkModuloOfOneError(const Token *tok);
292
293
0
    void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const override {
294
0
        CheckOther c(nullptr, settings, errorLogger);
295
296
0
        ErrorPath errorPath;
297
298
        // error
299
0
        c.zerodivError(nullptr, nullptr);
300
0
        c.misusedScopeObjectError(nullptr, "varname");
301
0
        c.invalidPointerCastError(nullptr,  "float *", "double *", false, false);
302
0
        c.negativeBitwiseShiftError(nullptr, 1);
303
0
        c.negativeBitwiseShiftError(nullptr, 2);
304
0
        c.raceAfterInterlockedDecrementError(nullptr);
305
0
        c.invalidFreeError(nullptr, "malloc", false);
306
0
        c.overlappingWriteUnion(nullptr);
307
0
        c.overlappingWriteFunction(nullptr);
308
309
        //performance
310
0
        c.redundantCopyError(nullptr,  "varname");
311
0
        c.redundantCopyError(nullptr, nullptr, "var");
312
313
        // style/warning
314
0
        c.checkComparisonFunctionIsAlwaysTrueOrFalseError(nullptr, "isless","varName",false);
315
0
        c.checkCastIntToCharAndBackError(nullptr, "func_name");
316
0
        c.cstyleCastError(nullptr);
317
0
        c.passedByValueError(nullptr, "parametername", false);
318
0
        c.constVariableError(nullptr, nullptr);
319
0
        c.constStatementError(nullptr, "type", false);
320
0
        c.signedCharArrayIndexError(nullptr);
321
0
        c.unknownSignCharArrayIndexError(nullptr);
322
0
        c.charBitOpError(nullptr);
323
0
        c.variableScopeError(nullptr,  "varname");
324
0
        c.redundantAssignmentInSwitchError(nullptr, nullptr, "var");
325
0
        c.suspiciousCaseInSwitchError(nullptr,  "||");
326
0
        c.selfAssignmentError(nullptr,  "varname");
327
0
        c.clarifyCalculationError(nullptr,  "+");
328
0
        c.clarifyStatementError(nullptr);
329
0
        c.duplicateBranchError(nullptr, nullptr, errorPath);
330
0
        c.duplicateAssignExpressionError(nullptr, nullptr, true);
331
0
        c.oppositeExpressionError(nullptr, errorPath);
332
0
        c.duplicateExpressionError(nullptr, nullptr, nullptr, errorPath);
333
0
        c.duplicateValueTernaryError(nullptr);
334
0
        c.duplicateExpressionTernaryError(nullptr, errorPath);
335
0
        c.duplicateBreakError(nullptr,  false);
336
0
        c.unreachableCodeError(nullptr, nullptr,  false);
337
0
        c.unsignedLessThanZeroError(nullptr, nullptr, "varname");
338
0
        c.unsignedPositiveError(nullptr, nullptr, "varname");
339
0
        c.pointerLessThanZeroError(nullptr, nullptr);
340
0
        c.pointerPositiveError(nullptr, nullptr);
341
0
        c.suspiciousSemicolonError(nullptr);
342
0
        c.incompleteArrayFillError(nullptr,  "buffer", "memset", false);
343
0
        c.varFuncNullUBError(nullptr);
344
0
        c.nanInArithmeticExpressionError(nullptr);
345
0
        c.commaSeparatedReturnError(nullptr);
346
0
        c.redundantPointerOpError(nullptr,  "varname", false, /*addressOfDeref*/ true);
347
0
        c.unusedLabelError(nullptr, false, false);
348
0
        c.unusedLabelError(nullptr, false, true);
349
0
        c.unusedLabelError(nullptr, true, false);
350
0
        c.unusedLabelError(nullptr, true, true);
351
0
        c.unknownEvaluationOrder(nullptr);
352
0
        c.accessMovedError(nullptr, "v", nullptr, false);
353
0
        c.funcArgNamesDifferent("function", 1, nullptr, nullptr);
354
0
        c.redundantBitwiseOperationInSwitchError(nullptr, "varname");
355
0
        c.shadowError(nullptr, nullptr, "variable");
356
0
        c.shadowError(nullptr, nullptr, "function");
357
0
        c.shadowError(nullptr, nullptr, "argument");
358
0
        c.knownArgumentError(nullptr, nullptr, nullptr, "x", false);
359
0
        c.knownPointerToBoolError(nullptr, nullptr);
360
0
        c.comparePointersError(nullptr, nullptr, nullptr);
361
0
        c.redundantAssignmentError(nullptr, nullptr, "var", false);
362
0
        c.redundantInitializationError(nullptr, nullptr, "var", false);
363
364
0
        const std::vector<const Token *> nullvec;
365
0
        c.funcArgOrderDifferent("function", nullptr, nullptr, nullvec, nullvec);
366
0
        c.checkModuloOfOneError(nullptr);
367
0
    }
368
369
1.36k
    static std::string myName() {
370
1.36k
        return "Other";
371
1.36k
    }
372
373
0
    std::string classInfo() const override {
374
0
        return "Other checks\n"
375
376
               // error
377
0
               "- division with zero\n"
378
0
               "- scoped object destroyed immediately after construction\n"
379
0
               "- assignment in an assert statement\n"
380
0
               "- free() or delete of an invalid memory location\n"
381
0
               "- bitwise operation with negative right operand\n"
382
0
               "- cast the return values of getc(),fgetc() and getchar() to character and compare it to EOF\n"
383
0
               "- race condition with non-interlocked access after InterlockedDecrement() call\n"
384
0
               "- expression 'x = x++;' depends on order of evaluation of side effects\n"
385
0
               "- overlapping write of union\n"
386
387
               // warning
388
0
               "- either division by zero or useless condition\n"
389
0
               "- access of moved or forwarded variable.\n"
390
391
               // performance
392
0
               "- redundant data copying for const variable\n"
393
0
               "- subsequent assignment or copying to a variable or buffer\n"
394
0
               "- passing parameter by value\n"
395
396
               // portability
397
0
               "- Passing NULL pointer to function with variable number of arguments leads to UB.\n"
398
399
               // style
400
0
               "- C-style pointer cast in C++ code\n"
401
0
               "- casting between incompatible pointer types\n"
402
0
               "- [Incomplete statement](IncompleteStatement)\n"
403
0
               "- [check how signed char variables are used](CharVar)\n"
404
0
               "- variable scope can be limited\n"
405
0
               "- unusual pointer arithmetic. For example: \"abc\" + 'd'\n"
406
0
               "- redundant assignment, increment, or bitwise operation in a switch statement\n"
407
0
               "- redundant strcpy in a switch statement\n"
408
0
               "- Suspicious case labels in switch()\n"
409
0
               "- assignment of a variable to itself\n"
410
0
               "- Comparison of values leading always to true or false\n"
411
0
               "- Clarify calculation with parentheses\n"
412
0
               "- suspicious comparison of '\\0' with a char\\* variable\n"
413
0
               "- duplicate break statement\n"
414
0
               "- unreachable code\n"
415
0
               "- testing if unsigned variable is negative/positive\n"
416
0
               "- Suspicious use of ; at the end of 'if/for/while' statement.\n"
417
0
               "- Array filled incompletely using memset/memcpy/memmove.\n"
418
0
               "- NaN (not a number) value used in arithmetic expression.\n"
419
0
               "- comma in return statement (the comma can easily be misread as a semicolon).\n"
420
0
               "- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
421
0
               "- identical code in both branches of if/else or ternary operator.\n"
422
0
               "- redundant pointer operation on pointer like &\\*some_ptr.\n"
423
0
               "- find unused 'goto' labels.\n"
424
0
               "- function declaration and definition argument names different.\n"
425
0
               "- function declaration and definition argument order different.\n"
426
0
               "- shadow variable.\n"
427
0
               "- variable can be declared const.\n"
428
0
               "- calculating modulo of one.\n"
429
0
               "- known function argument, suspicious calculation.\n";
430
0
    }
431
};
432
/// @}
433
//---------------------------------------------------------------------------
434
#endif // checkotherH