#5592 - crash: gcc: testsuit: gcc.c-torture/compile/limits-declparen.c (Limit stack depth below createAst()
This commit is contained in:
parent
9bfc2b618b
commit
547803f581
2
Makefile
2
Makefile
|
@ -522,7 +522,7 @@ test/testtimer.o: test/testtimer.cpp lib/cxx11emu.h lib/timer.h lib/config.h tes
|
||||||
test/testtoken.o: test/testtoken.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/path.h lib/mathlib.h test/testutils.h lib/settings.h lib/standards.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h
|
test/testtoken.o: test/testtoken.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/path.h lib/mathlib.h test/testutils.h lib/settings.h lib/standards.h lib/timer.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -std=c++0x -c -o test/testtoken.o test/testtoken.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -std=c++0x -c -o test/testtoken.o test/testtoken.cpp
|
||||||
|
|
||||||
test/testtokenize.o: test/testtokenize.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/path.h lib/mathlib.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/settings.h lib/standards.h lib/timer.h
|
test/testtokenize.o: test/testtokenize.cpp lib/cxx11emu.h test/testsuite.h lib/errorlogger.h lib/config.h lib/suppressions.h test/redirect.h lib/library.h lib/path.h lib/mathlib.h lib/tokenize.h lib/tokenlist.h lib/token.h lib/valueflow.h lib/settings.h lib/standards.h lib/timer.h lib/preprocessor.h
|
||||||
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -std=c++0x -c -o test/testtokenize.o test/testtokenize.cpp
|
$(CXX) ${INCLUDE_FOR_TEST} $(CPPFLAGS) $(CFG) $(CXXFLAGS) -std=c++0x -c -o test/testtokenize.o test/testtokenize.cpp
|
||||||
|
|
||||||
test/testuninitvar.o: test/testuninitvar.cpp lib/cxx11emu.h lib/tokenize.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenlist.h lib/checkuninitvar.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/path.h lib/standards.h lib/timer.h test/testsuite.h test/redirect.h
|
test/testuninitvar.o: test/testuninitvar.cpp lib/cxx11emu.h lib/tokenize.h lib/errorlogger.h lib/config.h lib/suppressions.h lib/tokenlist.h lib/checkuninitvar.h lib/check.h lib/token.h lib/valueflow.h lib/mathlib.h lib/settings.h lib/library.h lib/path.h lib/standards.h lib/timer.h test/testsuite.h test/redirect.h
|
||||||
|
|
|
@ -392,11 +392,32 @@ static bool iscast(const Token *tok)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileUnaryOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &), std::stack<Token*> &op)
|
/*! Instances of this class are used to track the depth of the callstack. Simply pass the current instance down
|
||||||
|
* the callstack!
|
||||||
|
*/
|
||||||
|
class CallstackDepth {
|
||||||
|
public:
|
||||||
|
explicit CallstackDepth(unsigned _depth) :
|
||||||
|
depth(_depth) {
|
||||||
|
}
|
||||||
|
CallstackDepth(const CallstackDepth& rhs)
|
||||||
|
: depth(rhs.depth+1) {
|
||||||
|
}
|
||||||
|
bool exhausted() const {
|
||||||
|
return depth >= MAX_CALLSTACK_DEPTH;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
CallstackDepth& operator=(const CallstackDepth& rhs);
|
||||||
|
const unsigned depth;
|
||||||
|
static const unsigned MAX_CALLSTACK_DEPTH=300; // arbitrary limit: was sufficient to fix #5592 and run on cppcheck's own code
|
||||||
|
};
|
||||||
|
#define UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW if (callstackDepth.exhausted()) { return;}
|
||||||
|
|
||||||
|
static void compileUnaryOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &, const CallstackDepth callstackDepth), std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
Token *unaryop = tok;
|
Token *unaryop = tok;
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
f(tok,op);
|
f(tok,op, callstackDepth);
|
||||||
|
|
||||||
if (!op.empty()) {
|
if (!op.empty()) {
|
||||||
unaryop->astOperand1(op.top());
|
unaryop->astOperand1(op.top());
|
||||||
|
@ -405,12 +426,12 @@ static void compileUnaryOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &
|
||||||
op.push(unaryop);
|
op.push(unaryop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileBinOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &), std::stack<Token*> &op)
|
static void compileBinOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &, const CallstackDepth callstackDepth), std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
Token *binop = tok;
|
Token *binop = tok;
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
if (tok)
|
if (tok)
|
||||||
f(tok,op);
|
f(tok,op, callstackDepth);
|
||||||
|
|
||||||
// TODO: Should we check if op is empty.
|
// TODO: Should we check if op is empty.
|
||||||
// * Is it better to add assertion that it isn't?
|
// * Is it better to add assertion that it isn't?
|
||||||
|
@ -426,11 +447,12 @@ static void compileBinOp(Token *&tok, void (*f)(Token *&, std::stack<Token*> &),
|
||||||
op.push(binop);
|
op.push(binop);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileDot(Token *&tok, std::stack<Token*> &op);
|
static void compileDot(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth);
|
||||||
static void compileExpression(Token *&tok, std::stack<Token*> &op);
|
static void compileExpression(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth);
|
||||||
|
|
||||||
static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
static void compileTerm(Token *& tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return;
|
return;
|
||||||
if (Token::Match(tok, "L %str%|%char%"))
|
if (Token::Match(tok, "L %str%|%char%"))
|
||||||
|
@ -439,9 +461,9 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
op.push(tok);
|
op.push(tok);
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
} else if (Token::Match(tok, "+|-|~|*|&|!")) {
|
} else if (Token::Match(tok, "+|-|~|*|&|!")) {
|
||||||
compileUnaryOp(tok, compileDot, op);
|
compileUnaryOp(tok, compileDot, op, callstackDepth);
|
||||||
} else if (tok->str() == "return") {
|
} else if (tok->str() == "return") {
|
||||||
compileUnaryOp(tok, compileExpression, op);
|
compileUnaryOp(tok, compileExpression, op, callstackDepth);
|
||||||
} else if (tok->isName()) {
|
} else if (tok->isName()) {
|
||||||
const bool templatefunc = Token::Match(tok, "%var% <") && Token::simpleMatch(tok->linkAt(1), "> (");
|
const bool templatefunc = Token::Match(tok, "%var% <") && Token::simpleMatch(tok->linkAt(1), "> (");
|
||||||
if (Token::Match(tok->next(), "++|--")) { // post increment / decrement
|
if (Token::Match(tok->next(), "++|--")) { // post increment / decrement
|
||||||
|
@ -453,7 +475,7 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
op.push(tok);
|
op.push(tok);
|
||||||
tok = tok->next()->link()->next();
|
tok = tok->next()->link()->next();
|
||||||
if (!Token::simpleMatch(tok, "{"))
|
if (!Token::simpleMatch(tok, "{"))
|
||||||
compileTerm(tok,op);
|
compileTerm(tok,op, callstackDepth);
|
||||||
} else if (!Token::Match(tok->next(), "(|[") && !templatefunc) {
|
} else if (!Token::Match(tok->next(), "(|[") && !templatefunc) {
|
||||||
op.push(tok);
|
op.push(tok);
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
|
@ -473,7 +495,7 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
while (Token::Match(tok,"%var% %var%")) // example: sizeof(struct S)
|
while (Token::Match(tok,"%var% %var%")) // example: sizeof(struct S)
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
compileExpression(tok, op);
|
compileExpression(tok, op, callstackDepth);
|
||||||
if (!op.empty()) {
|
if (!op.empty()) {
|
||||||
tok1->astOperand2(op.top());
|
tok1->astOperand2(op.top());
|
||||||
op.pop();
|
op.pop();
|
||||||
|
@ -496,7 +518,7 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
|
|
||||||
if (pre) {
|
if (pre) {
|
||||||
// pre increment/decrement
|
// pre increment/decrement
|
||||||
compileUnaryOp(tok, compileDot, op);
|
compileUnaryOp(tok, compileDot, op, callstackDepth);
|
||||||
} else {
|
} else {
|
||||||
// post increment/decrement
|
// post increment/decrement
|
||||||
tok->astOperand1(op.top());
|
tok->astOperand1(op.top());
|
||||||
|
@ -508,7 +530,7 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
if (iscast(tok)) {
|
if (iscast(tok)) {
|
||||||
Token *unaryop = tok;
|
Token *unaryop = tok;
|
||||||
tok = tok->link()->next();
|
tok = tok->link()->next();
|
||||||
compileDot(tok,op);
|
compileDot(tok,op, callstackDepth);
|
||||||
|
|
||||||
if (!op.empty()) {
|
if (!op.empty()) {
|
||||||
unaryop->astOperand1(op.top());
|
unaryop->astOperand1(op.top());
|
||||||
|
@ -519,14 +541,14 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
// Parenthesized sub-expression
|
// Parenthesized sub-expression
|
||||||
Token *nextpar = tok->link()->next();
|
Token *nextpar = tok->link()->next();
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
compileExpression(tok,op);
|
compileExpression(tok,op, callstackDepth);
|
||||||
tok = nextpar;
|
tok = nextpar;
|
||||||
compileBinOp(tok, compileExpression, op);
|
compileBinOp(tok, compileExpression, op, callstackDepth);
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
} else {
|
} else {
|
||||||
// Parenthesized sub-expression
|
// Parenthesized sub-expression
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
compileExpression(tok,op);
|
compileExpression(tok,op, callstackDepth);
|
||||||
tok = tok->next();
|
tok = tok->next();
|
||||||
}
|
}
|
||||||
} else if (tok->str() == "{") {
|
} else if (tok->str() == "{") {
|
||||||
|
@ -535,175 +557,194 @@ static void compileTerm(Token *& tok, std::stack<Token*> &op)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileScope(Token *&tok, std::stack<Token*> &op)
|
static void compileScope(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileTerm(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileTerm(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "::") {
|
if (tok->str() == "::") {
|
||||||
if (tok->previous() && tok->previous()->isName())
|
if (tok->previous() && tok->previous()->isName())
|
||||||
compileBinOp(tok, compileTerm, op);
|
compileBinOp(tok, compileTerm, op, callstackDepth);
|
||||||
else
|
else
|
||||||
compileUnaryOp(tok, compileDot, op);
|
compileUnaryOp(tok, compileDot, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileParAndBrackets(Token *&tok, std::stack<Token*> &op)
|
static void compileParAndBrackets(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileScope(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileScope(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "[") {
|
if (tok->str() == "[") {
|
||||||
compileBinOp(tok, compileScope, op);
|
compileBinOp(tok, compileScope, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileDot(Token *&tok, std::stack<Token*> &op)
|
static void compileDot(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileParAndBrackets(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileParAndBrackets(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == ".") {
|
if (tok->str() == ".") {
|
||||||
compileBinOp(tok, compileParAndBrackets, op);
|
compileBinOp(tok, compileParAndBrackets, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileMulDiv(Token *&tok, std::stack<Token*> &op)
|
static void compileMulDiv(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileDot(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileDot(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "[*/%]")) {
|
if (Token::Match(tok, "[*/%]")) {
|
||||||
if (Token::Match(tok, "* [,)]"))
|
if (Token::Match(tok, "* [,)]"))
|
||||||
break;
|
break;
|
||||||
compileBinOp(tok, compileDot, op);
|
compileBinOp(tok, compileDot, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileAddSub(Token *&tok, std::stack<Token*> &op)
|
static void compileAddSub(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileMulDiv(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileMulDiv(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "+|-")) {
|
if (Token::Match(tok, "+|-")) {
|
||||||
compileBinOp(tok, compileMulDiv, op);
|
compileBinOp(tok, compileMulDiv, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileShift(Token *&tok, std::stack<Token*> &op)
|
static void compileShift(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileAddSub(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileAddSub(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "<<|>>")) {
|
if (Token::Match(tok, "<<|>>")) {
|
||||||
compileBinOp(tok, compileAddSub, op);
|
compileBinOp(tok, compileAddSub, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileRelComp(Token *&tok, std::stack<Token*> &op)
|
static void compileRelComp(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileShift(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileShift(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "<|<=|>=|>")) {
|
if (Token::Match(tok, "<|<=|>=|>")) {
|
||||||
compileBinOp(tok, compileShift, op);
|
compileBinOp(tok, compileShift, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileEqComp(Token *&tok, std::stack<Token*> &op)
|
static void compileEqComp(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileRelComp(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileRelComp(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "==|!=")) {
|
if (Token::Match(tok, "==|!=")) {
|
||||||
compileBinOp(tok, compileRelComp, op);
|
compileBinOp(tok, compileRelComp, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileAnd(Token *&tok, std::stack<Token*> &op)
|
static void compileAnd(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileEqComp(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileEqComp(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "&") {
|
if (tok->str() == "&") {
|
||||||
compileBinOp(tok, compileEqComp, op);
|
compileBinOp(tok, compileEqComp, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileXor(Token *&tok, std::stack<Token*> &op)
|
static void compileXor(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileAnd(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileAnd(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "^") {
|
if (tok->str() == "^") {
|
||||||
compileBinOp(tok, compileAnd, op);
|
compileBinOp(tok, compileAnd, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileOr(Token *&tok, std::stack<Token*> &op)
|
static void compileOr(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileXor(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileXor(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "|") {
|
if (tok->str() == "|") {
|
||||||
compileBinOp(tok, compileXor, op);
|
compileBinOp(tok, compileXor, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileLogicAnd(Token *&tok, std::stack<Token*> &op)
|
static void compileLogicAnd(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileOr(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileOr(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "&&") {
|
if (tok->str() == "&&") {
|
||||||
compileBinOp(tok, compileOr, op);
|
compileBinOp(tok, compileOr, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileLogicOr(Token *&tok, std::stack<Token*> &op)
|
static void compileLogicOr(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileLogicAnd(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileLogicAnd(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "||") {
|
if (tok->str() == "||") {
|
||||||
compileBinOp(tok, compileLogicAnd, op);
|
compileBinOp(tok, compileLogicAnd, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileTernaryOp(Token *&tok, std::stack<Token*> &op)
|
static void compileTernaryOp(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileLogicOr(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileLogicOr(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (Token::Match(tok, "[?:]")) {
|
if (Token::Match(tok, "[?:]")) {
|
||||||
compileBinOp(tok, compileLogicOr, op);
|
compileBinOp(tok, compileLogicOr, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileAssign(Token *&tok, std::stack<Token*> &op)
|
static void compileAssign(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileTernaryOp(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileTernaryOp(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == "=") {
|
if (tok->str() == "=") {
|
||||||
compileBinOp(tok, compileTernaryOp, op);
|
compileBinOp(tok, compileTernaryOp, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileComma(Token *&tok, std::stack<Token*> &op)
|
static void compileComma(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
compileAssign(tok,op);
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
compileAssign(tok,op, callstackDepth);
|
||||||
while (tok) {
|
while (tok) {
|
||||||
if (tok->str() == ",") {
|
if (tok->str() == ",") {
|
||||||
compileBinOp(tok, compileAssign, op);
|
compileBinOp(tok, compileAssign, op, callstackDepth);
|
||||||
} else break;
|
} else break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void compileExpression(Token *&tok, std::stack<Token*> &op)
|
static void compileExpression(Token *&tok, std::stack<Token*> &op, const CallstackDepth callstackDepth)
|
||||||
{
|
{
|
||||||
|
UGLY_BAILOUT_TO_AVOID_CALLSTACKOVERFLOW
|
||||||
|
if (callstackDepth.exhausted())
|
||||||
|
return; // ticket #5592
|
||||||
if (tok)
|
if (tok)
|
||||||
compileComma(tok,op);
|
compileComma(tok,op, callstackDepth);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Token * createAstAtToken(Token *tok)
|
static Token * createAstAtToken(Token *tok)
|
||||||
|
@ -720,7 +761,7 @@ static Token * createAstAtToken(Token *tok)
|
||||||
} else if (Token::Match(tok2, "%var% %op%|(|[|.|=|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) {
|
} else if (Token::Match(tok2, "%var% %op%|(|[|.|=|:|::") || Token::Match(tok2->previous(), "[(;{}] %cop%|(")) {
|
||||||
init1 = tok2;
|
init1 = tok2;
|
||||||
std::stack<Token *> operands;
|
std::stack<Token *> operands;
|
||||||
compileExpression(tok2, operands);
|
compileExpression(tok2, operands, CallstackDepth(0));
|
||||||
if (tok2->str() == ";" || tok2->str() == ")")
|
if (tok2->str() == ";" || tok2->str() == ")")
|
||||||
break;
|
break;
|
||||||
init1 = 0;
|
init1 = 0;
|
||||||
|
@ -740,12 +781,12 @@ static Token * createAstAtToken(Token *tok)
|
||||||
Token * const semicolon1 = tok2;
|
Token * const semicolon1 = tok2;
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
std::stack<Token *> operands2;
|
std::stack<Token *> operands2;
|
||||||
compileExpression(tok2, operands2);
|
compileExpression(tok2, operands2, CallstackDepth(0));
|
||||||
|
|
||||||
Token * const semicolon2 = tok2;
|
Token * const semicolon2 = tok2;
|
||||||
tok2 = tok2->next();
|
tok2 = tok2->next();
|
||||||
std::stack<Token *> operands3;
|
std::stack<Token *> operands3;
|
||||||
compileExpression(tok2, operands3);
|
compileExpression(tok2, operands3, CallstackDepth(0));
|
||||||
|
|
||||||
if (init != semicolon1)
|
if (init != semicolon1)
|
||||||
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
|
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
|
||||||
|
@ -776,7 +817,7 @@ static Token * createAstAtToken(Token *tok)
|
||||||
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) {
|
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) {
|
||||||
std::stack<Token *> operands;
|
std::stack<Token *> operands;
|
||||||
Token * const tok1 = tok;
|
Token * const tok1 = tok;
|
||||||
compileExpression(tok, operands);
|
compileExpression(tok, operands, CallstackDepth(0));
|
||||||
Token * const endToken = tok;
|
Token * const endToken = tok;
|
||||||
if (endToken == tok1)
|
if (endToken == tok1)
|
||||||
return tok1;
|
return tok1;
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
|
#include "preprocessor.h" // usually tests here should not use preprocessor...
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
|
||||||
|
@ -561,6 +562,8 @@ private:
|
||||||
|
|
||||||
TEST_CASE(simplifyMathExpressions); //ticket #1620
|
TEST_CASE(simplifyMathExpressions); //ticket #1620
|
||||||
|
|
||||||
|
TEST_CASE(compileLimits); // #5592 crash: gcc: testsuit: gcc.c-torture/compile/limits-declparen.c
|
||||||
|
|
||||||
// AST data
|
// AST data
|
||||||
TEST_CASE(astexpr);
|
TEST_CASE(astexpr);
|
||||||
TEST_CASE(astpar);
|
TEST_CASE(astpar);
|
||||||
|
@ -10145,6 +10148,7 @@ private:
|
||||||
ASSERT_EQUALS(code6, tokenizeAndStringify(code6));
|
ASSERT_EQUALS(code6, tokenizeAndStringify(code6));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string testAst(const char code[]) {
|
static std::string testAst(const char code[]) {
|
||||||
// tokenize given code..
|
// tokenize given code..
|
||||||
const Settings settings;
|
const Settings settings;
|
||||||
|
@ -10296,6 +10300,36 @@ private:
|
||||||
ASSERT_EQUALS("publica::b::", testAst("class C : public ::a::b<bool> { };"));
|
ASSERT_EQUALS("publica::b::", testAst("class C : public ::a::b<bool> { };"));
|
||||||
ASSERT_EQUALS("f( abc+=", testAst("struct A : public B<C*> { void f() { a=b+c; } };"));
|
ASSERT_EQUALS("f( abc+=", testAst("struct A : public B<C*> { void f() { a=b+c; } };"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void compileLimits() {
|
||||||
|
const char raw_code[] = "#define PTR1 (* (* (* (* (* (* (* (* (* (*\n"
|
||||||
|
"#define PTR2 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1 PTR1\n"
|
||||||
|
"#define PTR3 PTR2 PTR2 PTR2 PTR2 PTR2 PTR2 PTR2 PTR2 PTR2 PTR2\n"
|
||||||
|
"#define PTR4 PTR3 PTR3 PTR3 PTR3 PTR3 PTR3 PTR3 PTR3 PTR3 PTR3\n"
|
||||||
|
"#define PTR5 PTR4 PTR4 PTR4 PTR4 PTR4 PTR4 PTR4 PTR4 PTR4 PTR4\n"
|
||||||
|
"#define PTR6 PTR5 PTR5 PTR5 PTR5 PTR5 PTR5 PTR5 PTR5 PTR5 PTR5\n"
|
||||||
|
"\n"
|
||||||
|
"#define RBR1 ) ) ) ) ) ) ) ) ) )\n"
|
||||||
|
"#define RBR2 RBR1 RBR1 RBR1 RBR1 RBR1 RBR1 RBR1 RBR1 RBR1 RBR1\n"
|
||||||
|
"#define RBR3 RBR2 RBR2 RBR2 RBR2 RBR2 RBR2 RBR2 RBR2 RBR2 RBR2\n"
|
||||||
|
"#define RBR4 RBR3 RBR3 RBR3 RBR3 RBR3 RBR3 RBR3 RBR3 RBR3 RBR3\n"
|
||||||
|
"#define RBR5 RBR4 RBR4 RBR4 RBR4 RBR4 RBR4 RBR4 RBR4 RBR4 RBR4\n"
|
||||||
|
"#define RBR6 RBR5 RBR5 RBR5 RBR5 RBR5 RBR5 RBR5 RBR5 RBR5 RBR5\n"
|
||||||
|
"\n"
|
||||||
|
"int PTR4 q4_var RBR4 = 0;\n";
|
||||||
|
|
||||||
|
// Preprocess file..
|
||||||
|
Settings settings;
|
||||||
|
Preprocessor preprocessor(&settings);
|
||||||
|
std::list<std::string> configurations;
|
||||||
|
std::string filedata = "";
|
||||||
|
std::istringstream fin(raw_code);
|
||||||
|
preprocessor.preprocess(fin, filedata, configurations, "", settings._includePaths);
|
||||||
|
const std::string code = preprocessor.getcode(filedata, "", "");
|
||||||
|
|
||||||
|
tokenizeAndStringify(code.c_str()); // just survive...
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestTokenizer)
|
REGISTER_TEST(TestTokenizer)
|
||||||
|
|
Loading…
Reference in New Issue