Skip to content

Commit db6dfa2

Browse files
IOBYTEdanmar
authored andcommitted
Fixed cppcheck-opensource#7195 (crash: valueFlowSwitchVariable())
1 parent 599327b commit db6dfa2

3 files changed

Lines changed: 137 additions & 19 deletions

File tree

lib/symboldatabase.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -443,9 +443,18 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
443443
function.arg = function.argDef;
444444

445445
// out of line function
446-
if (Token::simpleMatch(end, ") ;")) {
446+
if (Token::Match(end, ") const| &|&&| ;")) {
447447
// find the function implementation later
448448
tok = end->next();
449+
if (tok->str() == "const")
450+
tok = tok->next();
451+
if (tok->str() == "&") {
452+
function.hasLvalRefQualifier(true);
453+
tok = tok->next();
454+
} else if (tok->str() == "&&") {
455+
function.hasRvalRefQualifier(true);
456+
tok = tok->next();
457+
}
449458

450459
scope->addFunction(function);
451460
}
@@ -575,6 +584,16 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
575584
function.throwArg = end->tokAt(arg);
576585

577586
function.isThrow(true);
587+
} else if (Token::Match(end, ") const| &|&&|")) {
588+
int arg = 1;
589+
590+
if (end->strAt(arg) == "const")
591+
arg++;
592+
593+
if (end->strAt(arg) == "&")
594+
function.hasLvalRefQualifier(true);
595+
else if (end->strAt(arg) == "&&")
596+
function.hasRvalRefQualifier(true);
578597
}
579598

580599
// find start of function '{'
@@ -670,7 +689,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
670689
}
671690

672691
// has body?
673-
if (Token::Match(scopeBegin, "{|:")) {
692+
if (Token::Match(scopeBegin, "&|&&| {|:")) {
674693
tok = funcStart;
675694

676695
// class function
@@ -1388,6 +1407,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
13881407
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
13891408
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
13901409
Token::Match(tok2, ": ::| %name% (|::|<|{") ||
1410+
Token::Match(tok2, "const| &|&&| ;|{") ||
13911411
Token::Match(tok2, "= delete|default ;") ||
13921412
Token::Match(tok2, "const| noexcept {|:|;|=") ||
13931413
(Token::Match(tok2, "const| noexcept|throw (") &&
@@ -1763,6 +1783,9 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok,
17631783
void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart)
17641784
{
17651785
const bool destructor((*tok)->previous()->str() == "~");
1786+
const bool has_const(argStart->link()->strAt(1) == "const");
1787+
const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&");
1788+
const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&");
17661789
const Token *tok1;
17671790
// skip class/struct name
17681791
if (destructor)
@@ -1888,8 +1911,9 @@ void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const To
18881911
// normal function?
18891912
if ((*tok)->next()->link()) {
18901913
const bool hasConstKeyword = (*tok)->next()->link()->next()->str() == "const";
1891-
if ((func->isConst() && hasConstKeyword) ||
1892-
(!func->isConst() && !hasConstKeyword)) {
1914+
if ((func->isConst() == hasConstKeyword) &&
1915+
(func->hasLvalRefQualifier() == lval) &&
1916+
(func->hasRvalRefQualifier() == rval)) {
18931917
func->hasBody(true);
18941918
}
18951919
}
@@ -2303,6 +2327,8 @@ void SymbolDatabase::printOut(const char *title) const
23032327
std::cout << " isNoExcept: " << func->isNoExcept() << std::endl;
23042328
std::cout << " isThrow: " << func->isThrow() << std::endl;
23052329
std::cout << " isOperator: " << func->isOperator() << std::endl;
2330+
std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
2331+
std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
23062332
std::cout << " attributes:";
23072333
if (func->isAttributeConst())
23082334
std::cout << " const ";

lib/symboldatabase.h

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -593,21 +593,23 @@ class CPPCHECKLIB Variable {
593593
class CPPCHECKLIB Function {
594594
/** @brief flags mask used to access specific bit. */
595595
enum {
596-
fHasBody = (1 << 0), /** @brief has implementation */
597-
fIsInline = (1 << 1), /** @brief implementation in class definition */
598-
fIsConst = (1 << 2), /** @brief is const */
599-
fIsVirtual = (1 << 3), /** @brief is virtual */
600-
fIsPure = (1 << 4), /** @brief is pure virtual */
601-
fIsStatic = (1 << 5), /** @brief is static */
602-
fIsStaticLocal = (1 << 6), /** @brief is static local */
603-
fIsExtern = (1 << 7), /** @brief is extern */
604-
fIsFriend = (1 << 8), /** @brief is friend */
605-
fIsExplicit = (1 << 9), /** @brief is explicit */
606-
fIsDefault = (1 << 10), /** @brief is default */
607-
fIsDelete = (1 << 11), /** @brief is delete */
608-
fIsNoExcept = (1 << 12), /** @brief is noexcept */
609-
fIsThrow = (1 << 13), /** @brief is throw */
610-
fIsOperator = (1 << 14) /** @brief is operator */
596+
fHasBody = (1 << 0), /** @brief has implementation */
597+
fIsInline = (1 << 1), /** @brief implementation in class definition */
598+
fIsConst = (1 << 2), /** @brief is const */
599+
fIsVirtual = (1 << 3), /** @brief is virtual */
600+
fIsPure = (1 << 4), /** @brief is pure virtual */
601+
fIsStatic = (1 << 5), /** @brief is static */
602+
fIsStaticLocal = (1 << 6), /** @brief is static local */
603+
fIsExtern = (1 << 7), /** @brief is extern */
604+
fIsFriend = (1 << 8), /** @brief is friend */
605+
fIsExplicit = (1 << 9), /** @brief is explicit */
606+
fIsDefault = (1 << 10), /** @brief is default */
607+
fIsDelete = (1 << 11), /** @brief is delete */
608+
fIsNoExcept = (1 << 12), /** @brief is noexcept */
609+
fIsThrow = (1 << 13), /** @brief is throw */
610+
fIsOperator = (1 << 14), /** @brief is operator */
611+
fHasLvalRefQual = (1 << 15), /** @brief has & lvalue ref-qualifier */
612+
fHasRvalRefQual = (1 << 16) /** @brief has && rvalue ref-qualifier */
611613
};
612614

613615
/**
@@ -739,6 +741,12 @@ class CPPCHECKLIB Function {
739741
bool isOperator() const {
740742
return getFlag(fIsOperator);
741743
}
744+
bool hasLvalRefQualifier() const {
745+
return getFlag(fHasLvalRefQual);
746+
}
747+
bool hasRvalRefQualifier() const {
748+
return getFlag(fHasRvalRefQual);
749+
}
742750

743751
void hasBody(bool state) {
744752
setFlag(fHasBody, state);
@@ -785,6 +793,12 @@ class CPPCHECKLIB Function {
785793
void isOperator(bool state) {
786794
setFlag(fIsOperator, state);
787795
}
796+
void hasLvalRefQualifier(bool state) {
797+
setFlag(fHasLvalRefQual, state);
798+
}
799+
void hasRvalRefQualifier(bool state) {
800+
setFlag(fHasRvalRefQual, state);
801+
}
788802

789803
const Token *tokenDef; // function name token in class definition
790804
const Token *argDef; // function argument start '(' in class definition

test/testsymboldatabase.cpp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ class TestSymbolDatabase: public TestFixture {
249249
TEST_CASE(findFunction5); // #6230
250250
TEST_CASE(findFunction6);
251251
TEST_CASE(findFunction7); // #6700
252+
TEST_CASE(findFunction8);
252253

253254
TEST_CASE(noexceptFunction1);
254255
TEST_CASE(noexceptFunction2);
@@ -2606,6 +2607,83 @@ class TestSymbolDatabase: public TestFixture {
26062607
ASSERT_EQUALS(true, callfunc && callfunc->tokAt(2)->function() && callfunc->tokAt(2)->function()->tokenDef->linenr() == 3);
26072608
}
26082609

2610+
void findFunction8() {
2611+
GET_SYMBOL_DB("struct S {\n"
2612+
" void f() { }\n"
2613+
" void f() & { }\n"
2614+
" void f() &&{ }\n"
2615+
" void f() const { }\n"
2616+
" void f() const & { }\n"
2617+
" void f() const &&{ }\n"
2618+
" void g() ;\n"
2619+
" void g() & ;\n"
2620+
" void g() &&;\n"
2621+
" void g() const ;\n"
2622+
" void g() const & ;\n"
2623+
" void g() const &&;\n"
2624+
"};\n"
2625+
"void S::g() { }\n"
2626+
"void S::g() & { }\n"
2627+
"void S::g() &&{ }\n"
2628+
"void S::g() const { }\n"
2629+
"void S::g() const & { }\n"
2630+
"void S::g() const &&{ }\n");
2631+
ASSERT_EQUALS("", errout.str());
2632+
2633+
const Token *f = Token::findsimplematch(tokenizer.tokens(), "f ( ) {");
2634+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 2);
2635+
2636+
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) & {");
2637+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
2638+
2639+
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) && {");
2640+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
2641+
2642+
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const {");
2643+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
2644+
2645+
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const & {");
2646+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
2647+
2648+
f = Token::findsimplematch(tokenizer.tokens(), "f ( ) const && {");
2649+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
2650+
2651+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) {");
2652+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8 && f->function()->token->linenr() == 15);
2653+
2654+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) & {");
2655+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 9 && f->function()->token->linenr() == 16);
2656+
2657+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) && {");
2658+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 10 && f->function()->token->linenr() == 17);
2659+
2660+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const {");
2661+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 11 && f->function()->token->linenr() == 18);
2662+
2663+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const & {");
2664+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 12 && f->function()->token->linenr() == 19);
2665+
2666+
f = Token::findsimplematch(tokenizer.tokens(), "g ( ) const && {");
2667+
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 13 && f->function()->token->linenr() == 20);
2668+
2669+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) {");
2670+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 8 && f->tokAt(2)->function()->token->linenr() == 15);
2671+
2672+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) & {");
2673+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 9 && f->tokAt(2)->function()->token->linenr() == 16);
2674+
2675+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) && {");
2676+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 10 && f->tokAt(2)->function()->token->linenr() == 17);
2677+
2678+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const {");
2679+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 11 && f->tokAt(2)->function()->token->linenr() == 18);
2680+
2681+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const & {");
2682+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 12 && f->tokAt(2)->function()->token->linenr() == 19);
2683+
2684+
f = Token::findsimplematch(tokenizer.tokens(), "S :: g ( ) const && {");
2685+
ASSERT_EQUALS(true, db && f && f->tokAt(2)->function() && f->tokAt(2)->function()->tokenDef->linenr() == 13 && f->tokAt(2)->function()->token->linenr() == 20);
2686+
}
26092687

26102688

26112689
#define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \

0 commit comments

Comments
 (0)