CheckUninitVar: Assertion for '} while (' after 'do {..' in debug builds. Bail out in release builds to avoid segfaults.

This commit is contained in:
Daniel Marjamäki 2013-07-28 12:41:38 +02:00
parent 09f4d3732a
commit 2a1af1acda
3 changed files with 26 additions and 3 deletions

View File

@ -1349,8 +1349,20 @@ bool CheckUninitVar::checkScopeForVariable(const Scope* scope, const Token *tok,
tok = tok2->link(); tok = tok2->link();
// do-while => goto ")" // do-while => goto ")"
if (!forwhile) if (!forwhile) {
// Assert that the tokens are '} while ('
if (testrunner && !Token::simpleMatch(tok, "} while ("))
reportError(tok,Severity::debug,"","assertion failed '} while ('");
else
assert(Token::simpleMatch(tok, "} while ("));
// Goto ')'
tok = tok->linkAt(2); tok = tok->linkAt(2);
if (!tok)
// bailout : invalid code / bad tokenizer
break;
}
} }
} }

View File

@ -39,12 +39,12 @@ class Variable;
class CPPCHECKLIB CheckUninitVar : public Check { class CPPCHECKLIB CheckUninitVar : public Check {
public: public:
/** @brief This constructor is used when registering the CheckUninitVar */ /** @brief This constructor is used when registering the CheckUninitVar */
CheckUninitVar() : Check(myName()) CheckUninitVar() : Check(myName()), testrunner(false)
{ } { }
/** @brief This constructor is used when running checks. */ /** @brief This constructor is used when running checks. */
CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) CheckUninitVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) : Check(myName(), tokenizer, settings, errorLogger), testrunner(false)
{ } { }
/** @brief Run checks against the simplified token list */ /** @brief Run checks against the simplified token list */
@ -83,6 +83,9 @@ public:
void uninitvarError(const Token *tok, const std::string &varname); void uninitvarError(const Token *tok, const std::string &varname);
void uninitStructMemberError(const Token *tok, const std::string &membername); void uninitStructMemberError(const Token *tok, const std::string &membername);
/** testrunner: (don't abort() when assertion fails, just write error message) */
bool testrunner;
private: private:
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const { void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
CheckUninitVar c(0, settings, errorLogger); CheckUninitVar c(0, settings, errorLogger);

View File

@ -1970,6 +1970,7 @@ private:
// Check for redundant code.. // Check for redundant code..
CheckUninitVar checkuninitvar(&tokenizer, &settings, this); CheckUninitVar checkuninitvar(&tokenizer, &settings, this);
checkuninitvar.testrunner = true;
checkuninitvar.check(); checkuninitvar.check();
} }
@ -2873,6 +2874,13 @@ private:
"}"); "}");
ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Uninitialized variable: x\n", errout.str());
checkUninitVar2("void f() {\n" // #4911 - bad simplification => don't crash
" int a;\n"
" do { } a=do_something(); while (a);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Uninitialized variable: a\n"
"[test.cpp:3]: (debug) assertion failed '} while ('\n", errout.str());
checkUninitVar2("void f() {\n" checkUninitVar2("void f() {\n"
" int x;\n" " int x;\n"
" while (a) {\n" " while (a) {\n"