Fixed #5406 (crash inside valueFlowBeforeCondition() on files from kernel-git)

This commit is contained in:
Daniel Marjamäki 2014-01-27 06:18:42 +01:00
parent 2b8cf462c9
commit c8a1424e10
2 changed files with 101 additions and 71 deletions

View File

@ -686,72 +686,92 @@ static void compileExpression(Token *&tok, std::stack<Token*> &op)
compileComma(tok,op);
}
static Token * createAstAtToken(Token *tok)
{
if (Token::simpleMatch(tok,"for (")) {
Token *tok2 = tok->tokAt(2);
Token *init1 = 0;
const Token * const endPar = tok->next()->link();
while (tok2 && tok2 != endPar && tok2->str() != ";") {
if (tok2->str() == "<" && tok2->link()) {
tok2 = tok2->link();
if (!tok2)
break;
} else if (Token::Match(tok2, "%var% %op%|(|[|.|=|:|::") || Token::Match(tok2->previous(), "[;{}] %cop%|(")) {
init1 = tok2;
std::stack<Token *> operands;
compileExpression(tok2, operands);
if (tok2->str() == ";" || tok2->str() == ")")
break;
init1 = 0;
}
tok2 = tok2->next();
}
if (!tok2 || tok2->str() != ";") {
if (tok2 == endPar && init1) {
tok->next()->astOperand2(init1);
tok->next()->astOperand1(tok);
}
return tok2;
}
Token * const init = init1 ? init1 : tok2;
Token * const semicolon1 = tok2;
tok2 = tok2->next();
std::stack<Token *> operands2;
compileExpression(tok2, operands2);
Token * const semicolon2 = tok2;
tok2 = tok2->next();
std::stack<Token *> operands3;
compileExpression(tok2, operands3);
if (init != semicolon1)
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
tok2 = semicolon1->next();
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
tok2 = tok2->next();
if (tok2 != semicolon2)
semicolon2->astOperand1(const_cast<Token*>(tok2->astTop()));
tok2 = tok->linkAt(1);
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
tok2 = tok2->previous();
if (tok2 != semicolon2)
semicolon2->astOperand2(const_cast<Token*>(tok2->astTop()));
semicolon1->astOperand2(semicolon2);
tok->next()->astOperand1(tok);
tok->next()->astOperand2(semicolon1);
return tok->linkAt(1);
}
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|( !!{")) {
std::stack<Token *> operands;
Token * const tok1 = tok;
compileExpression(tok, operands);
Token * const endToken = tok;
// Compile inner expressions inside inner ({..})
for (tok = tok1; tok && tok != endToken; tok = tok ? tok->next() : NULL) {
if (!Token::simpleMatch(tok, "( {"))
continue;
const Token * const endToken2 = tok->linkAt(1);
for (; tok && tok != endToken && tok != endToken2; tok = tok ? tok->next() : NULL)
tok = createAstAtToken(tok);
}
return endToken ? endToken->previous() : NULL;
}
return tok;
}
void TokenList::createAst()
{
for (Token *tok = _front; tok; tok = tok ? tok->next() : NULL) {
if (Token::simpleMatch(tok,"for (")) {
Token *tok2 = tok->tokAt(2);
Token *init1 = 0;
const Token * const endPar = tok->next()->link();
while (tok2 && tok2 != endPar && tok2->str() != ";") {
if (tok2->str() == "<" && tok2->link()) {
tok2 = tok2->link();
if (!tok2)
break;
} else if (Token::Match(tok2, "%var% %op%|(|[|.|=|:|::") || Token::Match(tok2->previous(), "[;{}] %cop%|(")) {
init1 = tok2;
std::stack<Token *> operands;
compileExpression(tok2, operands);
if (tok2->str() == ";" || tok2->str() == ")")
break;
init1 = 0;
}
tok2 = tok2->next();
}
if (!tok2 || tok2->str() != ";") {
if (tok2 == endPar && init1) {
tok->next()->astOperand2(init1);
tok->next()->astOperand1(tok);
}
tok = tok2;
continue;
}
Token * const init = init1 ? init1 : tok2;
Token * const semicolon1 = tok2;
tok2 = tok2->next();
std::stack<Token *> operands2;
compileExpression(tok2, operands2);
Token * const semicolon2 = tok2;
tok2 = tok2->next();
std::stack<Token *> operands3;
compileExpression(tok2, operands3);
if (init != semicolon1)
semicolon1->astOperand1(const_cast<Token*>(init->astTop()));
tok2 = semicolon1->next();
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
tok2 = tok2->next();
if (tok2 != semicolon2)
semicolon2->astOperand1(const_cast<Token*>(tok2->astTop()));
tok2 = tok->linkAt(1);
while (tok2 != semicolon2 && !tok2->isName() && !tok2->isNumber())
tok2 = tok2->previous();
if (tok2 != semicolon2)
semicolon2->astOperand2(const_cast<Token*>(tok2->astTop()));
semicolon1->astOperand2(semicolon2);
tok->next()->astOperand1(tok);
tok->next()->astOperand2(semicolon1);
tok = tok->linkAt(1);
}
if (tok->str() == "return" || !tok->previous() || Token::Match(tok, "%var% %op%|(|[|.|=|::") || Token::Match(tok->previous(), "[;{}] %cop%|(")) {
std::stack<Token *> operands;
compileExpression(tok, operands);
}
tok = createAstAtToken(tok);
}
}

View File

@ -10065,13 +10065,18 @@ private:
// Create AST..
tokenList.createAst();
// Return stringified AST
std::string ret;
std::set<const Token *> astTop;
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (tok->astOperand1())
return tok->astTop()->astString();
if (tok->astOperand1() && astTop.find(tok->astTop()) == astTop.end()) {
astTop.insert(tok->astTop());
if (!ret.empty())
ret = ret + " ";
ret += tok->astTop()->astString();
}
}
// No AST found
return "";
return ret;
}
void astexpr() const { // simple expressions with arithmetical ops
@ -10108,6 +10113,11 @@ private:
TODO_ASSERT_EQUALS("fori1=current0=,iNUM<=i++;;(", "fori1=current0=,i<NUM=i++;;(", testAst("for(i = (1), current = 0; i <= (NUM); ++i)"));
ASSERT_EQUALS("foreachxy,((", testAst("for(each(x,y)){}")); // it's not well-defined what this ast should be
ASSERT_EQUALS("forab:(", testAst("for (int a : b);"));
// problems with multiple expressions
ASSERT_EQUALS("ax( whilex(", testAst("a(x) while (x)"));
ASSERT_EQUALS("ifx( i0= whilei(", testAst("if (x) { ({ int i = 0; while(i); }) };"));
ASSERT_EQUALS("ifx( BUG_ON{!( i0= whilei(", testAst("if (x) { BUG_ON(!({int i=0; while(i);})); }"));
}
void astpar() const { // parentheses
@ -10126,8 +10136,8 @@ private:
ASSERT_EQUALS("ab::r&c(=", testAst("a::b& r = (a::b&)c;")); // #5261
// ({..})
ASSERT_EQUALS("a{+d+", testAst("a+({b+c;})+d"));
ASSERT_EQUALS("a{d*+", testAst("a+({b+c;})*d"));
ASSERT_EQUALS("a{+d+ bc+", testAst("a+({b+c;})+d"));
ASSERT_EQUALS("a{d*+ bc+", testAst("a+({b+c;})*d"));
}
void astbrackets() const { // []
@ -10162,7 +10172,7 @@ private:
void asttemplate() const { // uninstantiated templates will have <,>,etc..
ASSERT_EQUALS("a(3==", testAst("a<int>()==3"));
ASSERT_EQUALS("ab(==", testAst("a == b<c>(); f();"));
ASSERT_EQUALS("ab(== f(", testAst("a == b<c>(); f();"));
}
};