Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 68 additions & 66 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1565,82 +1565,84 @@ namespace {
};
using ExprIdMap = std::map<ExprIdKey, nonneg int>;
void setParentExprId(Token* tok, ExprIdMap& exprIdMap, nonneg int &id) {
if (!tok->astParent() || tok->astParent()->isControlFlowKeyword())
return;
const Token* op1 = tok->astParent()->astOperand1();
if (op1 && op1->exprId() == 0 && !Token::Match(op1, "[{[]"))
return;
const Token* op2 = tok->astParent()->astOperand2();
if (op2 && op2->exprId() == 0 &&
!((tok->astParent()->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->astParent()->isAssignmentOp()) ||
isLambdaCaptureList(op2) ||
(op2->str() == "(" && isLambdaCaptureList(op2->astOperand1())) ||
Token::simpleMatch(op2, "{ }")))
return;
for (;;) {
if (!tok->astParent() || tok->astParent()->isControlFlowKeyword())
break;
const Token* op1 = tok->astParent()->astOperand1();
if (op1 && op1->exprId() == 0 && !Token::Match(op1, "[{[]"))
break;
const Token* op2 = tok->astParent()->astOperand2();
if (op2 && op2->exprId() == 0 &&
!((tok->astParent()->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->astParent()->isAssignmentOp()) ||
isLambdaCaptureList(op2) ||
(op2->str() == "(" && isLambdaCaptureList(op2->astOperand1())) ||
Token::simpleMatch(op2, "{ }")))
break;

if (tok->astParent()->isExpandedMacro() || Token::Match(tok->astParent(), "++|--")) {
tok->astParent()->exprId(id);
++id;
setParentExprId(tok->astParent(), exprIdMap, id);
return;
}
if (tok->astParent()->isExpandedMacro() || Token::Match(tok->astParent(), "++|--")) {
tok->astParent()->exprId(id);
++id;
tok = tok->astParent();
continue;
}

ExprIdKey key;
key.parentOp = tok->astParent()->str();
key.operand1 = op1 ? op1->exprId() : 0;
key.operand2 = op2 ? op2->exprId() : 0;
ExprIdKey key;
key.parentOp = tok->astParent()->str();
key.operand1 = op1 ? op1->exprId() : 0;
key.operand2 = op2 ? op2->exprId() : 0;

if (tok->astParent()->isCast() && tok->astParent()->str() == "(") {
const Token* typeStartToken;
const Token* typeEndToken;
if (tok->astParent()->astOperand2()) {
typeStartToken = tok->astParent()->astOperand1();
typeEndToken = tok;
} else {
typeStartToken = tok->astParent()->next();
typeEndToken = tok->astParent()->link();
}
std::string type;
for (const Token* t = typeStartToken; t != typeEndToken; t = t->next()) {
type += " " + t->str();
if (tok->astParent()->isCast() && tok->astParent()->str() == "(") {
const Token* typeStartToken;
const Token* typeEndToken;
if (tok->astParent()->astOperand2()) {
typeStartToken = tok->astParent()->astOperand1();
typeEndToken = tok;
} else {
typeStartToken = tok->astParent()->next();
typeEndToken = tok->astParent()->link();
}
std::string type;
for (const Token* t = typeStartToken; t != typeEndToken; t = t->next()) {
type += " " + t->str();
}
key.parentOp += type;
}
key.parentOp += type;
}

for (const auto& ref: followAllReferences(op1)) {
if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
key.operand1 = ref.token->exprId();
break;
for (const auto& ref: followAllReferences(op1)) {
if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
key.operand1 = ref.token->exprId();
break;
}
}
}
for (const auto& ref: followAllReferences(op2)) {
if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
key.operand2 = ref.token->exprId();
break;
for (const auto& ref: followAllReferences(op2)) {
if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
key.operand2 = ref.token->exprId();
break;
}
}
}

if (key.operand1 > key.operand2 && key.operand2 &&
Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) {
// In C++ the order of operands of + might matter
if (!tok->isCpp() ||
key.parentOp != "+" ||
!tok->astParent()->valueType() ||
tok->astParent()->valueType()->isIntegral() ||
tok->astParent()->valueType()->isFloat() ||
tok->astParent()->valueType()->pointer > 0)
std::swap(key.operand1, key.operand2);
}
if (key.operand1 > key.operand2 && key.operand2 &&
Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) {
// In C++ the order of operands of + might matter
if (!tok->isCpp() ||
key.parentOp != "+" ||
!tok->astParent()->valueType() ||
tok->astParent()->valueType()->isIntegral() ||
tok->astParent()->valueType()->isFloat() ||
tok->astParent()->valueType()->pointer > 0)
std::swap(key.operand1, key.operand2);
}

const auto it = exprIdMap.find(key);
if (it == exprIdMap.end()) {
exprIdMap[key] = id;
tok->astParent()->exprId(id);
++id;
} else {
tok->astParent()->exprId(it->second);
const auto it = exprIdMap.find(key);
if (it == exprIdMap.end()) {
exprIdMap[key] = id;
tok->astParent()->exprId(id);
++id;
} else {
tok->astParent()->exprId(it->second);
}
tok = tok->astParent();
}
setParentExprId(tok->astParent(), exprIdMap, id);
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/tokenize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4838,7 +4838,7 @@ void Tokenizer::setVarIdPass1()
}

// function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) {
if (scopeStack.top().isExecutable && !scopeStack.top().isStructInit && Token::Match(tok, "%name% [,)[]")) {
bool par = false;
const Token* start;
Token* end;
Expand Down
19 changes: 19 additions & 0 deletions test/cli/performance_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,3 +219,22 @@ def test_slow_many_scopes(tmpdir):
return EXIT_SUCCESS;
}""")
cppcheck([filename]) # should not take more than ~1 second

@pytest.mark.timeout(20)
def test_crash_array_in_namespace(tmpdir):
# 12847
filename = os.path.join(tmpdir, 'hang.cpp')
with open(filename, 'wt') as f:
f.write(r"""
#define ROW A, A, A, A, A, A, A, A,
#define ROW8 ROW ROW ROW ROW ROW ROW ROW ROW
#define ROW64 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8 ROW8
#define ROW512 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64 ROW64
#define ROW4096 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512 ROW512
namespace N {
static const char A = 'a';
const char a[] = {
ROW4096 ROW4096 ROW4096 ROW4096
};
}""")
cppcheck([filename]) # should not take more than ~5 seconds