diff options
author | Jonas Toth <jonas.toth@gmail.com> | 2018-11-12 16:01:39 +0000 |
---|---|---|
committer | Jonas Toth <jonas.toth@gmail.com> | 2018-11-12 16:01:39 +0000 |
commit | 6b3d33e99677aa80fa2a899902323b0e6c7e3762 (patch) | |
tree | c5d634d2bc085fff265a388065e753a34e7f0330 /clang-tools-extra/test | |
parent | f4cd292ba25d7e286df41475328cd785ff97726f (diff) | |
download | bcm5719-llvm-6b3d33e99677aa80fa2a899902323b0e6c7e3762.tar.gz bcm5719-llvm-6b3d33e99677aa80fa2a899902323b0e6c7e3762.zip |
[clang-tidy] new check: bugprone-too-small-loop-variable
The new checker searches for those for loops which has a loop variable with a "too small" type which means this type can't represent all values which are part of the iteration range.
For example:
```
int main() {
long size = 300000;
for( short int i = 0; i < size; ++i) {}
}
```
The short type leads to infinite loop here because it can't store all values in the `[0..size]` interval. In a real use case, size means a container's size which depends on the user input. Which means for small amount of objects the algorithm works, but with a larger user input the software will freeze.
The idea of the checker comes from the LibreOffice project, where the same check was implemented as a clang compiler plugin, called `LoopVarTooSmall` (LLVM licensed).
The idea is the same behind this check, but the code is different because of the different framework.
Patch by ztamas.
Reviewers: alexfh, hokein, aaron.ballman, JonasToth, xazax.hun, whisperity
Reviewed By: JonasToth, whisperity
Differential Revision: https://reviews.llvm.org/D53974
llvm-svn: 346665
Diffstat (limited to 'clang-tools-extra/test')
-rw-r--r-- | clang-tools-extra/test/clang-tidy/bugprone-too-small-loop-variable.cpp | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/clang-tools-extra/test/clang-tidy/bugprone-too-small-loop-variable.cpp b/clang-tools-extra/test/clang-tidy/bugprone-too-small-loop-variable.cpp new file mode 100644 index 00000000000..ab32a12d023 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/bugprone-too-small-loop-variable.cpp @@ -0,0 +1,251 @@ +// RUN: %check_clang_tidy %s bugprone-too-small-loop-variable %t + +long size() { return 294967296l; } + +//////////////////////////////////////////////////////////////////////////////// +/// Test cases correctly caught by bugprone-too-small-loop-variable. + +void voidBadForLoop() { + for (int i = 0; i < size(); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidBadForLoop2() { + for (int i = 0; i < size() + 10; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidBadForLoop3() { + for (int i = 0; i <= size() - 1; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidBadForLoop4() { + for (int i = 0; size() > i; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidBadForLoop5() { + for (int i = 0; size() - 1 >= i; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidBadForLoop6() { + int i = 0; + for (; i < size(); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: loop variable has narrower type 'int' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidForLoopUnsignedBound() { + unsigned size = 3147483647; + for (int i = 0; i < size; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: loop variable has narrower type 'int' than iteration's upper bound 'unsigned int' [bugprone-too-small-loop-variable] + } +} + +// The iteration's upper bound has a template dependent value. +template <long size> +void doSomething() { + for (short i = 0; i < size; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +// The iteration's upper bound has a template dependent type. +template <class T> +void doSomething() { + for (T i = 0; i < size(); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +void voidForLoopInstantiation() { + // This line does not trigger the warning. + doSomething<long>(); + // This one triggers the warning. + doSomething<short>(); +} + +// A suspicious function used in a macro. +#define SUSPICIOUS_SIZE (size()) +void voidBadForLoopWithMacroBound() { + for (short i = 0; i < SUSPICIOUS_SIZE; ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'long' [bugprone-too-small-loop-variable] + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Correct loops: we should not warn here. + +// A simple use case when both expressions have the same type. +void voidGoodForLoop() { + for (long i = 0; i < size(); ++i) { // no warning + } +} + +// Other use case where both expressions have the same type, +// but short expressions are converted to int by the compare operator. +void voidGoodForLoop2() { + short loopCond = 10; + for (short i = 0; i < loopCond; ++i) { // no warning + } +} + +// Because of the integer literal, the iteration's upper bound is int, but we suppress the warning here. +void voidForLoopShortPlusLiteral() { + short size = 30000; + for (short i = 0; i <= (size - 1); ++i) { // no warning + } +} + +// Addition of two short variables results in an int value, but we suppress this to avoid false positives. +void voidForLoopShortPlusShort() { + short size = 256; + short increment = 14; + for (short i = 0; i < size + increment; ++i) { // no warning + } +} + +// In this test case we have different integer types, but here the loop variable has the bigger type. +// The iteration's bound is cast implicitly, not the loop variable. +void voidForLoopBoundImplicitCast() { + short start = 256; + short end = 14; + for (int i = start; i >= end; --i) { // no warning + } +} + +// Range based loop and other iterator based loops are ignored by this check. +void voidRangeBasedForLoop() { + int array[] = {1, 2, 3, 4, 5}; + for (const int &i : array) { // no warning + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Future possibilites to improve the check. + +// False positive: because of the int literal, iteration's upper bound has int type. +void voidForLoopFalsePositive() { + short size = 30000; + bool cond = false; + for (short i = 0; i < (cond ? 0 : size); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] + } +} + +void voidForLoopFalsePositive2() { + short size = 30000; + bool cond = false; + for (short i = 0; i < (!cond ? size : 0); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] + } +} + +// False positive: The loop bound expression contains nested binary operators. +void voidForLoopFalsePositive3() { + short number = 30000; + for (short i = 0; i < ((number & 0x7f) + 1); ++i) { + // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: loop variable has narrower type 'short' than iteration's upper bound 'int' [bugprone-too-small-loop-variable] + } +} + +// TODO: handle while loop. +void voidBadWhileLoop() { + short i = 0; + while (i < size()) { // missing warning + ++i; + } +} + +// TODO: handle do-while loop. +void voidBadDoWhileLoop() { + short i = 0; + do { + ++i; + } while (i < size()); // missing warning +} + +// TODO: handle complex loop conditions. +void voidComplexForCond() { + bool additionalCond = true; + for (int i = 0; i < size() && additionalCond; ++i) { // missing warning + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// Suspicious test cases ingored by this check. + +// Test case with a reverse iteration. +// This is caught by -Wimplicit-int-conversion. +void voidReverseForLoop() { + for (short i = size() - 1; i >= 0; --i) { // no warning + } +} + +// Macro defined literals are used inside the loop condition. +#define SIZE 125 +#define SIZE2 (SIZE + 1) +void voidForLoopWithMacroBound() { + for (short i = 0; i < SIZE2; ++i) { // no warning + } +} + +// A suspicious loop is not caught if the iteration's upper bound is a literal. +void voidForLoopWithLiteralBound() { + for (short i = 0; i < 125; ++i) { // no warning + } +} + +// The used literal leads to an infinite loop. +// This is caught by -Wtautological-constant-out-of-range-compare. +void voidForLoopWithBigLiteralBound() { + for (short i = 0; i < 294967296l; ++i) { // no warning + } +} + +enum eSizeType { + START, + Y, + END +}; + +// A suspicious loop is not caught if the iteration's upper bound is an enum value. +void voidForLoopWithEnumBound() { + for (short i = eSizeType::START; i < eSizeType::END; ++i) { // no warning + } +} + +enum eSizeType2 : long { + START2 = 294967296l, + Y2, + END2 +}; + +// The used enum value leads to an infinite loop. +// This is caught by -Wtautological-constant-out-of-range-compare. +void voidForLoopWithBigEnumBound() { + for (short i = eSizeType2::START2; i < eSizeType2::END2; ++i) { // no warning + } +} + +// A suspicious loop is not caught if the iteration's upper bound is a constant variable. +void voidForLoopWithConstBound() { + const long size = 252l; + for (short i = 0; i < size; ++i) { // no warning + } +} + +// The used constant variable leads to an infinite loop. +// This is caught by -Wtautological-constant-out-of-range-compare. +void voidForLoopWithBigConstBound() { + const long size = 294967296l; + for (short i = 0; i < size; ++i) { // no warning + } +} |