Fix #9097 (Crash on thousands of "else ifs"s in gcc-avr package) (#1982)

* Fix #9097 (Crash on thousands of "else ifs"s in gcc-avr package)

* increase recursion count maximum to 512 because cppcheck was hitting the 256 limit

* 512 was too much for windows
This commit is contained in:
IOBYTE 2019-07-12 01:56:05 -04:00 committed by Daniel Marjamäki
parent 4a70208e0e
commit 74e3114a64
5 changed files with 56 additions and 3 deletions

View File

@ -159,6 +159,8 @@ void CheckLeakAutoVar::check()
if (scope->hasInlineOrLambdaFunction())
continue;
recursiveCount = 0;
// Empty variable info
VarInfo varInfo;
@ -236,6 +238,11 @@ void CheckLeakAutoVar::checkScope(const Token * const startToken,
VarInfo *varInfo,
std::set<unsigned int> notzero)
{
// The C++ standard suggests a minimum of 256 nested control statements
// but MSVC has a limit of 100. Cppcheck is hitting 256 when checking itself.
if (++recursiveCount > 384)
throw InternalError(startToken, "Internal limit: CheckLeakAutoVar::checkScope() Maximum recursive count of 384 reached.", InternalError::LIMIT);
std::map<unsigned int, VarInfo::AllocInfo> &alloctype = varInfo->alloctype;
std::map<unsigned int, std::string> &possibleUsage = varInfo->possibleUsage;
const std::set<unsigned int> conditionalAlloc(varInfo->conditionalAlloc);

View File

@ -95,12 +95,12 @@ public:
class CPPCHECKLIB CheckLeakAutoVar : public Check {
public:
/** This constructor is used when registering the CheckLeakAutoVar */
CheckLeakAutoVar() : Check(myName()) {
CheckLeakAutoVar() : Check(myName()), recursiveCount(0) {
}
/** This constructor is used when running checks. */
CheckLeakAutoVar(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
: Check(myName(), tokenizer, settings, errorLogger) {
: Check(myName(), tokenizer, settings, errorLogger), recursiveCount(0) {
}
void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) OVERRIDE {
@ -163,6 +163,8 @@ private:
std::string classInfo() const OVERRIDE {
return "Detect when a auto variable is allocated but not deallocated or deallocated twice.\n";
}
unsigned int recursiveCount;
};
/// @}
//---------------------------------------------------------------------------

View File

@ -49,6 +49,9 @@ InternalError::InternalError(const Token *tok, const std::string &errorMsg, Type
case INTERNAL:
id = "cppcheckError";
break;
case LIMIT:
id = "cppcheckLimit";
break;
}
}

View File

@ -54,7 +54,7 @@ namespace tinyxml2 {
/** @brief Simple container to be thrown when internal error is detected. */
struct InternalError {
enum Type {AST, SYNTAX, UNKNOWN_MACRO, INTERNAL};
enum Type {AST, SYNTAX, UNKNOWN_MACRO, INTERNAL, LIMIT};
InternalError(const Token *tok, const std::string &errorMsg, Type type = INTERNAL);
const Token *token;
std::string errorMessage;

View File

@ -23,6 +23,8 @@
#include "testsuite.h"
#include "tokenize.h"
#include <simplecpp.h>
#include <vector>
class TestLeakAutoVar : public TestFixture {
public:
@ -163,6 +165,8 @@ private:
TEST_CASE(inlineFunction); // #3989
TEST_CASE(smartPtrInContainer); // #8262
TEST_CASE(recursiveCountLimit); // #5872 #6157 #9097
}
void check(const char code[], bool cpp = false) {
@ -181,6 +185,32 @@ private:
c.runChecks(&tokenizer, &settings, this);
}
void checkP(const char code[], bool cpp = false) {
// Clear the error buffer..
errout.str("");
// Raw tokens..
std::vector<std::string> files(1, cpp?"test.cpp":"test.c");
std::istringstream istr(code);
const simplecpp::TokenList tokens1(istr, files, files[0]);
// Preprocess..
simplecpp::TokenList tokens2(files);
std::map<std::string, simplecpp::TokenList*> filedata;
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
// Tokenizer..
Tokenizer tokenizer(&settings, this);
tokenizer.createTokens(&tokens2);
tokenizer.simplifyTokens1("");
// Check for leaks..
CheckLeakAutoVar c;
settings.checkLibrary = true;
settings.addEnabled("information");
c.runChecks(&tokenizer, &settings, this);
}
void assign1() {
check("void f() {\n"
" char *p = malloc(10);\n"
@ -1776,6 +1806,17 @@ private:
ASSERT_EQUALS("", errout.str());
}
void recursiveCountLimit() { // #5872 #6157 #9097
ASSERT_THROW(checkP("#define ONE else if (0) { }\n"
"#define TEN ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE\n"
"#define HUN TEN TEN TEN TEN TEN TEN TEN TEN TEN TEN\n"
"#define THOU HUN HUN HUN HUN HUN HUN HUN HUN HUN HUN\n"
"void foo() {\n"
" if (0) { }\n"
" THOU\n"
"}"), InternalError);
}
};
REGISTER_TEST(TestLeakAutoVar)