* Fix #10720 Hang/Crash with big variadic template * Fix CI
This commit is contained in:
parent
77717f73fd
commit
9c184462ad
2
Makefile
2
Makefile
|
@ -805,7 +805,7 @@ test/testsimplifytokens.o: test/testsimplifytokens.cpp lib/check.h lib/color.h l
|
|||
test/testsimplifytypedef.o: test/testsimplifytypedef.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifytypedef.cpp
|
||||
|
||||
test/testsimplifyusing.o: test/testsimplifyusing.cpp lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
|
||||
test/testsimplifyusing.o: test/testsimplifyusing.cpp externals/simplecpp/simplecpp.h lib/check.h lib/color.h lib/config.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h
|
||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CXXFLAGS) -c -o $@ test/testsimplifyusing.cpp
|
||||
|
||||
test/testsingleexecutor.o: test/testsingleexecutor.cpp cli/executor.h cli/singleexecutor.h lib/analyzerinfo.h lib/check.h lib/color.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/errortypes.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/vfvalue.h test/fixture.h test/helpers.h test/redirect.h
|
||||
|
|
|
@ -2760,11 +2760,23 @@ static bool scopesMatch(const std::string &scope1, const std::string &scope2, co
|
|||
return false;
|
||||
}
|
||||
|
||||
static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
|
||||
unsigned int dist = 0;
|
||||
const Token* tok = tok1;
|
||||
while (tok != tok2) {
|
||||
++dist;
|
||||
tok = tok->next();
|
||||
}
|
||||
return dist;
|
||||
};
|
||||
|
||||
bool Tokenizer::simplifyUsing()
|
||||
{
|
||||
if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
|
||||
return false;
|
||||
|
||||
const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace
|
||||
|
||||
bool substitute = false;
|
||||
ScopeInfo3 scopeInfo;
|
||||
ScopeInfo3 *currentScope = &scopeInfo;
|
||||
|
@ -3006,6 +3018,12 @@ bool Tokenizer::simplifyUsing()
|
|||
} else if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, nullptr))
|
||||
continue;
|
||||
|
||||
const auto nReplace = tokDistance(start, usingEnd);
|
||||
if (nReplace > maxReplacementTokens) {
|
||||
simplifyUsingError(usingStart, usingEnd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// remove the qualification
|
||||
std::string fullScope = scope;
|
||||
std::string removed;
|
||||
|
@ -3187,18 +3205,7 @@ bool Tokenizer::simplifyUsing()
|
|||
}
|
||||
} else {
|
||||
skip = true;
|
||||
if (mSettings->debugwarnings && mErrorLogger) {
|
||||
std::string str;
|
||||
for (Token *tok3 = usingStart; tok3 && tok3 != usingEnd; tok3 = tok3->next()) {
|
||||
if (!str.empty())
|
||||
str += ' ';
|
||||
str += tok3->str();
|
||||
}
|
||||
str += " ;";
|
||||
std::list<const Token *> callstack(1, usingStart);
|
||||
mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
|
||||
"Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
|
||||
}
|
||||
simplifyUsingError(usingStart, usingEnd);
|
||||
}
|
||||
tok1 = after;
|
||||
}
|
||||
|
@ -3233,6 +3240,22 @@ bool Tokenizer::simplifyUsing()
|
|||
return substitute;
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
|
||||
{
|
||||
if (mSettings->debugwarnings && mErrorLogger) {
|
||||
std::string str;
|
||||
for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
|
||||
if (!str.empty())
|
||||
str += ' ';
|
||||
str += tok->str();
|
||||
}
|
||||
str += " ;";
|
||||
std::list<const Token *> callstack(1, usingStart);
|
||||
mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
|
||||
"Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
|
||||
}
|
||||
}
|
||||
|
||||
bool Tokenizer::createTokens(std::istream &code,
|
||||
const std::string& FileName)
|
||||
{
|
||||
|
|
|
@ -280,6 +280,7 @@ public:
|
|||
/**
|
||||
*/
|
||||
bool simplifyUsing();
|
||||
void simplifyUsingError(const Token* usingStart, const Token* usingEnd);
|
||||
|
||||
/** Simplify useless C++ empty namespaces, like: 'namespace %name% { }'*/
|
||||
void simplifyEmptyNamespaces();
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "token.h"
|
||||
#include "tokenize.h"
|
||||
|
||||
#include <simplecpp.h>
|
||||
|
||||
#include <sstream> // IWYU pragma: keep
|
||||
#include <string>
|
||||
|
||||
|
@ -92,13 +94,14 @@ private:
|
|||
TEST_CASE(simplifyUsing10172);
|
||||
TEST_CASE(simplifyUsing10173);
|
||||
TEST_CASE(simplifyUsing10335);
|
||||
TEST_CASE(simplifyUsing10720);
|
||||
|
||||
TEST_CASE(scopeInfo1);
|
||||
TEST_CASE(scopeInfo2);
|
||||
}
|
||||
|
||||
#define tok(...) tok_(__FILE__, __LINE__, __VA_ARGS__)
|
||||
std::string tok_(const char* file, int line, const char code[], cppcheck::Platform::Type type = cppcheck::Platform::Type::Native, bool debugwarnings = true) {
|
||||
std::string tok_(const char* file, int line, const char code[], cppcheck::Platform::Type type = cppcheck::Platform::Type::Native, bool debugwarnings = true, bool preprocess = false) {
|
||||
errout.str("");
|
||||
|
||||
settings0.certainty.enable(Certainty::inconclusive);
|
||||
|
@ -106,6 +109,18 @@ private:
|
|||
PLATFORM(settings0.platform, type);
|
||||
Tokenizer tokenizer(&settings0, this);
|
||||
|
||||
if (preprocess) {
|
||||
std::vector<std::string> files{ "test.cpp" };
|
||||
std::istringstream istr(code);
|
||||
const simplecpp::TokenList tokens1(istr, files, files[0]);
|
||||
|
||||
simplecpp::TokenList tokens2(files);
|
||||
std::map<std::string, simplecpp::TokenList*> filedata;
|
||||
simplecpp::preprocess(tokens2, tokens1, files, filedata, simplecpp::DUI());
|
||||
|
||||
tokenizer.createTokens(std::move(tokens2));
|
||||
}
|
||||
|
||||
std::istringstream istr(code);
|
||||
ASSERT_LOC(tokenizer.tokenize(istr, "test.cpp"), file, line);
|
||||
|
||||
|
@ -1346,6 +1361,17 @@ private:
|
|||
ASSERT_EQUALS(exp, tok(code));
|
||||
}
|
||||
|
||||
void simplifyUsing10720() {
|
||||
const char code[] = "template <typename... Ts>\n"
|
||||
"struct S {};\n"
|
||||
"#define STAMP(thiz, prev) using thiz = S<prev, prev, prev, prev, prev, prev, prev, prev, prev, prev>;\n"
|
||||
"STAMP(A, int);\n"
|
||||
"STAMP(B, A);\n"
|
||||
"STAMP(C, B);\n";
|
||||
tok(code, cppcheck::Platform::Type::Native, /*debugwarnings*/ true, /*preprocess*/ true);
|
||||
ASSERT_EQUALS(errout.str().compare(0, 64, "[test.cpp:6]: (debug) Failed to parse 'using C = S < S < S < int"), 0);
|
||||
}
|
||||
|
||||
void scopeInfo1() {
|
||||
const char code[] = "struct A {\n"
|
||||
" enum class Mode { UNKNOWN, ENABLED, NONE, };\n"
|
||||
|
|
Loading…
Reference in New Issue