Fix valueFlowBailoutIncompleteVar with ptr to ptr (refs #10045) (#5488)

This commit is contained in:
chrchr-github 2023-09-28 10:36:18 +02:00 committed by GitHub
parent 73d305ea46
commit 63b76d2266
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 36 additions and 22 deletions

View File

@ -1102,7 +1102,7 @@ void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass)
} }
// Set function call pointers // Set function call pointers
for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
if (tok->isName() && !tok->function() && tok->varId() == 0 && ((tok->astParent() && tok->astParent()->isComparisonOp()) || Token::Match(tok, "%name% [{(,)>;]")) && !isReservedName(tok->str())) { if (tok->isName() && !tok->function() && tok->varId() == 0 && ((tok->astParent() && tok->astParent()->isComparisonOp()) || Token::Match(tok, "%name% [{(,)>;]")) && !isReservedName(tok->str())) {
if (tok->next()->str() == ">" && !tok->next()->link()) if (tok->next()->str() == ">" && !tok->next()->link())
continue; continue;
@ -1121,7 +1121,7 @@ void SymbolDatabase::createSymbolDatabaseSetFunctionPointers(bool firstPass)
if (!function || (isTemplateArg && function->isConstructor())) if (!function || (isTemplateArg && function->isConstructor()))
continue; continue;
const_cast<Token *>(tok)->function(function); tok->function(function);
if (tok->next()->str() != "(") if (tok->next()->str() != "(")
const_cast<Function *>(function)->functionPointerUsage = tok; const_cast<Function *>(function)->functionPointerUsage = tok;
@ -1170,7 +1170,7 @@ void SymbolDatabase::createSymbolDatabaseSetTypePointers()
} }
// Set type pointers // Set type pointers
for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator()) if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
continue; continue;
@ -1179,7 +1179,7 @@ void SymbolDatabase::createSymbolDatabaseSetTypePointers()
const Type *type = findVariableType(tok->scope(), tok); const Type *type = findVariableType(tok->scope(), tok);
if (type) if (type)
const_cast<Token *>(tok)->type(type); // TODO: avoid const_cast tok->type(type);
} }
} }
@ -1241,7 +1241,7 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
if (!tok->isName() || tok->isKeyword() || tok->isStandardType()) if (!tok->isName() || tok->isKeyword() || tok->isStandardType())
continue; continue;
if (tok->varId()) if (tok->varId())
const_cast<Token*>(tok)->variable(getVariableFromVarId(tok->varId())); tok->variable(getVariableFromVarId(tok->varId()));
// Set Token::variable pointer for array member variable // Set Token::variable pointer for array member variable
// Since it doesn't point at a fixed location it doesn't have varid // Since it doesn't point at a fixed location it doesn't have varid
@ -1253,16 +1253,16 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) { if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) {
Token* membertok{}; Token* membertok{};
if (isArrayAccess) { if (isArrayAccess) {
membertok = const_cast<Token*>(tok->astParent()); membertok = tok->astParent();
while (Token::simpleMatch(membertok, "[")) while (Token::simpleMatch(membertok, "["))
membertok = membertok->astParent(); membertok = membertok->astParent();
if (membertok) if (membertok)
membertok = membertok->astOperand2(); membertok = membertok->astOperand2();
} }
else if (isDirectAccess) { else if (isDirectAccess) {
membertok = const_cast<Token*>(tok->astParent()->astOperand2()); membertok = tok->astParent()->astOperand2();
if (membertok == tok) { if (membertok == tok) {
Token* gptok = const_cast<Token*>(tok->astParent()->astParent()); Token* gptok = tok->astParent()->astParent();
if (Token::simpleMatch(gptok, ".")) // chained access if (Token::simpleMatch(gptok, ".")) // chained access
membertok = gptok->astOperand2(); membertok = gptok->astOperand2();
else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), ".")) else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), "."))
@ -1270,7 +1270,7 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
} }
} }
else { // isDerefAccess else { // isDerefAccess
membertok = const_cast<Token*>(tok->astParent()); membertok = tok->astParent();
while (Token::simpleMatch(membertok, "*")) while (Token::simpleMatch(membertok, "*"))
membertok = membertok->astParent(); membertok = membertok->astParent();
if (membertok) if (membertok)
@ -1394,15 +1394,15 @@ void SymbolDatabase::createSymbolDatabaseEnums()
} }
// find enumerators // find enumerators
for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
const bool isVariable = (tok->tokType() == Token::eVariable && !tok->variable()); const bool isVariable = (tok->tokType() == Token::eVariable && !tok->variable());
if (tok->tokType() != Token::eName && !isVariable) if (tok->tokType() != Token::eName && !isVariable)
continue; continue;
const Enumerator * enumerator = findEnumerator(tok, tokensThatAreNotEnumeratorValues); const Enumerator * enumerator = findEnumerator(tok, tokensThatAreNotEnumeratorValues);
if (enumerator) { if (enumerator) {
if (isVariable) if (isVariable)
const_cast<Token*>(tok)->varId(0); tok->varId(0);
const_cast<Token*>(tok)->enumerator(enumerator); tok->enumerator(enumerator);
} }
} }
} }
@ -1470,7 +1470,7 @@ void SymbolDatabase::createSymbolDatabaseIncompleteVars()
"volatile", "volatile",
"NULL", "NULL",
}; };
for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) { for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
const Scope * scope = tok->scope(); const Scope * scope = tok->scope();
if (!scope) if (!scope)
continue; continue;
@ -1492,7 +1492,7 @@ void SymbolDatabase::createSymbolDatabaseIncompleteVars()
continue; continue;
if (Token::Match(tok->next(), "::|.|(|{|:|%var%")) if (Token::Match(tok->next(), "::|.|(|{|:|%var%"))
continue; continue;
if (Token::Match(tok->next(), "&|&&|* )|,|%var%|const")) if (Token::Match(tok->next(), "&|&&|* *| *| )|,|%var%|const"))
continue; continue;
// Very likely a typelist // Very likely a typelist
if (Token::Match(tok->tokAt(-2), "%type% ,") || Token::Match(tok->next(), ", %type%")) if (Token::Match(tok->tokAt(-2), "%type% ,") || Token::Match(tok->next(), ", %type%"))
@ -1529,7 +1529,7 @@ void SymbolDatabase::createSymbolDatabaseIncompleteVars()
if (Token::simpleMatch(parent, "new")) if (Token::simpleMatch(parent, "new"))
continue; continue;
} }
const_cast<Token *>(tok)->isIncompleteVar(true); // TODO: avoid const_cast tok->isIncompleteVar(true);
} }
} }
@ -1806,13 +1806,13 @@ void SymbolDatabase::setArrayDimensionsUsingValueFlow()
SymbolDatabase::~SymbolDatabase() SymbolDatabase::~SymbolDatabase()
{ {
// Clear scope, type, function and variable pointers // Clear scope, type, function and variable pointers
for (const Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) { for (Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
const_cast<Token *>(tok)->scope(nullptr); tok->scope(nullptr);
const_cast<Token *>(tok)->type(nullptr); tok->type(nullptr);
const_cast<Token *>(tok)->function(nullptr); tok->function(nullptr);
const_cast<Token *>(tok)->variable(nullptr); tok->variable(nullptr);
const_cast<Token *>(tok)->enumerator(nullptr); tok->enumerator(nullptr);
const_cast<Token *>(tok)->setValueType(nullptr); tok->setValueType(nullptr);
} }
} }

View File

@ -5511,6 +5511,20 @@ private:
const Token* s4 = Token::findsimplematch(s3->next(), "string ["); const Token* s4 = Token::findsimplematch(s3->next(), "string [");
ASSERT(s4 && !s4->isIncompleteVar()); ASSERT(s4 && !s4->isIncompleteVar());
} }
{
GET_SYMBOL_DB("void f() {\n"
" T** p;\n"
" T*** q;\n"
" T** const * r;\n"
"}\n");
ASSERT(db && errout.str().empty());
const Token* p = Token::findsimplematch(tokenizer.tokens(), "p");
ASSERT(p && !p->isIncompleteVar());
const Token* q = Token::findsimplematch(p, "q");
ASSERT(q && !q->isIncompleteVar());
const Token* r = Token::findsimplematch(q, "r");
ASSERT(r && !r->isIncompleteVar());
}
} }
void enum1() { void enum1() {