diff --git a/cfg/windows.cfg b/cfg/windows.cfg index f690a83a1aa..05c31803fbc 100644 --- a/cfg/windows.cfg +++ b/cfg/windows.cfg @@ -4907,6 +4907,8 @@ HFONT CreateFont( + + false diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6aa923a3667..08e053a840a 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4251,7 +4251,7 @@ static bool setVarIdParseDeclaration(Token** tok, const VariableMap& variableMap bracket = true; } else if (tok2->str() == "::") { singleNameCount = 0; - } else if (tok2->str() != "*" && tok2->str() != "::" && tok2->str() != "...") { + } else if (tok2->str() != "*" && tok2->str() != "...") { break; } tok2 = tok2->next(); diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index 5a3833419b0..e7f9709a33d 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -5334,16 +5334,19 @@ static const Scope* getLoopScope(const Token* tok) // static void valueFlowConditionExpressions(const TokenList &tokenlist, const SymbolDatabase& symboldatabase, ErrorLogger *errorLogger, const Settings &settings) { - if (settings.checkLevel == Settings::CheckLevel::normal) + if (!settings.daca && (settings.checkLevel == Settings::CheckLevel::normal)) return; for (const Scope * scope : symboldatabase.functionScopes) { if (const Token* incompleteTok = findIncompleteVar(scope->bodyStart, scope->bodyEnd)) { if (settings.debugwarnings) bailoutIncompleteVar(tokenlist, errorLogger, incompleteTok, "Skipping function due to incomplete variable " + incompleteTok->str()); - break; + continue; } + if (settings.daca && (settings.checkLevel == Settings::CheckLevel::normal)) + continue; + for (Token* tok = const_cast(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) { if (!Token::simpleMatch(tok, "if (")) continue; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4ec673ba152..723aa98ea0c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -132,6 +132,7 @@ if (BUILD_TESTS) --suppress=valueFlowBailout --suppress=purgedConfiguration --suppress=unmatchedSuppression + --suppress=checkersReport ${CMAKE_CURRENT_SOURCE_DIR}/cfg/${CFG_TEST} ) endif() diff --git a/test/cfg/gnu.c b/test/cfg/gnu.c index a259215153b..6b51a2bb3fb 100644 --- a/test/cfg/gnu.c +++ b/test/cfg/gnu.c @@ -387,6 +387,7 @@ void memleak_xmalloc() void memleak_mmap() { + // cppcheck-suppress valueFlowBailoutIncompleteVar const void * p_mmap = mmap(NULL, 1, PROT_NONE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); printf("%p", p_mmap); // cppcheck-suppress memleak @@ -466,6 +467,7 @@ int nullPointer_epoll_ctl(int epfd, int op, int fd, struct epoll_event *event) // Remove (deregister) the target file descriptor fd from the // epoll instance referred to by epfd. The event is ignored and // can be NULL. + // cppcheck-suppress valueFlowBailoutIncompleteVar return epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); } #endif diff --git a/test/cfg/googletest.cpp b/test/cfg/googletest.cpp index cc4c1415ae6..7dfc0946006 100644 --- a/test/cfg/googletest.cpp +++ b/test/cfg/googletest.cpp @@ -50,6 +50,7 @@ TEST(test_cppcheck, cppcheck) // #9964 - avoid compareBoolExpressionWithInt false positive TEST(Test, assert_false_fp) { + // cppcheck-suppress valueFlowBailoutIncompleteVar ASSERT_FALSE(errno < 0); } @@ -73,6 +74,7 @@ TEST(Test, warning_in_assert_macros) // cppcheck-suppress duplicateExpression ASSERT_GE(i, i); + // cppcheck-suppress valueFlowBailoutIncompleteVar unsigned int u = errno; // cppcheck-suppress [unsignedPositive] ASSERT_GE(u, 0); diff --git a/test/cfg/gtk.c b/test/cfg/gtk.c index 66aa875b229..6d8b2258a91 100644 --- a/test/cfg/gtk.c +++ b/test/cfg/gtk.c @@ -302,6 +302,7 @@ void g_new0_test() int b; }; // valid + // cppcheck-suppress valueFlowBailoutIncompleteVar struct a * pNew1 = g_new0(struct a, 5); printf("%p", pNew1); g_free(pNew1); @@ -320,6 +321,7 @@ void g_try_new_test() int b; }; // valid + // cppcheck-suppress valueFlowBailoutIncompleteVar struct a * pNew1 = g_try_new(struct a, 5); printf("%p", pNew1); g_free(pNew1); @@ -337,6 +339,7 @@ void g_try_new0_test() int b; }; // valid + // cppcheck-suppress valueFlowBailoutIncompleteVar struct a * pNew1 = g_try_new0(struct a, 5); printf("%p", pNew1); g_free(pNew1); @@ -354,7 +357,7 @@ void g_renew_test() struct a { int b; }; - // cppcheck-suppress leakReturnValNotUsed + // cppcheck-suppress [leakReturnValNotUsed,valueFlowBailoutIncompleteVar] g_renew(struct a, NULL, 1); struct a * pNew = g_new(struct a, 1); @@ -369,7 +372,7 @@ void g_try_renew_test() struct a { int b; }; - // cppcheck-suppress leakReturnValNotUsed + // cppcheck-suppress [leakReturnValNotUsed,valueFlowBailoutIncompleteVar] g_try_renew(struct a, NULL, 1); struct a * pNew = g_try_new(struct a, 1); diff --git a/test/cfg/opencv2.cpp b/test/cfg/opencv2.cpp index 7af2d6b7055..5ab29ef80ff 100644 --- a/test/cfg/opencv2.cpp +++ b/test/cfg/opencv2.cpp @@ -41,6 +41,6 @@ void ignoredReturnValue() void memleak() { const char * pBuf = (char *)cv::fastMalloc(1000); // cppcheck-suppress cstyleCast - std::cout << pBuf; + std::cout << pBuf; // cppcheck-suppress valueFlowBailoutIncompleteVar // cppcheck-suppress memleak } diff --git a/test/cfg/posix.c b/test/cfg/posix.c index c2a78fbdc1b..95c7b81cda1 100644 --- a/test/cfg/posix.c +++ b/test/cfg/posix.c @@ -1062,6 +1062,7 @@ void * memleak_mmap2() // #8327 void memleak_getline() { // #11043 char *line = NULL; size_t size = 0; + // cppcheck-suppress valueFlowBailoutIncompleteVar getline(&line, &size, stdin); // cppcheck-suppress memleak line = NULL; @@ -1082,6 +1083,7 @@ void memleak_getline_array(FILE* stream) { // #12498 void memleak_getdelim(int delim) { char *line = NULL; size_t size = 0; + // cppcheck-suppress valueFlowBailoutIncompleteVar getdelim(&line, &size, delim, stdin); // cppcheck-suppress memleak line = NULL; @@ -1101,6 +1103,7 @@ void memleak_getdelim_array(FILE* stream, int delim) { void * identicalCondition_mmap(int fd, size_t size) // #9940 { + // cppcheck-suppress valueFlowBailoutIncompleteVar void* buffer = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (buffer == MAP_FAILED) { return NULL; @@ -1113,6 +1116,7 @@ int munmap_no_double_free(int tofd, // #11396 size_t len) { int rc; + // cppcheck-suppress valueFlowBailoutIncompleteVar const void* fptr = mmap(NULL,len,PROT_READ|PROT_WRITE,MAP_SHARED,fromfd,(off_t)0); if (fptr == MAP_FAILED) { return -1; @@ -1147,6 +1151,7 @@ void resourceLeak_fdopen(int fd) void resourceLeak_fdopen2(const char* fn) // #2767 { + // cppcheck-suppress valueFlowBailoutIncompleteVar int fi = open(fn, O_RDONLY); FILE* fd = fdopen(fi, "r"); fclose(fd); @@ -1193,14 +1198,14 @@ void resourceLeak_socket(void) void resourceLeak_open1(void) { - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] int fd = open("file", O_RDWR | O_CREAT); // cppcheck-suppress resourceLeak } void resourceLeak_open2(void) { - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] int fd = open("file", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); // cppcheck-suppress resourceLeak } @@ -1213,6 +1218,7 @@ void noleak(int x, int y, int z) closedir(p2); int s = socket(AF_INET,SOCK_STREAM,0); close(s); + // cppcheck-suppress valueFlowBailoutIncompleteVar int fd1 = open("a", O_RDWR | O_CREAT); close(fd1); int fd2 = open("a", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); @@ -1357,7 +1363,7 @@ void timet_h(const struct timespec* ptp1) clockid_t clk_id1, clk_id2, clk_id3; // cppcheck-suppress constVariablePointer struct timespec* ptp; - // cppcheck-suppress uninitvar + // cppcheck-suppress [uninitvar,valueFlowBailoutIncompleteVar] clock_settime(CLOCK_REALTIME, ptp); // cppcheck-suppress uninitvar clock_settime(clk_id1, ptp); diff --git a/test/cfg/qt.cpp b/test/cfg/qt.cpp index b6cbff9fe96..513c8bb1bef 100644 --- a/test/cfg/qt.cpp +++ b/test/cfg/qt.cpp @@ -576,7 +576,7 @@ void validCode(int * pIntPtr, QString & qstrArg, double d) printf(QT_TR_NOOP("Hi")); - // cppcheck-suppress checkLibraryFunction + // cppcheck-suppress [checkLibraryFunction,valueFlowBailoutIncompleteVar] Q_DECLARE_LOGGING_CATEGORY(logging_category_test); QT_FORWARD_DECLARE_CLASS(forwardDeclaredClass); QT_FORWARD_DECLARE_STRUCT(forwardDeclaredStruct); diff --git a/test/cfg/runtests.sh b/test/cfg/runtests.sh index 744d9aa7284..70eb2ffb478 100755 --- a/test/cfg/runtests.sh +++ b/test/cfg/runtests.sh @@ -27,7 +27,7 @@ CFG="$DIR"../../cfg/ # TODO: remove missingInclude disabling when it no longer is implied by --enable=information # Cppcheck options # need to suppress unmatchedSuppression in case valueFlowBailout is not reported -CPPCHECK_OPT='--check-library --platform=unix64 --enable=style,information --inconclusive --force --check-level=exhaustive --error-exitcode=-1 --disable=missingInclude --inline-suppr --template="{file}:{line}:{severity}:{id}:{message}" --debug-warnings --suppress=valueFlowBailout --suppress=purgedConfiguration --suppress=unmatchedSuppression' +CPPCHECK_OPT='--check-library --platform=unix64 --enable=style,information --inconclusive --force --check-level=exhaustive --error-exitcode=-1 --disable=missingInclude --inline-suppr --template="{file}:{line}:{severity}:{id}:{message}" --debug-warnings --suppress=valueFlowBailout --suppress=purgedConfiguration --suppress=unmatchedSuppression --suppress=checkersReport' # Compiler settings CXX=g++ diff --git a/test/cfg/std.c b/test/cfg/std.c index 9f2a0d213cf..98952c6de3b 100644 --- a/test/cfg/std.c +++ b/test/cfg/std.c @@ -401,6 +401,7 @@ void nullpointer(int value) fp = 0; // No FP fflush(0); // If stream is a null pointer, all streams are flushed. + // cppcheck-suppress valueFlowBailoutIncompleteVar fp = freopen(0,"abc",stdin); fclose(fp); fp = NULL; @@ -732,6 +733,7 @@ void uninitvar_fgets(void) char *str; int n; + // cppcheck-suppress valueFlowBailoutIncompleteVar fgets(buf,10,stdin); // cppcheck-suppress uninitvar @@ -749,6 +751,7 @@ void uninitvar_fputc(void) int i; FILE *fp; + // cppcheck-suppress valueFlowBailoutIncompleteVar fputc('a', stdout); // cppcheck-suppress uninitvar @@ -763,6 +766,7 @@ void uninitvar_fputs(void) const char *s; FILE *fp; + // cppcheck-suppress valueFlowBailoutIncompleteVar fputs("a", stdout); // cppcheck-suppress uninitvar @@ -3456,6 +3460,7 @@ void invalidFunctionArg_log10(float f, double d, const long double ld) (void)log10f(0.0f); (void)log10f(1.4013e-45f); // note: calculated by nextafterf(0.0f, 1.0f); (void)log10f(f); + // cppcheck-suppress valueFlowBailoutIncompleteVar (void)log10f(FLT_MAX); // cppcheck-suppress invalidFunctionArg @@ -3480,6 +3485,7 @@ void invalidFunctionArg_log(float f, double d, const long double ld) (void)logf(0.0f); (void)logf(1.4013e-45f); // note: calculated by nextafterf(0.0f, 1.0f); (void)logf(f); + // cppcheck-suppress valueFlowBailoutIncompleteVar (void)logf(FLT_MAX); // cppcheck-suppress invalidFunctionArg @@ -3504,6 +3510,7 @@ void invalidFunctionArg_log2(float f, double d, const long double ld) (void)log2f(0.0f); (void)log2f(1.4013e-45f); // note: calculated by nextafterf(0.0f, 1.0f); (void)log2f(f); + // cppcheck-suppress valueFlowBailoutIncompleteVar (void)log2f(FLT_MAX); // cppcheck-suppress invalidFunctionArg @@ -4973,6 +4980,7 @@ void invalidPrintfArgType_printf(void) // #7016 uint8_t n = 7; // TODO cppcheck-suppress invalidPrintfArgType_uint + // cppcheck-suppress valueFlowBailoutIncompleteVar printf("%" PRIi16 "\n", n); } diff --git a/test/cfg/std.cpp b/test/cfg/std.cpp index d27a87d0b47..a5490796dc8 100644 --- a/test/cfg/std.cpp +++ b/test/cfg/std.cpp @@ -662,8 +662,10 @@ void memleak_localtime_s(const std::time_t *restrict time, struct tm *restrict r { const time_t t = time(0); const struct tm* const now = new tm(); - if (localtime_s(now, &t) == 0) + if (localtime_s(now, &t) == 0) { + // cppcheck-suppress valueFlowBailoutIncompleteVar std::cout << now->tm_mday << std::endl; + } // cppcheck-suppress memleak } #endif // __STDC_LIB_EXT1__ @@ -706,6 +708,7 @@ void invalidFunctionArg_std_wstring_substr(const std::wstring &str, std::size_t (void)str.substr(pos,-1); // no warning is expected for (void)str.substr(pos,len); + // cppcheck-suppress valueFlowBailoutIncompleteVar (void)str.substr(pos, std::wstring::npos); } @@ -4256,7 +4259,7 @@ void nullPointer_system(const char *c) void uninitvar_setw(void) { int i; - // cppcheck-suppress uninitvar + // cppcheck-suppress [uninitvar,valueFlowBailoutIncompleteVar] std::cout << std::setw(i); } @@ -4264,6 +4267,7 @@ void uninitvar_setiosflags(void) { std::ios_base::fmtflags mask; // TODO cppcheck-suppress uninitvar + // cppcheck-suppress valueFlowBailoutIncompleteVar std::cout << std::setiosflags(mask); // #6987 - false negative } @@ -4271,13 +4275,14 @@ void uninitvar_resetiosflags(void) { std::ios_base::fmtflags mask; // TODO cppcheck-suppress uninitvar + // cppcheck-suppress valueFlowBailoutIncompleteVar std::cout << std::resetiosflags(mask); // #6987 - false negative } void uninitvar_setfill(void) { char c; - // cppcheck-suppress uninitvar + // cppcheck-suppress [uninitvar,valueFlowBailoutIncompleteVar] std::cout << std::setfill(c); wchar_t wc; @@ -4288,14 +4293,14 @@ void uninitvar_setfill(void) void uninitvar_setprecision(void) { int p; - // cppcheck-suppress uninitvar + // cppcheck-suppress [uninitvar,valueFlowBailoutIncompleteVar] std::cout << std::setprecision(p); } void uninitvar_setbase(void) { int p; - // cppcheck-suppress uninitvar + // cppcheck-suppress [uninitvar,valueFlowBailoutIncompleteVar] std::cout << std::setbase(p); } @@ -4732,6 +4737,7 @@ void stdbind_helper(int a) void stdbind() { + // cppcheck-suppress valueFlowBailoutIncompleteVar using namespace std::placeholders; // TODO cppcheck-suppress ignoredReturnValue #9369 diff --git a/test/cfg/windows.cpp b/test/cfg/windows.cpp index 179f44d4b3f..470aeb332c1 100644 --- a/test/cfg/windows.cpp +++ b/test/cfg/windows.cpp @@ -485,7 +485,7 @@ void mismatchAllocDealloc() void nullPointer() { HANDLE hSemaphore; - // cppcheck-suppress nullPointer + // cppcheck-suppress [nullPointer,valueFlowBailoutIncompleteVar] hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, FALSE, NULL); CloseHandle(hSemaphore); @@ -588,7 +588,7 @@ void memleak_HeapAlloc() void memleak_LocalAlloc() { LPTSTR pszBuf; - // cppcheck-suppress [LocalAllocCalled, cstyleCast] + // cppcheck-suppress [LocalAllocCalled, cstyleCast, valueFlowBailoutIncompleteVar] pszBuf = (LPTSTR)LocalAlloc(LPTR, MAX_PATH*sizeof(TCHAR)); (void)LocalSize(pszBuf); (void)LocalFlags(pszBuf); @@ -622,7 +622,7 @@ void resourceLeak_CreateSemaphoreA() void resourceLeak_CreateSemaphoreEx() { HANDLE hSemaphore; - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] hSemaphore = CreateSemaphoreEx(NULL, 0, 1, NULL, 0, SEMAPHORE_ALL_ACCESS); // cppcheck-suppress resourceLeak } @@ -630,7 +630,7 @@ void resourceLeak_CreateSemaphoreEx() void resourceLeak_OpenSemaphore() { HANDLE hSemaphore; - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] hSemaphore = OpenSemaphore(SEMAPHORE_ALL_ACCESS, TRUE, _T("sem")); // cppcheck-suppress resourceLeak } @@ -646,7 +646,7 @@ void resourceLeak_CreateMutexA() void resourceLeak_CreateMutexEx() { HANDLE hMutex; - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] hMutex = CreateMutexEx(NULL, _T("sem"), 0, MUTEX_ALL_ACCESS); // cppcheck-suppress resourceLeak } @@ -688,7 +688,7 @@ void resourceLeak_CreateEventExA() void resourceLeak_OpenEventW() { HANDLE hEvent; - // cppcheck-suppress unreadVariable + // cppcheck-suppress [unreadVariable,valueFlowBailoutIncompleteVar] hEvent = OpenEventW(EVENT_ALL_ACCESS, TRUE, L"testevent"); // cppcheck-suppress resourceLeak } @@ -705,7 +705,7 @@ void ignoredReturnValue(FILE* fp) { // cppcheck-suppress leakReturnValNotUsed CreateSemaphoreW(NULL, 0, 1, NULL); - // cppcheck-suppress leakReturnValNotUsed + // cppcheck-suppress [leakReturnValNotUsed,valueFlowBailoutIncompleteVar] CreateSemaphoreExA(NULL, 0, 1, NULL, 0, SEMAPHORE_ALL_ACCESS); // cppcheck-suppress leakReturnValNotUsed OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, TRUE, "sem"); @@ -770,7 +770,7 @@ void invalidFunctionArg() // cppcheck-suppress invalidFunctionArgBool hSemaphore = CreateSemaphore(NULL, 0, 1, false); CloseHandle(hSemaphore); - // cppcheck-suppress invalidFunctionArg + // cppcheck-suppress [invalidFunctionArg,valueFlowBailoutIncompleteVar] hSemaphore = CreateSemaphoreEx(NULL, 0, 0, NULL, 0, SEMAPHORE_ALL_ACCESS); CloseHandle(hSemaphore); // cppcheck-suppress invalidFunctionArg diff --git a/test/testcondition.cpp b/test/testcondition.cpp index 868f8a98caa..5c794bbd39c 100644 --- a/test/testcondition.cpp +++ b/test/testcondition.cpp @@ -123,6 +123,7 @@ class TestCondition : public TestFixture { TEST_CASE(compareOutOfTypeRange); TEST_CASE(knownConditionCast); // #9976 TEST_CASE(knownConditionIncrementLoop); // #9808 + TEST_CASE(knownConditionAfterBailout); // #12526 } #define check(...) check_(__FILE__, __LINE__, __VA_ARGS__) @@ -5957,6 +5958,37 @@ class TestCondition : public TestFixture { "}\n"); ASSERT_EQUALS("", errout_str()); } + + void knownConditionAfterBailout() { // #12526 + check( + "#include \n" + "int func()\n" + "{\n" + " return VALUE_1;" + "}\n" + "\n" + "struct S1 {\n" + " bool b{};\n" + "};\n" + "\n" + "struct S {\n" + " void f(const std::list& l) const\n" + " {\n" + " if (mS.b)\n" + " return;\n" + " for (int i : l)\n" + " {\n" + " (void)i;\n" + " if (mS.b)\n" + " continue;\n" + " }\n" + " }\n" + "\n" + " S1 mS;\n" + "};" + ); + ASSERT_EQUALS("[test.cpp:13] -> [test.cpp:18]: (style) Condition 'mS.b' is always false\n", errout_str()); + } }; REGISTER_TEST(TestCondition) diff --git a/test/testvalueflow.cpp b/test/testvalueflow.cpp index 3d6b6feb2a4..61f99fe52cd 100644 --- a/test/testvalueflow.cpp +++ b/test/testvalueflow.cpp @@ -160,6 +160,8 @@ class TestValueFlow : public TestFixture { TEST_CASE(valueFlowImpossibleUnknownConstant); TEST_CASE(valueFlowContainerEqual); + TEST_CASE(valueFlowBailoutIncompleteVar); + TEST_CASE(performanceIfCount); } @@ -8468,6 +8470,22 @@ class TestValueFlow : public TestFixture { ASSERT_EQUALS(false, testValueOfX(code, 5U, 0)); } + void valueFlowBailoutIncompleteVar() { // #12526 + bailout( + "int f1() {\n" + " return VALUE_1;\n" + "}\n" + "\n" + "int f2() {\n" + " return VALUE_2;\n" + "}\n" + ); + ASSERT_EQUALS_WITHOUT_LINENUMBERS( + "[test.cpp:2]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_1\n" + "[test.cpp:6]: (debug) valueFlowConditionExpressions bailout: Skipping function due to incomplete variable VALUE_2\n", + errout_str()); + } + void performanceIfCount() { /*const*/ Settings s(settings); s.performanceValueFlowMaxIfCount = 1;