Skip to content

Commit ed4a47d

Browse files
committed
Tokenizer: Improve syntax checking of switch,if,while
1 parent 224e557 commit ed4a47d

File tree

7 files changed

+53
-44
lines changed

7 files changed

+53
-44
lines changed

lib/tokenize.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3469,6 +3469,20 @@ bool Tokenizer::simplifyTokenList1(const char FileName[])
34693469
Token::simpleMatch(tok->linkAt(2), "} ;")) {
34703470
syntaxError(tok);
34713471
}
3472+
3473+
if (tok->str() == "switch") { // switch (EXPR) { ... }
3474+
if (!Token::Match(tok->next(), "( !!)"))
3475+
syntaxError(tok->next());
3476+
if (!Token::simpleMatch(tok->linkAt(1),") {"))
3477+
syntaxError(tok->linkAt(1));
3478+
validateExpr(tok->next(), tok->linkAt(1));
3479+
}
3480+
3481+
if (Token::Match(tok, "if|while")) {
3482+
if (!Token::Match(tok->next(), "( !!)"))
3483+
syntaxError(tok->next());
3484+
validateExpr(tok->next(), tok->linkAt(1));
3485+
}
34723486
}
34733487

34743488
if (!simplifyAddBraces())
@@ -8175,6 +8189,29 @@ void Tokenizer::validate() const
81758189
cppcheckError(lastTok);
81768190
}
81778191

8192+
void Tokenizer::validateExpr(const Token *start, const Token *end)
8193+
{
8194+
std::set<std::string> controlFlowKeywords;
8195+
controlFlowKeywords.insert("goto");
8196+
controlFlowKeywords.insert("do");
8197+
controlFlowKeywords.insert("if");
8198+
controlFlowKeywords.insert("else");
8199+
controlFlowKeywords.insert("for");
8200+
controlFlowKeywords.insert("while");
8201+
controlFlowKeywords.insert("switch");
8202+
controlFlowKeywords.insert("break");
8203+
controlFlowKeywords.insert("continue");
8204+
controlFlowKeywords.insert("return");
8205+
for (const Token *tok = start; tok != end; tok = tok->next()) {
8206+
if (controlFlowKeywords.find(tok->str()) != controlFlowKeywords.end())
8207+
syntaxError(tok);
8208+
if (tok->str() == ";")
8209+
syntaxError(tok);
8210+
if (tok->str() == "{")
8211+
tok = tok->link();
8212+
}
8213+
}
8214+
81788215
std::string Tokenizer::simplifyString(const std::string &source)
81798216
{
81808217
std::string str = source;

lib/tokenize.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,9 @@ class CPPCHECKLIB Tokenizer {
592592
*/
593593
void validate() const;
594594

595+
/** Validate that expression is valid. If it's invalid a syntax error is reported. */
596+
void validateExpr(const Token *start, const Token *end);
597+
595598
/**
596599
* Remove __declspec()
597600
*/

test/testgarbage.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ class TestGarbage : public TestFixture {
246246
// run alternate check first. It should only ensure stability - so we catch exceptions here.
247247
try {
248248
checkCodeInternal(code, alternatefilename);
249-
} catch (InternalError&) {
249+
} catch (const InternalError&) {
250250
}
251251

252252
return checkCodeInternal(code, filename);
@@ -451,7 +451,7 @@ class TestGarbage : public TestFixture {
451451
}
452452

453453
void garbageCode15() { // Ticket #5203
454-
checkCode("int f ( int* r ) { { int s[2] ; f ( s ) ; if ( ) } }");
454+
ASSERT_THROW(checkCode("int f ( int* r ) { { int s[2] ; f ( s ) ; if ( ) } }"), InternalError);
455455
}
456456

457457
void garbageCode16() {
@@ -480,13 +480,13 @@ class TestGarbage : public TestFixture {
480480

481481
void garbageCode21() {
482482
// Ticket #3486 - Don't crash garbage code
483-
checkCode("void f()\n"
484-
"{\n"
485-
" (\n"
486-
" x;\n"
487-
" int a, a2, a2*x; if () ;\n"
488-
" )\n"
489-
"}");
483+
ASSERT_THROW(checkCode("void f()\n"
484+
"{\n"
485+
" (\n"
486+
" x;\n"
487+
" int a, a2, a2*x; if () ;\n"
488+
" )\n"
489+
"}"), InternalError);
490490
}
491491

492492
void garbageCode22() {
@@ -765,7 +765,7 @@ class TestGarbage : public TestFixture {
765765
}
766766

767767
void garbageCode76() { // #6754
768-
checkCode(" ( ) ( ) { ( ) [ ] } TEST ( ) { ( _broadcast_f32x4 ) ( ) ( ) ( ) ( ) if ( ) ( ) ; } E mask = ( ) [ ] ( ) res1.x =");
768+
ASSERT_THROW(checkCode(" ( ) ( ) { ( ) [ ] } TEST ( ) { ( _broadcast_f32x4 ) ( ) ( ) ( ) ( ) if ( ) ( ) ; } E mask = ( ) [ ] ( ) res1.x ="), InternalError);
769769
}
770770

771771
void garbageCode77() { // #6755

test/testnullpointer.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,9 +1538,6 @@ class TestNullPointer : public TestFixture {
15381538
"}");
15391539
ASSERT_EQUALS("", errout.str());
15401540

1541-
// #2582 - segmentation fault
1542-
check("if()");
1543-
15441541
// #2674 - different functions
15451542
check("class Fred {\n"
15461543
"public:\n"

test/testother.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3410,7 +3410,7 @@ class TestOther : public TestFixture {
34103410
ASSERT_EQUALS("", errout.str());
34113411

34123412
// make sure there are not "same expression" fp when there are different ({}) expressions
3413-
check("void f(long x) { if (({ 1+2; }) == ({3+4};)) {} }");
3413+
check("void f(long x) { if (({ 1+2; }) == ({3+4;})) {} }");
34143414
ASSERT_EQUALS("", errout.str());
34153415

34163416
// #5535: Reference named like its type

test/testtokenize.cpp

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -102,16 +102,14 @@ class TestTokenizer : public TestFixture {
102102
TEST_CASE(ifAddBraces3);
103103
TEST_CASE(ifAddBraces4);
104104
TEST_CASE(ifAddBraces5);
105-
TEST_CASE(ifAddBraces6);
106105
TEST_CASE(ifAddBraces7);
107106
TEST_CASE(ifAddBraces9);
108107
TEST_CASE(ifAddBraces10);
109108
TEST_CASE(ifAddBraces11);
110109
TEST_CASE(ifAddBraces12);
111110
TEST_CASE(ifAddBraces13);
112-
TEST_CASE(ifAddBraces14); // #2610 - segfault: if()<{}
113111
TEST_CASE(ifAddBraces15); // #2616 - unknown macro before if
114-
TEST_CASE(ifAddBraces16); // ticket # 2739 (segmentation fault)
112+
TEST_CASE(ifAddBraces16);
115113
TEST_CASE(ifAddBraces17); // '} else' should be in the same line
116114
TEST_CASE(ifAddBraces18); // #3424 - if if { } else else
117115
TEST_CASE(ifAddBraces19); // #3928 - if for if else
@@ -1096,11 +1094,6 @@ class TestTokenizer : public TestFixture {
10961094
"}", tokenizeAndStringify(code, true));
10971095
}
10981096

1099-
void ifAddBraces6() {
1100-
const char code[] = "if()";
1101-
ASSERT_EQUALS("if ( )", tokenizeAndStringify(code, true));
1102-
}
1103-
11041097
void ifAddBraces7() {
11051098
const char code[] = "void f()\n"
11061099
"{\n"
@@ -1163,20 +1156,12 @@ class TestTokenizer : public TestFixture {
11631156
ASSERT_EQUALS(expected2, tokenizeAndStringify(code2, true));
11641157
}
11651158

1166-
void ifAddBraces14() {
1167-
// ticket #2610 (segfault)
1168-
tokenizeAndStringify("if()<{}", false);
1169-
}
1170-
11711159
void ifAddBraces15() {
11721160
// ticket #2616 - unknown macro before if
11731161
ASSERT_EQUALS("{ A if ( x ) { y ( ) ; } }", tokenizeAndStringify("{A if(x)y();}", false));
11741162
}
11751163

1176-
void ifAddBraces16() { // ticket # 2739 (segmentation fault)
1177-
tokenizeAndStringify("if()x");
1178-
ASSERT_EQUALS("", errout.str());
1179-
1164+
void ifAddBraces16() {
11801165
// ticket #2873 - the fix is not needed anymore.
11811166
{
11821167
const char code[] = "void f() { "

test/testuninitvar.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ class TestUninitVar : public TestFixture {
6060
TEST_CASE(uninitvar2_while);
6161
TEST_CASE(uninitvar2_4494); // #4494
6262
TEST_CASE(uninitvar2_malloc); // malloc returns uninitialized data
63-
TEST_CASE(uninitvar7); // ticket #5971
6463
TEST_CASE(uninitvar8); // ticket #6230
6564
TEST_CASE(uninitvar9); // ticket #6424
6665
TEST_CASE(uninitvar_unconditionalTry);
@@ -2576,18 +2575,6 @@ class TestUninitVar : public TestFixture {
25762575
ASSERT_EQUALS("", errout.str());
25772576
}
25782577

2579-
void uninitvar7() {
2580-
const char code[] = "void eDBauth_user() {\n"
2581-
" char *blid_cert;\n"
2582-
" if( ) {\n"
2583-
" blid_cert = ;\n"
2584-
" } \n"
2585-
"}\n";
2586-
2587-
// Assume dfs is a non POD type if file is C++
2588-
checkUninitVar(code, "test.cpp");
2589-
}
2590-
25912578
void uninitvar8() {
25922579
const char code[] = "struct Fred {\n"
25932580
" void Sync(dsmp_t& type, int& len, int limit = 123);\n"

0 commit comments

Comments
 (0)