From ba0859e838aedc04e0fcf0fcc8f814e5229f5f9a Mon Sep 17 00:00:00 2001 From: Alexander Mai Date: Sat, 5 Dec 2015 20:55:26 +0100 Subject: [PATCH] #6981 crash in checkvaarg.cpp (with possible fix). Avoid segfault. Add SymbolDatabase::validate() to allow validating smyboldatabase --- lib/checkvaarg.cpp | 2 ++ lib/symboldatabase.cpp | 19 +++++++++++++++++++ lib/symboldatabase.h | 10 ++++++++++ lib/tokenize.cpp | 2 ++ lib/valueflow.cpp | 2 +- test/testautovariables.cpp | 3 +-- test/testvaarg.cpp | 10 ++++++++++ 7 files changed, 45 insertions(+), 3 deletions(-) diff --git a/lib/checkvaarg.cpp b/lib/checkvaarg.cpp index 385479411..18e9219d8 100644 --- a/lib/checkvaarg.cpp +++ b/lib/checkvaarg.cpp @@ -40,6 +40,8 @@ void CheckVaarg::va_start_argument() for (std::size_t i = 0; i < functions; ++i) { const Scope* scope = symbolDatabase->functionScopes[i]; const Function* function = scope->function; + if (!function) + continue; for (const Token* tok = scope->classStart->next(); tok != scope->classEnd; tok = tok->next()) { if (!tok->scope()->isExecutable()) tok = tok->scope()->classEnd; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 86b75dec4..51c5f33da 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1425,6 +1425,25 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const return false; } +void SymbolDatabase::validate() const +{ + const std::size_t functions = functionScopes.size(); + for (std::size_t i = 0; i < functions; ++i) { + const Scope* scope = functionScopes[i]; + if (scope->isExecutable()) { + const Function* function = scope->function; + if (!function) { + cppcheckError(nullptr); + } + } + } +} + +void SymbolDatabase::cppcheckError(const Token *tok) const +{ + throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL); +} + bool Variable::isPointerArray() const { return isArray() && nameToken() && nameToken()->previous() && (nameToken()->previous()->str() == "*"); diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 2c65013eb..330a2e8b7 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -1007,6 +1007,11 @@ public: bool isCPP() const; + /* + * @brief Do a sanity check + */ + void validate() const; + /** Set valuetype in provided tokenlist */ static void setValueTypeInTokenList(Token *tokens); @@ -1022,6 +1027,11 @@ private: const Type *findTypeInNested(const Token *tok, const Scope *startScope) const; const Scope *findNamespace(const Token * tok, const Scope * scope) const; Function *findFunctionInScope(const Token *func, const Scope *ns); + /** + * Send error message to error logger about internal bug. + * @param tok the token that this bug concerns. + */ + void cppcheckError(const Token *tok) const __attribute__((noreturn)); /** Whether iName is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en.cppreference.com/w/cpp/keyword*/ bool isReservedName(const std::string& iName) const; diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index f6cb2aaa0..7c47d0c1a 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -9840,6 +9840,8 @@ void Tokenizer::createSymbolDatabase() { if (!_symbolDatabase) _symbolDatabase = new SymbolDatabase(this, _settings, _errorLogger); + if (_settings->debug) + _symbolDatabase->validate(); } void Tokenizer::deleteSymbolDatabase() diff --git a/lib/valueflow.cpp b/lib/valueflow.cpp index ca49fa001..cf7acd8f6 100644 --- a/lib/valueflow.cpp +++ b/lib/valueflow.cpp @@ -1982,7 +1982,7 @@ static void valueFlowForLoopSimplify(Token * const bodyStart, const unsigned int break; if (parent->str() == "?") { if (parent->astOperand2() != p) - parent = NULL; + parent = nullptr; break; } } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 440dfbed1..18f51fd49 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -446,7 +446,7 @@ private: void testautovar_return2() { check("class Fred {\n" - " int* func1()\n" + " int* func1();\n" "}\n" "int* Fred::func1()\n" "{\n" @@ -876,7 +876,6 @@ private: " return foo();\n" "}"); ASSERT_EQUALS("", errout.str()); - // Don't crash with function in unknown scope (#4076) check("X& a::Bar() {}" "X& foo() {" diff --git a/test/testvaarg.cpp b/test/testvaarg.cpp index 4ad8f0633..5961559e4 100644 --- a/test/testvaarg.cpp +++ b/test/testvaarg.cpp @@ -50,6 +50,7 @@ private: TEST_CASE(va_end_missing); TEST_CASE(va_list_usedBeforeStarted); TEST_CASE(va_start_subsequentCalls); + TEST_CASE(unknownFunctionScope); } void wrongParameterTo_va_start() { @@ -227,6 +228,15 @@ private: "}"); ASSERT_EQUALS("", errout.str()); } + + void unknownFunctionScope() { + check("void BG_TString::Format() {\n" + " BG_TChar * f;\n" + " va_start(args,f);\n" + " BG_TString result(f);\n" + "}"); + ASSERT_EQUALS("", errout.str()); + } }; REGISTER_TEST(TestVaarg)