diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 0ceec88ab..7d58a97c9 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -2418,6 +2418,24 @@ void CheckOther::checkInterlockedDecrement() (Token::Match(checkStartTok, "%name% %comp% 0 )") && checkStartTok->str() == interlockedVarTok->str())) { raceAfterInterlockedDecrementError(checkStartTok); } + } else if (Token::Match(tok, "if ( ::| InterlockedDecrement ( & %name%")) { + const Token* condEnd = tok->next()->link(); + const Token* funcTok = tok->tokAt(2); + const Token* firstAccessTok = funcTok->str() == "::" ? funcTok->tokAt(4) : funcTok->tokAt(3); + if (condEnd && condEnd->next() && condEnd->next()->link()) { + const Token* ifEndTok = condEnd->next()->link(); + if (Token::Match(ifEndTok, "} return %name%")) { + const Token* secondAccessTok = ifEndTok->tokAt(2); + if (secondAccessTok->str() == firstAccessTok->str()) { + raceAfterInterlockedDecrementError(secondAccessTok); + } + } else if (Token::Match(ifEndTok, "} else { return %name%")) { + const Token* secondAccessTok = ifEndTok->tokAt(4); + if (secondAccessTok->str() == firstAccessTok->str()) { + raceAfterInterlockedDecrementError( secondAccessTok ); + } + } + } } } } diff --git a/test/testother.cpp b/test/testother.cpp index b7b18964d..f4c38037d 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -5971,6 +5971,77 @@ private: " destroy;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " } else {\n" + " return counter;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (::InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " } else {\n" + " return counter;\n" + " }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); + + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " }\n" + " return counter;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (::InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " }\n" + " return counter;\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " } else\n" + " return counter;\n" + " \n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); + + checkInterlockedDecrement( + "int f() {\n" + " int counter = 0;\n" + " if (::InterlockedDecrement(&counter) == 0) {\n" + " destroy();\n" + " return 0;\n" + " } else\n" + " return counter;\n" + " \n" + "}\n"); + ASSERT_EQUALS("[test.cpp:7]: (error) Race condition: non-interlocked access after InterlockedDecrement(). Use InterlockedDecrement() return value instead.\n", errout.str()); } void testUnusedLabel() {