diff --git a/lib/astutils.cpp b/lib/astutils.cpp index 96a9232ef..2eaf3d932 100644 --- a/lib/astutils.cpp +++ b/lib/astutils.cpp @@ -2324,6 +2324,21 @@ const Variable *getLHSVariable(const Token *tok) return getLHSVariableRecursive(tok->astOperand1()); } +const Token* findAllocFuncCallToken(const Token *expr, const Library &library) +{ + if (!expr) + return nullptr; + if (Token::Match(expr, "[+-]")) { + const Token *tok1 = findAllocFuncCallToken(expr->astOperand1(), library); + return tok1 ? tok1 : findAllocFuncCallToken(expr->astOperand2(), library); + } + if (expr->isCast()) + return findAllocFuncCallToken(expr->astOperand2() ? expr->astOperand2() : expr->astOperand1(), library); + if (Token::Match(expr->previous(), "%name% (") && library.getAllocFuncInfo(expr->astOperand1())) + return expr->astOperand1(); + return (Token::simpleMatch(expr, "new") && expr->astOperand1()) ? expr : nullptr; +} + static bool nonLocal(const Variable* var, bool deref) { return !var || (!var->isLocal() && !var->isArgument()) || (deref && var->isArgument() && var->isPointer()) || var->isStatic() || var->isReference() || var->isExtern(); diff --git a/lib/astutils.h b/lib/astutils.h index 6c1be1eea..6b39d5930 100644 --- a/lib/astutils.h +++ b/lib/astutils.h @@ -281,6 +281,9 @@ const Variable *getLHSVariable(const Token *tok); std::vector getLHSVariables(const Token* tok); +/** Find a allocation function call in expression, so result of expression is allocated memory/resource. */ +const Token* findAllocFuncCallToken(const Token *expr, const Library &library); + bool isScopeBracket(const Token* tok); bool isNullOperand(const Token *expr); diff --git a/lib/checkuninitvar.cpp b/lib/checkuninitvar.cpp index 3bdd18450..66e72040f 100644 --- a/lib/checkuninitvar.cpp +++ b/lib/checkuninitvar.cpp @@ -171,9 +171,12 @@ void CheckUninitVar::checkScope(const Scope* scope, const std::set if (arg.declarationId() && Token::Match(arg.typeStartToken(), "%type% * %name% [,)]")) { // Treat the pointer as initialized until it is assigned by malloc for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) { - if (!Token::Match(tok, "[;{}] %varid% = %name% (", arg.declarationId())) + if (!Token::Match(tok, "[;{}] %varid% =", arg.declarationId())) continue; - const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(tok->tokAt(3)); + const Token *allocFuncCallToken = findAllocFuncCallToken(tok->tokAt(2)->astOperand2(), mSettings->library); + if (!allocFuncCallToken) + continue; + const Library::AllocFunc *allocFunc = mSettings->library.getAllocFuncInfo(allocFuncCallToken); if (!allocFunc || allocFunc->initData) continue; diff --git a/lib/checkunusedvar.cpp b/lib/checkunusedvar.cpp index fe37e477f..8ba6b4770 100644 --- a/lib/checkunusedvar.cpp +++ b/lib/checkunusedvar.cpp @@ -938,11 +938,14 @@ void CheckUnusedVar::checkFunctionVariableUsage_iterateScopes(const Scope* const } // Consider allocating memory separately because allocating/freeing alone does not constitute using the variable else if (var && var->mType == Variables::pointer && - Token::Match(start, "%name% = new|malloc|calloc|kmalloc|kzalloc|kcalloc|strdup|strndup|vmalloc|g_new0|g_try_new|g_new|g_malloc|g_malloc0|g_try_malloc|g_try_malloc0|g_strdup|g_strndup|g_strdup_printf")) { + Token::Match(start, "%name% =") && + findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library)) { bool allocate = true; - if (start->strAt(2) == "new") { - const Token *type = start->tokAt(3); + const Token *allocFuncCallToken = findAllocFuncCallToken(start->next()->astOperand2(), mSettings->library); + + if (allocFuncCallToken->str() == "new") { + const Token *type = allocFuncCallToken->next(); // skip nothrow if (mTokenizer->isCPP() && (Token::simpleMatch(type, "( nothrow )") || diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index f01fb0d95..3a0b3819a 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -1013,6 +1013,7 @@ private: void array_index_30() { // ticket #2086 - unknown type + // extracttests.start: typedef unsigned char UINT8; check("void f() {\n" " UINT8 x[2];\n" " x[5] = 0;\n" @@ -1245,7 +1246,7 @@ private: check("void f()\n" "{\n" - " char *p; p = malloc(10);\n" + " char *p; p = (char *)malloc(10);\n" " p[10] = 7;\n" " free(p);\n" "}"); @@ -1253,7 +1254,7 @@ private: check("void f()\n" "{\n" - " char *p; p = malloc(10);\n" + " char *p; p = (char *)malloc(10);\n" " p[0] = 0;\n" " p[9] = 9;\n" " free(p);\n" @@ -1880,6 +1881,8 @@ private: } void array_index_for_andand_oror() { // #3907 - using && or || + // extracttests.start: volatile int y; + check("void f() {\n" " char data[2];\n" " int x;\n" @@ -1930,10 +1933,11 @@ private: "}", true); ASSERT_EQUALS("", errout.str()); + // extracttests.start: int maybe(); check("void f() {\n" " int a[2];\n" " for (int i = 0; i < 2; ++i) {\n" - " if (somecondition) {\n" + " if (maybe()) {\n" " continue;\n" " }\n" " a[i - 1] = 0;\n" @@ -1967,9 +1971,10 @@ private: ASSERT_EQUALS("", errout.str()); // Ticket #3893 - start value out of bounds + // extracttests.start: int maybe(); int dostuff(); check("void f() {\n" " int a[10];\n" - " for (int i = 10; somecondition; dosomething) {\n" + " for (int i = 10; maybe(); dostuff()) {\n" " a[i] = 0;\n" " }\n" "}"); @@ -2748,21 +2753,21 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str()); - check("void f(float a[10][20]);\n" + check("void f(float a[10][3]);\n" "void g() {\n" " float a[2][3];\n" " f(a);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str()); - check("void f(char a[20]);\n" + check("void f(int a[20]);\n" "void g() {\n" " int a[2];\n" " f(a);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (warning) The array 'a' is too small, the function 'f' expects a bigger one.\n", errout.str()); - check("void f(char a[20]);\n" + check("void f(int a[20]);\n" "void g() {\n" " int a[5];\n" " f(a);\n" @@ -2791,7 +2796,7 @@ private: void possible_buffer_overrun_1() { // #3035 check("void foo() {\n" - " char * data = alloca(50);\n" + " char * data = (char *)alloca(50);\n" " char src[100];\n" " memset(src, 'C', 99);\n" " src[99] = '\\0';\n" @@ -2800,7 +2805,7 @@ private: ASSERT_EQUALS("[test.cpp:6]: (warning) Possible buffer overflow if strlen(src) is larger than sizeof(data)-strlen(data).\n", errout.str()); check("void foo() {\n" - " char * data = alloca(100);\n" + " char * data = (char *)alloca(100);\n" " char src[100];\n" " memset(src, 'C', 99);\n" " src[99] = '\\0';\n" @@ -2809,19 +2814,19 @@ private: ASSERT_EQUALS("", errout.str()); check("void foo(char src[100]) {\n" - " char * data = alloca(50);\n" + " char * data = (char *)alloca(50);\n" " strcat(data, src);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (warning) Possible buffer overflow if strlen(src) is larger than sizeof(data)-strlen(data).\n", errout.str()); check("void foo(char src[100]) {\n" - " char * data = alloca(100);\n" + " char * data = (char *)alloca(100);\n" " strcat(data, src);\n" "}"); ASSERT_EQUALS("", errout.str()); check("void foo() {\n" - " char * data = alloca(50);\n" + " char * data = (char *)alloca(50);\n" " char src[100];\n" " memset(src, 'C', 99);\n" " src[99] = '\\0';\n" @@ -2830,7 +2835,7 @@ private: ASSERT_EQUALS("[test.cpp:6]: (warning) Possible buffer overflow if strlen(src) is larger than or equal to sizeof(data).\n", errout.str()); check("void foo() {\n" - " char * data = alloca(100);\n" + " char * data = (char *)alloca(100);\n" " char src[100];\n" " memset(src, 'C', 99);\n" " src[99] = '\\0';\n" @@ -2839,13 +2844,13 @@ private: ASSERT_EQUALS("", errout.str()); check("void foo(char src[100]) {\n" - " char * data = alloca(50);\n" + " char * data = (char *)alloca(50);\n" " strcpy(data, src);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (warning) Possible buffer overflow if strlen(src) is larger than or equal to sizeof(data).\n", errout.str()); check("void foo(char src[100]) {\n" - " char * data = alloca(100);\n" + " char * data = (char *)alloca(100);\n" " strcpy(data, src);\n" "}"); ASSERT_EQUALS("", errout.str()); @@ -2905,13 +2910,15 @@ private: } void pointer_out_of_bounds_1() { + // extracttests.start: void dostuff(char *); + check("void f() {\n" " char a[10];\n" " char *p = a + 100;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour, pointer arithmetic 'a+100' is out of bounds.\n", errout.str()); - check("void f() {\n" + check("char *f() {\n" " char a[10];\n" " return a + 100;\n" "}"); @@ -2983,7 +2990,7 @@ private: void pointer_out_of_bounds_3() { check("struct S { int a[10]; };\n" "void f(struct S *s) {\n" - " char *p = s->a + 100;\n" + " int *p = s->a + 100;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour, pointer arithmetic 's->a+100' is out of bounds.\n", errout.str()); } @@ -3012,7 +3019,9 @@ private: void pointer_out_of_bounds_sub() { - check("void f() {\n" + // extracttests.start: void dostuff(char *); + + check("char *f() {\n" " char x[10];\n" " return x-1;\n" "}"); @@ -3129,7 +3138,7 @@ private: // ticket #1670 - false negative when using return check("char f()\n" "{\n" - " char *s; s = new int[10];\n" + " int *s; s = new int[10];\n" " return s[10];\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 's[10]' accessed at index 10, which is out of bounds.\n", errout.str()); @@ -3177,9 +3186,9 @@ private: check("void foo()\n" "{\n" - " enum E { };\n" + " enum E { ZERO };\n" " E *e; e = new E[10];\n" - " e[10] = 0;\n" + " e[10] = ZERO;\n" "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Array 'e[10]' accessed at index 10, which is out of bounds.\n", errout.str()); } @@ -3188,23 +3197,23 @@ private: void alloc_malloc() { check("void foo()\n" "{\n" - " char *s; s = malloc(10);\n" + " char *s; s = (char *)malloc(10);\n" " s[10] = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 's[10]' accessed at index 10, which is out of bounds.\n", errout.str()); // ticket #842 check("void f() {\n" - " int *tab4 = malloc(20 * sizeof(int));\n" + " int *tab4 = (int *)malloc(20 * sizeof(int));\n" " tab4[20] = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Array 'tab4[20]' accessed at index 20, which is out of bounds.\n", errout.str()); // ticket #1478 check("void foo() {\n" - " char *p = malloc(10);\n" + " char *p = (char *)malloc(10);\n" " free(p);\n" - " p = malloc(10);\n" + " p = (char *)malloc(10);\n" " p[10] = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Array 'p[10]' accessed at index 10, which is out of bounds.\n", errout.str()); @@ -3212,7 +3221,7 @@ private: // ticket #1134 check("void f() {\n" " int *x, i;\n" - " x = malloc(10 * sizeof(int));\n" + " x = (int *)malloc(10 * sizeof(int));\n" " x[10] = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'x[10]' accessed at index 10, which is out of bounds.\n", errout.str()); @@ -3238,22 +3247,22 @@ private: check("void f() {\n" " enum E { Size = 20 };\n" - " E *tab4 = malloc(Size * 4);\n" - " tab4[Size] = 0;\n" + " E *tab4 = (E *)malloc(Size * 4);\n" + " tab4[Size] = Size;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'tab4[20]' accessed at index 20, which is out of bounds.\n", errout.str()); check("void f() {\n" " enum E { Size = 20 };\n" - " E *tab4 = malloc(4 * Size);\n" - " tab4[Size] = 0;\n" + " E *tab4 = (E *)malloc(4 * Size);\n" + " tab4[Size] = Size;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'tab4[20]' accessed at index 20, which is out of bounds.\n", errout.str()); check("void f() {\n" - " enum E { };\n" - " E *tab4 = malloc(20 * sizeof(E));\n" - " tab4[20] = 0;\n" + " enum E { ZERO };\n" + " E *tab4 = (E *)malloc(20 * sizeof(E));\n" + " tab4[20] = ZERO;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 'tab4[20]' accessed at index 20, which is out of bounds.\n", errout.str()); @@ -3301,7 +3310,7 @@ private: void alloc_alloca() { check("void foo()\n" "{\n" - " char *s = alloca(10);\n" + " char *s = (char *)alloca(10);\n" " s[10] = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Array 's[10]' accessed at index 10, which is out of bounds.\n", errout.str()); @@ -3378,6 +3387,9 @@ private: ASSERT_EQUALS(26, CheckBufferOverrun::countSprintfLength("str%-6s%08ld%08ld", multipleParams)); } */ + + // extracttests.disable + void minsize_argvalue() { Settings settings; const char xmldata[] = "\n" @@ -3717,6 +3729,8 @@ private: ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: c\n", errout.str()); } + // extracttests.enable + void unknownType() { check("void f()\n" "{\n" @@ -3770,7 +3784,7 @@ private: " char baz[100];\n" " strncpy(baz, bar, 100);\n" " bar[99] = 0;\n" - " return baz;\n" + " return strdup(baz);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (warning, inconclusive) The buffer 'baz' may not be null-terminated after the call to strncpy().\n", errout.str()); } @@ -4095,20 +4109,20 @@ private: ASSERT_EQUALS("", errout.str()); check("void f(char *a) {\n" - " char *b = malloc(strlen(a));\n" + " char *b = (char *)malloc(strlen(a));\n" " b = realloc(b, 10000);\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("", errout.str()); check("void f(char *a) {\n" - " char *b = malloc(strlen(a));\n" + " char *b = (char *)malloc(strlen(a));\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", errout.str()); check("void f(char *a) {\n" - " char *b = malloc(strlen(a));\n" + " char *b = (char *)malloc(strlen(a));\n" " {\n" " strcpy(b, a);\n" " }\n" @@ -4116,25 +4130,25 @@ private: ASSERT_EQUALS("[test.cpp:4]: (error) Buffer is accessed out of bounds.\n", errout.str()); check("void f(char *a) {\n" - " char *b = malloc(strlen(a) + 1);\n" + " char *b = (char *)malloc(strlen(a) + 1);\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("", errout.str()); check("void f(char *a, char *c) {\n" - " char *b = realloc(c, strlen(a));\n" + " char *b = (char *)realloc(c, strlen(a));\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", errout.str()); check("void f(char *a, char *c) {\n" - " char *b = realloc(c, strlen(a) + 1);\n" + " char *b = (char *)realloc(c, strlen(a) + 1);\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("", errout.str()); check("void f(char *a) {\n" - " char *b = malloc(strlen(a));\n" + " char *b = (char *)malloc(strlen(a));\n" " strcpy(b, a);\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds.\n", errout.str()); @@ -4144,7 +4158,7 @@ private: check("class A {\n" "private:\n" " struct X { char buf[10]; };\n" - "}\n" + "};\n" "\n" "void f()\n" "{\n" @@ -4156,7 +4170,7 @@ private: check("class A {\n" "public:\n" " struct X { char buf[10]; };\n" - "}\n" + "};\n" "\n" "void f()\n" "{\n" @@ -4173,6 +4187,8 @@ private: } void arrayIndexThenCheck() { + // extracttests.start: volatile int y; + check("void f(const char s[]) {\n" " if (s[i] == 'x' && i < y) {\n" " }" @@ -4203,12 +4219,14 @@ private: "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Array index 'i' is used before limits check.\n", errout.str()); + // extracttests.start: int elen; check("void f(char* e, int y) {\n" " if (e[y] == '/' && elen > y + 1 && e[y + 1] == '?') {\n" " }\n" "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: int foo(int); int func(int); check("void f(const int a[], unsigned i) {\n" " if(a[i] < func(i) && i <= 42) {\n" " }\n" @@ -4232,6 +4250,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: extern int buf[]; check("void f(int i) {\n" // ?: " if ((i < 10 ? buf[i] : 1) && (i < 5 ? buf[i] : 5)){}\n" "}"); @@ -4262,15 +4281,7 @@ private: check("void f()\n" "{\n" " int *a;\n" - " a = new int[-1];\n" - " delete [] a;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str()); - - check("void f()\n" - "{\n" - " int *a;\n" - " a = malloc( -10 );\n" + " a = (int *)malloc( -10 );\n" " free(a);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str()); @@ -4278,7 +4289,7 @@ private: check("void f()\n" "{\n" " int *a;\n" - " a = malloc( -10);\n" + " a = (int *)malloc( -10);\n" " free(a);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str()); @@ -4286,7 +4297,7 @@ private: check("void f()\n" "{\n" " int *a;\n" - " a = alloca( -10 );\n" + " a = (int *)alloca( -10 );\n" " free(a);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory allocation size is negative.\n", errout.str()); @@ -4310,7 +4321,7 @@ private: void pointerAddition1() { check("void f() {\n" " char arr[10];\n" - " p = arr + 20;\n" + " char *p = arr + 20;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (portability) Undefined behaviour, pointer arithmetic 'arr+20' is out of bounds.\n", errout.str()); } diff --git a/test/testnullpointer.cpp b/test/testnullpointer.cpp index e8c40e4bc..38182b9ba 100644 --- a/test/testnullpointer.cpp +++ b/test/testnullpointer.cpp @@ -191,7 +191,8 @@ private: void nullpointerAfterLoop() { - check("int foo(const Token *tok)\n" + // extracttests.start: struct Token { const Token *next() const; std::string str() const; }; + check("void foo(const Token *tok)\n" "{\n" " while (tok);\n" " tok = tok->next();\n" @@ -363,6 +364,8 @@ private: // This is checked by this function: // CheckOther::nullPointerStructByDeRefAndChec void structDerefAndCheck() { + // extracttests.start: struct ABC { int a; int b; int x; }; + // errors.. check("void foo(struct ABC *abc)\n" "{\n" @@ -622,6 +625,8 @@ private: // Dereferencing a pointer and then checking if it is null void pointerDerefAndCheck() { + // extracttests.start: void bar(int); + // errors.. check("void foo(int *p)\n" "{\n" @@ -992,14 +997,14 @@ private: "", errout.str()); check("static void foo() {\n" - " int &r = *0;\n" + " int &r = *(int*)0;\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference: (int*)0\n", errout.str()); check("static void foo(int x) {\n" - " int y = 5 + *0;\n" + " int y = 5 + *(int*)0;\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference: (int*)0\n", errout.str()); { const char code[] = "static void foo() {\n" @@ -1012,9 +1017,9 @@ private: } check("static void foo() {\n" - " std::cout << *0;" + " std::cout << *(int*)0;" "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference: (int*)0\n", errout.str()); check("void f()\n" "{\n" @@ -1027,9 +1032,9 @@ private: ASSERT_EQUALS("[test.cpp:7]: (error) Null pointer dereference: c\n", errout.str()); check("static void foo() {\n" - " if (3 > *0);\n" + " if (3 > *(int*)0);\n" "}"); - ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference\n", errout.str()); + ASSERT_EQUALS("[test.cpp:2]: (error) Null pointer dereference: (int*)0\n", errout.str()); // no false positive.. check("static void foo()\n" @@ -1218,12 +1223,13 @@ private: "", errout.str()); // #2231 - error if assignment in loop is not used + // extracttests.start: int y[20]; check("void f() {\n" " char *p = 0;\n" "\n" " for (int x = 0; x < 3; ++x) {\n" " if (y[x] == 0) {\n" - " p = malloc(10);\n" + " p = (char *)malloc(10);\n" " break;\n" " }\n" " }\n" @@ -1252,6 +1258,7 @@ private: } void nullpointer10() { + // extracttests.start: struct my_type { int x; }; check("void foo()\n" "{\n" " struct my_type* p = 0;\n" @@ -1261,6 +1268,8 @@ private: } void nullpointer11() { // ticket #2812 + // extracttests.start: struct my_type { int x; }; + check("int foo()\n" "{\n" " struct my_type* p;\n" @@ -2184,7 +2193,7 @@ private: " const Token* next() const;\n" " int varId() const;\n" "};\n" - "int f(const Token *first, const Token* second) const {\n" + "int f(const Token *first, const Token* second) {\n" " first = first->nextArgument();\n" " if (first)\n" " first = first->next();\n" @@ -2203,8 +2212,9 @@ private: " const Token* nextArgument() const;\n" " const Token* next() const;\n" " int varId() const;\n" + " void str() const;" "};\n" - "int f(const Token *first) const {\n" + "void f(const Token *first) {\n" " first = first->nextArgument();\n" " if (first)\n" " first = first->next();\n" @@ -2246,6 +2256,7 @@ private: } void nullpointerSwitch() { // #2626 + // extracttests.start: char *do_something(); check("char *f(int x) {\n" " char *p = do_something();\n" " switch (x) {\n" @@ -2667,7 +2678,7 @@ private: // Test CheckNullPointer::nullConstantDereference void nullConstantDereference() { - check("void f() {\n" + check("int f() {\n" " int* p = 0;\n" " return p[4];\n" "}"); @@ -2836,9 +2847,10 @@ private: } void nullpointer_in_return() { + // extracttests.start: int maybe(); int *g(); check("int foo() {\n" " int* iVal = 0;\n" - " if(g()) iVal = g();\n" + " if(maybe()) iVal = g();\n" " return iVal[0];\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (warning) Possible null pointer dereference: iVal\n", errout.str()); @@ -3130,6 +3142,8 @@ private: } void nullpointerSmartPointer() { + // extracttests.start: void dostuff(int); + check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" " if (p) {}\n" @@ -3190,7 +3204,7 @@ private: check("struct Fred { int x; };\n" "void f(std::shared_ptr p) {\n" - " p.release();\n" + " p.reset();\n" " dostuff(p->x);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Null pointer dereference: p\n", errout.str()); @@ -3547,7 +3561,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - check("void foo(int *p = 0) {\n" + check("void foo(int x, int *p = 0) {\n" " int var1 = x ? *p : 5;\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (warning) Possible null pointer dereference if the default parameter value is used: p\n", errout.str()); @@ -3582,7 +3596,7 @@ private: void subtract() { check("void foo(char *s) {\n" - " p = s - 20;\n" + " char *p = s - 20;\n" "}\n" "void bar() { foo(0); }"); ASSERT_EQUALS("[test.cpp:2]: (error) Overflow in pointer arithmetic, NULL pointer is subtracted.\n", @@ -3590,7 +3604,7 @@ private: check("void foo(char *s) {\n" " if (!s) {}\n" - " p = s - 20;\n" + " char *p = s - 20;\n" "}"); ASSERT_EQUALS("[test.cpp:2] -> [test.cpp:3]: (warning) Either the condition '!s' is redundant or there is overflow in pointer subtraction.\n", errout.str()); diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index b93f2f30e..6e6e2cd02 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -113,6 +113,8 @@ private: } void uninitvar1() { + // extracttests.start: int b; int c; + // Ticket #2207 - False negative checkUninitVar("void foo() {\n" " int a;\n" @@ -127,11 +129,13 @@ private: ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); // Ticket #6455 - some compilers allow const variables to be uninitialized + // extracttests.disable checkUninitVar("void foo() {\n" " const int a;\n" " b = c - a;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + // extracttests.enable checkUninitVar("void foo() {\n" " int *p;\n" @@ -153,6 +157,7 @@ private: ASSERT_EQUALS("", errout.str()); // dereferencing uninitialized pointer.. + // extracttests.start: struct Foo { void abcd(); }; checkUninitVar("static void foo()\n" "{\n" " Foo *p;\n" @@ -160,6 +165,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str()); + // extracttests.start: template struct Foo { void abcd(); }; checkUninitVar("static void foo()\n" "{\n" " Foo *p;\n" @@ -167,6 +173,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: p\n", errout.str()); + // extracttests.start: struct Foo { void* a; }; checkUninitVar("void f(Foo *p)\n" "{\n" " int a;\n" @@ -257,6 +264,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: void bar(int); checkUninitVar("void f()\n" "{\n" " int a;\n" @@ -285,7 +293,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: i\n", errout.str()); - checkUninitVar("static int foo(int x)\n" + checkUninitVar("static void foo(int x)\n" "{\n" " int i;\n" " if (x)\n" @@ -317,7 +325,7 @@ private: ASSERT_EQUALS("", errout.str()); // Ticket #3597 - checkUninitVar("int f() {\n" + checkUninitVar("void f() {\n" " int a;\n" " int b = 1;\n" " (b += a) = 1;\n" @@ -345,6 +353,7 @@ private: ASSERT_EQUALS("", errout.str()); // Unknown types + // extracttests.disable { checkUninitVar("void a()\n" "{\n" @@ -369,6 +378,7 @@ private: "test.c", false); ASSERT_EQUALS("", errout.str()); } + // extracttests.enable checkUninitVar("void a()\n" "{\n" @@ -730,6 +740,8 @@ private: } void uninitvar_warn_once() { + // extracttests.start: int a; int b; + checkUninitVar("void f() {\n" " int x;\n" " a = x;\n" @@ -817,6 +829,8 @@ private: } void uninitvar_bitop() { + // extracttests.start: int a; int c; + checkUninitVar("void foo() {\n" " int b;\n" " c = a | b;\n" @@ -832,7 +846,8 @@ private: // if.. void uninitvar_if() { - checkUninitVar("static void foo()\n" + // extracttests.start: struct Foo { void abcd(); }; + checkUninitVar("static void foo(int x)\n" "{\n" " Foo *p;\n" " if (x)\n" @@ -1148,6 +1163,7 @@ private: // handling for/while loops.. void uninitvar_loops() { // for.. + // extracttests.start: void b(int); checkUninitVar("void f()\n" "{\n" " for (int i = 0; i < 4; ++i) {\n" @@ -1211,7 +1227,8 @@ private: " }\n" "}"); ASSERT_EQUALS("", errout.str()); - checkUninitVar("void f(int x) {\n" + // extracttests.start: struct PoolItem { bool operator!=(const PoolItem&) const; }; + checkUninitVar("void f(int x, const PoolItem& rPool) {\n" " const PoolItem* pItem;\n" " while (x > 0) {\n" " if (*pItem != rPool)\n" @@ -1257,6 +1274,7 @@ private: ASSERT_EQUALS("", errout.str()); // #10273 - assignment in conditional code + // extracttests.start: extern const int PORT_LEARN_DISABLE; checkUninitVar("void foo() {\n" " int learn;\n" " for (int index = 0; index < 10; index++) {\n" @@ -1394,7 +1412,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - checkUninitVar("void f() {\n" + checkUninitVar("void f(int x) {\n" " char a[10], c;\n" " c = *(x?a:0);\n" "}"); @@ -1420,7 +1438,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - checkUninitVar("void f() {\n" + checkUninitVar("void f(char *s2) {\n" " char s[20];\n" " strcpy(s2, s);\n" "};"); @@ -1614,7 +1632,7 @@ private: // alloc.. void uninitvar_alloc() { checkUninitVar("void f() {\n" - " char *s = malloc(100);\n" + " char *s = (char *)malloc(100);\n" " strcat(s, \"abc\");\n" "};"); ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: s\n", errout.str()); @@ -1628,19 +1646,19 @@ private: checkUninitVar("void f()\n" "{\n" - " char *p = malloc(64);\n" + " char *p = (char*)malloc(64);\n" " int x = p[0];\n" "}"); TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Memory is allocated but not initialized: p\n", "", errout.str()); checkUninitVar("void f() {\n" - " char *p = malloc(64);\n" + " char *p = (char*)malloc(64);\n" " if (p[0]) { }\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str()); - checkUninitVar("void f() {\n" - " char *p = malloc(64);\n" + checkUninitVar("char f() {\n" + " char *p = (char*)malloc(64);\n" " return p[0];\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str()); @@ -1725,7 +1743,7 @@ private: checkUninitVar("void f()\n" "{\n" - " char *s = malloc(100);\n" + " char *s = (char*)malloc(100);\n" " if (!s)\n" " return;\n" " char c = *s;\n" @@ -2181,6 +2199,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str()); + // extracttests.start: char str[10]; checkUninitVar("void f() {\n" " int x;\n" " str[x] = 0;\n" @@ -2205,12 +2224,13 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str()); - checkUninitVar("int f() {\n" + checkUninitVar("void f() {\n" " int x;\n" " x = x;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: x\n", errout.str()); + // extracttests.start: struct ABC {int a;}; checkUninitVar("void f() {\n" " struct ABC *abc;\n" " abc->a = 0;\n" @@ -2813,6 +2833,8 @@ private: } void uninitvar_funcptr() { + // extracttests.disable + checkUninitVar("void getLibraryContainer() {\n" " Reference< XStorageBasedLibraryContainer >(*Factory)(const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&)\n" " = &DocumentDialogLibraryContainer::create;\n" @@ -2832,6 +2854,8 @@ private: " rxContainer.set((*Factory)(m_aContext, xDocument));\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: Factory\n", errout.str()); + + // extracttests.enable } void uninitvar_operator() { // Ticket #6463, #6680 @@ -2912,10 +2936,10 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c\n", errout.str()); - checkUninitVar("void a(const char c);\n" // const value => error + checkUninitVar("void a(const char *c);\n" // const value => error "void b() {\n" " char c;\n" - " a(*c);\n" + " a(&c);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: c\n", errout.str()); @@ -3014,6 +3038,7 @@ private: ASSERT_EQUALS("[test.c:3]: (error) Uninitialized variable: now0\n", errout.str()); // #2775 - uninitialized struct pointer in subfunction + // extracttests.start: struct Fred {int x;}; checkUninitVar("void a(struct Fred *fred) {\n" " fred->x = 0;\n" "}\n" @@ -3111,10 +3136,11 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: int y; checkUninitVar("int f(int x) {\n" // FP with ?: " int a;\n" " if (x)\n" - " a = p;\n" + " a = y;\n" " return x ? 2*a : 0;\n" "}"); ASSERT_EQUALS("", errout.str()); @@ -3122,7 +3148,7 @@ private: checkUninitVar("int f(int x) {\n" " int a;\n" " if (x)\n" - " a = p;\n" + " a = y;\n" " return y ? 2*a : 3*a;\n" "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: a\n", errout.str()); @@ -3253,7 +3279,7 @@ private: "}\n", "test.c"); ASSERT_EQUALS("", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " static void f() { }\n" "};\n" "void test() {\n" @@ -3261,7 +3287,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " static void f() { }\n" "};\n" "void test() {\n" @@ -3269,7 +3295,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " static int v;\n" "};\n" "void test() {\n" @@ -3277,7 +3303,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " static int v;\n" "};\n" "void test() {\n" @@ -3285,7 +3311,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " void f() { }\n" "};\n" "void test() {\n" @@ -3293,7 +3319,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " void f() { }\n" "};\n" "void test() {\n" @@ -3301,7 +3327,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " int v;\n" "};\n" "void test() {\n" @@ -3309,7 +3335,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized variable: element\n", errout.str()); - checkUninitVar("class Element {\n" + checkUninitVar("struct Element {\n" " int v;\n" "};\n" "void test() {\n" @@ -3688,6 +3714,8 @@ private: } void uninitvar2_while() { + // extracttests.start: int a; + // for, while checkUninitVar("void f() {\n" " int x;\n" @@ -3710,11 +3738,13 @@ private: "}"); ASSERT_EQUALS("[test.cpp:2]: (error) Uninitialized variable: x\n", errout.str()); + // extracttests.start: struct Element{Element*Next();}; checkUninitVar("void f() {\n" " for (Element *ptr3 = ptr3->Next(); ptr3; ptr3 = ptr3->Next()) {}\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (error) Uninitialized variable: ptr3\n", errout.str()); + // extracttests.start: int a; checkUninitVar("void f() {\n" " int x;\n" " while (a) {\n" @@ -3785,6 +3815,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: void do_something(int); checkUninitVar("void f(void) {\n" " int x;\n" " for (;;) {\n" @@ -3856,7 +3887,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - checkUninitVar("int f() {\n" + checkUninitVar("void f() {\n" " char *p = (char *)malloc(256);\n" " while(*p && *p == '_')\n" " p++;\n" @@ -3870,6 +3901,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: int a; checkUninitVar("void f() {\n" // No FN " for (int i;;i++)\n" " a=i;\n" @@ -3942,20 +3974,20 @@ private: void uninitvar2_malloc() { checkUninitVar("int f() {\n" - " int *p = malloc(40);\n" + " int *p = (int*)malloc(40);\n" " return *p;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str()); - checkUninitVar("int f() {\n" - " int *p = malloc(40);\n" - " var = *p;\n" + checkUninitVar("void f() {\n" + " int *p = (int*)malloc(40);\n" + " int var = *p;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Memory is allocated but not initialized: p\n", errout.str()); checkUninitVar("struct AB { int a; int b; };\n" "int f() {\n" - " struct AB *ab = malloc(sizeof(struct AB));\n" + " struct AB *ab = (AB*)malloc(sizeof(struct AB));\n" " return ab->a;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory is allocated but not initialized: ab\n" @@ -3992,7 +4024,7 @@ private: // function parameter (treat it as initialized until malloc is used) checkUninitVar("int f(int *p) {\n" " if (*p == 1) {}\n" // no error - " p = malloc(256);\n" + " p = (int*)malloc(256);\n" " return *p;\n" // error "}"); ASSERT_EQUALS("[test.cpp:4]: (error) Memory is allocated but not initialized: p\n", errout.str()); @@ -4000,15 +4032,15 @@ private: checkUninitVar("struct AB { int a; int b; };\n" "int f(struct AB *ab) {\n" " if (ab->a == 1) {}\n" // no error - " ab = malloc(sizeof(struct AB));\n" + " ab = (AB*)malloc(sizeof(struct AB));\n" " return ab->a;\n" // error "}"); ASSERT_EQUALS("[test.cpp:5]: (error) Uninitialized struct member: ab.a\n", errout.str()); checkUninitVar("struct AB { int a; int b; };\n" "void do_something(struct AB *ab);\n" // unknown function - "int f() {\n" - " struct AB *ab = malloc(sizeof(struct AB));\n" + "void f() {\n" + " struct AB *ab = (AB*)malloc(sizeof(struct AB));\n" " do_something(ab);\n" "}"); ASSERT_EQUALS("", errout.str()); @@ -4744,6 +4776,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n", errout.str()); + // extracttests.start: extern const int SIZE; checkUninitVar("void f() {\n" " char a[SIZE+10];\n" " char c = *a;\n" diff --git a/test/testunusedvar.cpp b/test/testunusedvar.cpp index 350135bf9..f5e9c03fd 100644 --- a/test/testunusedvar.cpp +++ b/test/testunusedvar.cpp @@ -1576,6 +1576,7 @@ private: } void localvar1() { + // extracttests.disable functionVariableUsage("void foo()\n" "{\n" " int i = 0;\n" @@ -2007,9 +2008,12 @@ private: " int i = 0;\n" "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'i' is assigned a value that is never used.\n", errout.str()); + // extracttests.enable } void localvar2() { + // extracttests.start: struct undefined { void f(); }; + functionVariableUsage("int foo()\n" "{\n" " int i;\n" @@ -2032,6 +2036,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.disable functionVariableUsage("undefined foo()\n" "{\n" " undefined i;\n" @@ -2039,6 +2044,7 @@ private: "}\n", "test.c"); ASSERT_EQUALS("[test.c:3]: (style) Variable 'i' is not assigned a value.\n", errout.str()); + // extracttests.enable functionVariableUsage("undefined *foo()\n" "{\n" @@ -2146,7 +2152,7 @@ private: } void localvar3() { - functionVariableUsage("void foo()\n" + functionVariableUsage("void foo(int abc)\n" "{\n" " int i;\n" " if ( abc )\n" @@ -2225,6 +2231,8 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Unused variable: i\n", errout.str()); + // extracttests.start: struct A {int x;}; + functionVariableUsage("void foo()\n" "{\n" " A * i;\n" @@ -2384,6 +2392,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:6]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); + // extracttests.start: int f(); functionVariableUsage("void foo()\n" "{\n" " int a, b, c;\n" @@ -2527,6 +2536,7 @@ private: } void localvar13() { // ticket #1640 + // extracttests.start: struct OBJECT { int ySize; }; functionVariableUsage("void foo( OBJECT *obj )\n" "{\n" " int x;\n" @@ -2592,7 +2602,7 @@ private: } void localvar16() { // ticket #1709 - functionVariableUsage("int foo()\n" + functionVariableUsage("void foo()\n" "{\n" " char buf[5];\n" " char *ptr = buf;\n" @@ -2600,7 +2610,7 @@ private: "}"); // TODO ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'buf' is assigned a value that is never used.\n", errout.str()); - functionVariableUsage("int foo()\n" + functionVariableUsage("void foo()\n" "{\n" " char buf[5];\n" " char *ptr = buf - 1;\n" @@ -2609,7 +2619,7 @@ private: ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'buf' is not assigned a value.\n", errout.str()); // #3910 - functionVariableUsage("int foo() {\n" + functionVariableUsage("void foo() {\n" " char buf[5];\n" " char *data[2];\n" " data[0] = buf;\n" @@ -2617,7 +2627,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - functionVariableUsage("int foo() {\n" + functionVariableUsage("void foo() {\n" " char buf1[5];\n" " char buf2[5];\n" " char *data[2];\n" @@ -2629,6 +2639,7 @@ private: } void localvar17() { // ticket #1720 + // extracttests.disable // Don't crash when checking the code below! functionVariableUsage("void foo()\n" "{\n" @@ -2642,6 +2653,7 @@ private: " line_start = ptr;\n" "}"); ASSERT_EQUALS("[test.cpp:10]: (style) Variable 'line_start' is assigned a value that is never used.\n", errout.str()); + // extracttests.enable } void localvar18() { // ticket #1723 @@ -3028,11 +3040,13 @@ private: } void localvar47() { // #6603 + // extracttests.disable functionVariableUsage("void f() {\n" " int (SfxUndoManager::*retrieveCount)(bool) const\n" " = (flag) ? &SfxUndoManager::foo : &SfxUndoManager::bar;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'retrieveCount' is assigned a value that is never used.\n", errout.str()); + // extracttests.enable } void localvar48() { // #6954 @@ -3087,8 +3101,9 @@ private: } void localvar51() { // #8128 FN - functionVariableUsage("void foo() {\n" - " const char *tok = var->nameToken();\n" + // extracttests.start: struct Token { const Token* next() const; }; const Token* nameToken(); + functionVariableUsage("void foo(const Token *var) {\n" + " const Token *tok = nameToken();\n" " tok = tok->next();\n" // read+write "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'tok' is assigned a value that is never used.\n", errout.str()); @@ -3110,7 +3125,7 @@ private: } void localvar53() { - functionVariableUsage("void foo() {\n" + functionVariableUsage("void foo(int a, int loop) {\n" " bool x = false;\n" " while (loop) {\n" " if (a) {\n" @@ -3121,7 +3136,7 @@ private: "}"); ASSERT_EQUALS("[test.cpp:2]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); - functionVariableUsage("void foo() {\n" + functionVariableUsage("void foo(int a, int loop) {\n" " bool x = false;\n" " while (loop) {\n" " if (a) {\n" @@ -3202,14 +3217,14 @@ private: void localvarloops() { // loops - functionVariableUsage("void fun() {\n" + functionVariableUsage("void fun(int c) {\n" " int x;\n" " while (c) { x=10; }\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'x' is assigned a value that is never used.\n", errout.str()); functionVariableUsage("void dostuff(int x);\n" - "void fun() {\n" + "void fun(int y, int c) {\n" " int x = 1;\n" " while (c) {\n" " dostuff(x);\n" @@ -3357,7 +3372,7 @@ private: " {\n" " int *b = &a;\n" " }\n" - "}"); + "};"); ASSERT_EQUALS("[test.cpp:6]: (style) Variable 'b' is assigned a value that is never used.\n", errout.str()); functionVariableUsage("int a;\n" @@ -3475,6 +3490,7 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: int a[10]; functionVariableUsage("void foo()\n" "{\n" " int *b = a;\n" @@ -3601,6 +3617,7 @@ private: ASSERT_EQUALS(// TODO "[test.cpp:4]: (style) Variable 'a' is assigned a value that is never used.\n" "[test.cpp:5]: (style) Variable 'c' is assigned a value that is never used.\n", errout.str()); + // extracttests.start: int x; functionVariableUsage("void foo()\n" "{\n" " int a[10], * b = a + 10;\n" @@ -3625,6 +3642,7 @@ private: "}"); // TODO ASSERT_EQUALS("[test.cpp:5]: (style) Variable 'c[1]' is assigned a value that is never used.\n", errout.str()); + // extracttests.start: void f(int); functionVariableUsage("void foo()\n" "{\n" " int a[10], * b = a + 10;\n" @@ -3819,6 +3837,7 @@ private: } void localvaralias6() { // ticket 1729 + // extracttests.start: int a(); void b(const char *); functionVariableUsage("void foo()\n" "{\n" " char buf[8];\n" @@ -3859,7 +3878,7 @@ private: "}"); // TODO ASSERT_EQUALS("[test.cpp:6]: (style) Variable 'buf' is assigned a value that is never used.\n", errout.str()); - functionVariableUsage("void foo()\n" + functionVariableUsage("void foo(char *vdata)\n" "{\n" " char buf[8];\n" " char *srcdata;\n" @@ -4336,6 +4355,7 @@ private: } void localvarStruct5() { + // extracttests.disable functionVariableUsage("int foo() {\n" " A a;\n" " return a.i;\n" @@ -4354,6 +4374,7 @@ private: "}\n", "test.c"); ASSERT_EQUALS("[test.c:2]: (style) Unused variable: a\n", errout.str()); + // extracttests.enable functionVariableUsage("struct A { int i; };\n" "int foo() {\n" @@ -4362,13 +4383,6 @@ private: "}"); ASSERT_EQUALS("", errout.str()); - functionVariableUsage("class A { int i; };\n" - "int foo() {\n" - " A a;\n" - " return a.i;\n" - "}"); - ASSERT_EQUALS("", errout.str()); - functionVariableUsage("struct A { int i; };\n" "int foo() {\n" " A a;\n" @@ -4377,14 +4391,6 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'a.i' is assigned a value that is never used.\n", errout.str()); - functionVariableUsage("class A { int i; };\n" - "int foo() {\n" - " A a;\n" - " a.i = 0;\n" - " return 0;\n" - "}"); - ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'a.i' is assigned a value that is never used.\n", errout.str()); - functionVariableUsage("struct A { int i; };\n" "int foo() {\n" " A a = { 0 };\n" @@ -4392,12 +4398,14 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used.\n", errout.str()); + // extracttests.disable functionVariableUsage("class A { int i; };\n" "int foo() {\n" " A a = { 0 };\n" " return 0;\n" "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'a' is assigned a value that is never used.\n", errout.str()); + // extracttests.enable functionVariableUsage("class A { int i; public: A(); { } };\n" "int foo() {\n" @@ -4474,9 +4482,10 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.start: void dostuff(int*); functionVariableUsage("struct ARG {\n" - " void *a;\n" - " void *b;\n" + " int a;\n" + " int b;\n" "};\n" "\n" "void fun() {\n" @@ -4533,7 +4542,7 @@ private: void localvarStruct10() { // #6766 functionVariableUsage("struct S { int x; };\n" "\n" - "void foo() {\n" + "void foo(const struct S s2) {\n" " struct S s;\n" " s.x = 3;\n" " memcpy (&s, &s2, sizeof (S));\n" @@ -4542,6 +4551,8 @@ private: } void localvarStructArray() { + // extracttests.start: struct X {int a;}; + // #3633 - detect that struct array is assigned a value functionVariableUsage("void f() {\n" " struct X x[10];\n" @@ -4674,14 +4685,16 @@ private: "}"); ASSERT_EQUALS("", errout.str()); + // extracttests.disable functionVariableUsage("void f() {\n" // unknown class => library configuration is needed " Fred fred;\n" " int *a; a = b;\n" " fred += a;\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (information) --check-library: Provide configuration for Fred\n", errout.str()); + // extracttests.enable - functionVariableUsage("void f() {\n" + functionVariableUsage("void f(std::pair x) {\n" " std::pair fred;\n" // class with library configuration " fred = x;\n" "}"); @@ -4896,28 +4909,6 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); - functionVariableUsage("void foo()\n" - "{\n" - " void* ptr = g_malloc(16);\n" - " g_free(ptr);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); - - functionVariableUsage("void foo()\n" - "{\n" - " void* ptr = kmalloc(16, GFP_KERNEL);\n" - " kfree(ptr);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); - - functionVariableUsage("void foo()\n" - "{\n" - " void* ptr = vmalloc(16, GFP_KERNEL);\n" - " vfree(ptr);\n" - "}"); - ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); - - functionVariableUsage("void foo()\n" "{\n" " char* ptr = new char[16];\n" @@ -4925,6 +4916,8 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); + // extracttests.disable + functionVariableUsage("void foo()\n" "{\n" " char* ptr = new ( nothrow ) char[16];\n" @@ -4939,6 +4932,8 @@ private: "}"); ASSERT_EQUALS("[test.cpp:3]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); + // extracttests.enable + functionVariableUsage("void foo()\n" "{\n" " char* ptr = new char;\n" @@ -5009,7 +5004,7 @@ private: functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" - " Fred* ptr = malloc(sizeof(Fred));\n" + " Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " free(ptr);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); @@ -5017,7 +5012,7 @@ private: functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" - " Fred* ptr = malloc(sizeof(Fred));\n" + " Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " ptr->i = 0;\n" " free(ptr);\n" "}"); @@ -5026,7 +5021,7 @@ private: functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" - " struct Fred* ptr = malloc(sizeof(Fred));\n" + " struct Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " free(ptr);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); @@ -5034,7 +5029,7 @@ private: functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" - " struct Fred* ptr = malloc(sizeof(Fred));\n" + " struct Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " ptr->i = 0;\n" " free(ptr);\n" "}"); @@ -5048,6 +5043,8 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); + // extracttests.disable + functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" @@ -5064,6 +5061,8 @@ private: "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); + // extracttests.enable + functionVariableUsage("struct Fred { int i; };\n" "void foo()\n" "{\n" @@ -5093,7 +5092,7 @@ private: functionVariableUsage("class Fred { public: int i; };\n" "void foo()\n" "{\n" - " Fred* ptr = malloc(sizeof(Fred));\n" + " Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " free(ptr);\n" "}"); ASSERT_EQUALS("[test.cpp:4]: (style) Variable 'ptr' is allocated memory that is never used.\n", errout.str()); @@ -5101,7 +5100,7 @@ private: functionVariableUsage("class Fred { public: int i; };\n" "void foo()\n" "{\n" - " Fred* ptr = malloc(sizeof(Fred));\n" + " Fred* ptr = (Fred*)malloc(sizeof(Fred));\n" " ptr->i = 0;\n" " free(ptr);\n" "}"); @@ -5344,6 +5343,8 @@ private: } void localVarStd() { + // extracttests.start: struct MyClass {int x;}; std::string foo(); + functionVariableUsage("void f() {\n" " std::string x = foo();\n" "}"); diff --git a/tools/extracttests.py b/tools/extracttests.py index d82ec99a8..cd29c1933 100755 --- a/tools/extracttests.py +++ b/tools/extracttests.py @@ -26,6 +26,43 @@ import sys import re +def add_includes(code): + includes = (('alloca','alloca.h'), + ('NULL','cstddef'), + ('size_t','cstddef'), + ('free','cstdlib'), + ('malloc','cstdlib'), + ('realloc','cstdlib'), + ('stdin','cstdio'), + ('strcat','cstring'), + ('strchr','cstring'), + ('strcpy','cstring'), + ('strlen','cstring'), + ('strncat','cstring'), + ('strncpy','cstring'), + ('std::cout','iostream'), + ('std::shared_ptr','memory'), + ('std::string','string'), + ('std::unique_ptr','memory')) + + for i in includes: + if i[0] in code: + include_header = f'#include <{i[1]}>' + if include_header not in code: + code = include_header + '\n' + code + + return code + + +def tweak_expected(expected, start_code): + if start_code is None: + return expected + res = re.match(r'\[([^:\]]+):([0-9]+)\](.*)', expected) + if res is None: + return expected + lines = len(start_code.split('\n')) + return '[%s:%i]%s' % (res.group(1), lines + int(res.group(2)), res.group(3)) + class Extract: """ @@ -48,6 +85,8 @@ class Extract: testclass = None functionName = None code = None + start_code = None + disable = False fin = open(filename, 'r') for line in fin: @@ -64,31 +103,47 @@ class Extract: res = re.match('\\s+void (' + name + ')\\(\\)', line) if res is not None: functionName = res.group(1) + start_code = None elif re.match('\\s+}', line) is not None: functionName = None - if functionName is None: + # extracttests commands.. + res = re.match(r'\s*//\s*extracttests.start:(.*)', line) + if res is not None: + start_code = res.group(1).replace('\\n', '\n') + elif line.find('extracttests.disable') >= 0: + disable = True + elif line.find('extracttests.enable') >= 0: + disable = False + + if functionName is None or disable: continue # check - res = re.match('\\s+check.*\\(' + string, line) + res = re.match('\\s+' + check_function + '\\(' + string, line) if res is not None: code = res.group(1) + if start_code: + code = start_code + '\n' + code # code.. if code is not None: res = re.match('\\s+' + string, line) if res is not None: code = code + res.group(1) + if res.group(1).find('"') > 0: + code = None # assert res = re.match('\\s+ASSERT_EQUALS\\(\\"([^"]*)\\",', line) if res is not None and code is not None: + code = add_includes(code) + expected = tweak_expected(res.group(1), start_code) node = {'testclass': testclass, 'functionName': functionName, - 'code': code, - 'expected': res.group(1)} + 'code': code.replace("\\\\", "\\"), + 'expected': expected} self.nodes.append(node) code = None @@ -165,7 +220,7 @@ def writeHtmlFile(nodes, functionName, filename, errorsOnly): if len(sys.argv) <= 1 or '--help' in sys.argv: print('Extract test cases from test file') print( - 'Syntax: extracttests.py [--html=folder] [--xml] [--code=folder] [--onlyTP] path/testfile.cpp') + 'Syntax: extracttests.py [--html=folder] [--xml] [--code=folder] [--only-tp] [--check-function=check] path/testfile.cpp') sys.exit(0) # parse command line @@ -174,10 +229,11 @@ filename = None htmldir = None codedir = None onlyTP = None +check_function = 'check.*' for arg in sys.argv[1:]: if arg == '--xml': xml = True - elif arg == '--onlyTP': + elif arg == '--only-tp': onlyTP = True elif arg.startswith('--html='): htmldir = arg[7:] @@ -185,6 +241,8 @@ for arg in sys.argv[1:]: codedir = arg[7:] elif arg.endswith('.cpp'): filename = arg + elif arg.startswith('--check-function='): + check_function = arg[17:] else: print('Invalid option: ' + arg) sys.exit(1) @@ -286,6 +344,11 @@ if filename is not None: errors = open(codedir + 'errors.txt', 'w') + testfile = filename + if testfile.find('/'): + testfile = testfile[testfile.rfind('/'):] + testfile = testfile[:testfile.find('.')] + for node in e.nodes: if onlyTP and node['expected'] == '': continue @@ -298,14 +361,11 @@ if filename is not None: code = code.replace('\\"', '"') expected = node['expected'] - filename = '0000' + str(testnum) + '-' - filename = filename[-4:] - filename += functionName + '.cpp' + filename = '%s-%03i-%s.cpp' % (testfile, testnum, functionName) # source code - fout = open(codedir + filename, 'w') - fout.write(code) - fout.close() + with open(codedir + filename, 'w') as fout: + fout.write(code) # write 'expected' to errors.txt if expected != '':