summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/test
diff options
context:
space:
mode:
authorJonas Toth <jonas.toth@gmail.com>2018-11-12 16:01:39 +0000
committerJonas Toth <jonas.toth@gmail.com>2018-11-12 16:01:39 +0000
commit6b3d33e99677aa80fa2a899902323b0e6c7e3762 (patch)
treec5d634d2bc085fff265a388065e753a34e7f0330 /clang-tools-extra/test
parentf4cd292ba25d7e286df41475328cd785ff97726f (diff)
downloadbcm5719-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.cpp251
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
+ }
+}
OpenPOWER on IntegriCloud