From c0d3e002a9f9556e17c19acfa0191936cb0c96bb Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 8 Feb 2011 20:59:30 +1300 Subject: [PATCH 01/24] preprocessor check for #define A 0 --- test/testpreprocessor.cpp | 46 ++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 7163b3af2..192f53dfb 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1226,21 +1226,41 @@ private: void if_cond7() { - const char filedata[] = "#define A 1\n" - "#if A==1\n" - "a1;\n" - "#endif\n"; + { + const char filedata[] = "#define A 1\n" + "#if A==1\n" + "a1;\n" + "#endif\n"; - // Preprocess => actual result.. - std::istringstream istr(filedata); - std::map actual; - Settings settings; - Preprocessor preprocessor(&settings, this); - preprocessor.preprocess(istr, actual, "file.c"); + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Settings settings; + Preprocessor preprocessor(&settings, this); + preprocessor.preprocess(istr, actual, "file.c"); - // Compare results.. - ASSERT_EQUALS(1, (int)actual.size()); - ASSERT_EQUALS("\n\na1;\n\n", actual[""]); + // Compare results.. + ASSERT_EQUALS(1, (int)actual.size()); + ASSERT_EQUALS("\n\na1;\n\n", actual[""]); + } + + { + const char filedata[] = "#define A 0\n" + "#if A\n" + "foo();\n" + "#endif\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Settings settings; + Preprocessor preprocessor(&settings, this); + preprocessor.preprocess(istr, actual, "file.c"); + + // Compare results.. + ASSERT_EQUALS(2, static_cast(actual.size())); + ASSERT_EQUALS("\n\n\n\n", actual[""]); + } } From 38986302e91fafacb6e9599e1e220c15c035d933 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 8 Feb 2011 21:44:59 +1300 Subject: [PATCH 02/24] failing test for suppression glob --- test/testsettings.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/testsettings.cpp b/test/testsettings.cpp index 28e242543..88a5eeda5 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -36,6 +36,7 @@ private: TEST_CASE(suppressionsBadId1); TEST_CASE(suppressionsDosFormat); // Ticket #1836 TEST_CASE(suppressionsFileNameWithColon); // Ticket #1919 - filename includes colon + TEST_CASE(suppressionsGlob); } void suppressionsBadId1() @@ -63,6 +64,15 @@ private: ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 10)); ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "c:\\bar.cpp", 12)); } + + void suppressionsGlob() + { + Settings::Suppressions suppressions; + std::istringstream s("error:x*.cpp\n"); + ASSERT_EQUALS("", suppressions.parseFile(s)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1)); + ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1)); + } }; REGISTER_TEST(TestSettings) From a9f28798892811dee32dfaf0b1ab6bcd008b9dd6 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Tue, 8 Feb 2011 21:45:17 +1300 Subject: [PATCH 03/24] factor out file matching into own class --- lib/settings.cpp | 46 +++++++++++++++++++++++++++------------------- lib/settings.h | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 20 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index e0fc89257..007edcac6 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -116,6 +116,31 @@ std::string Settings::Suppressions::parseFile(std::istream &istr) return ""; } +std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name, unsigned int line) +{ + _files[name].insert(line); + return ""; +} + +bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, unsigned int line) +{ + // Check are all errors of this type filtered out + if (_files.find("") != _files.end()) + return true; + + if (_files.find(file) == _files.end()) + return false; + + // Check should all errors in this file be filtered out + if (std::find(_files[file].begin(), _files[file].end(), 0U) != _files[file].end()) + return true; + + if (std::find(_files[file].begin(), _files[file].end(), line) == _files[file].end()) + return false; + + return true; +} + std::string Settings::Suppressions::addSuppression(const std::string &errorId, const std::string &file, unsigned int line) { // Check that errorId is valid.. @@ -135,10 +160,7 @@ std::string Settings::Suppressions::addSuppression(const std::string &errorId, c } } - _suppressions[errorId][file].push_back(line); - _suppressions[errorId][file].sort(); - - return ""; + return _suppressions[errorId].addFile(file, line); } bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std::string &file, unsigned int line) @@ -146,21 +168,7 @@ bool Settings::Suppressions::isSuppressed(const std::string &errorId, const std: if (_suppressions.find(errorId) == _suppressions.end()) return false; - // Check are all errors of this type filtered out - if (_suppressions[errorId].find("") != _suppressions[errorId].end()) - return true; - - if (_suppressions[errorId].find(file) == _suppressions[errorId].end()) - return false; - - // Check should all errors in this file be filtered out - if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), 0) != _suppressions[errorId][file].end()) - return true; - - if (std::find(_suppressions[errorId][file].begin(), _suppressions[errorId][file].end(), line) == _suppressions[errorId][file].end()) - return false; - - return true; + return _suppressions[errorId].isSuppressed(file, line); } std::string Settings::addEnabled(const std::string &str) diff --git a/lib/settings.h b/lib/settings.h index c6bec4336..d2d9a217d 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -23,6 +23,7 @@ #include #include #include +#include /// @addtogroup Core /// @{ @@ -135,8 +136,42 @@ public: class Suppressions { private: + class FileMatcher + { + private: + /** @brief List of filenames suppressed. */ + std::map > _files; + /** @brief List of globs suppressed. */ + std::map > _globs; + + /** + * @brief Match a name against a glob pattern. + * @param pattern The glob pattern to match. + * @param name The filename to match against the glob pattern. + * @return match success + */ + static bool match(const std::string &pattern, const std::string &name); + + public: + /** + * @brief Add a file or glob (and line number). + * @param name File name or glob pattern + * @param line Line number + * @return error message. empty upon success + */ + std::string addFile(const std::string &name, unsigned int line); + + /** + * @brief Returns true if the file name matches a previously added file or glob pattern. + * @param name File name to check + * @param line Line number + * @return true if this filename/line matches + */ + bool isSuppressed(const std::string &file, unsigned int line); + }; + /** @brief List of error which the user doesn't want to see. */ - std::map > > _suppressions; + std::map _suppressions; public: /** * @brief Don't show errors listed in the file. From 7a219b1fb8354634c48820f3ea699ad9a2f6e473 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Wed, 9 Feb 2011 00:13:50 +1300 Subject: [PATCH 04/24] support wildcard characters * and ? in suppression list --- lib/settings.cpp | 92 +++++++++++++++++++++++++++++++++++++++++-- man/cppcheck.1.xml | 3 +- man/manual.docbook | 4 ++ test/testsettings.cpp | 36 ++++++++++++++--- 4 files changed, 125 insertions(+), 10 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index 007edcac6..bf9f6a58e 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -116,9 +116,81 @@ std::string Settings::Suppressions::parseFile(std::istream &istr) return ""; } +bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, const std::string &name) +{ + const char *p = pattern.c_str(); + const char *n = name.c_str(); + std::list > backtrack; + + for (;;) { + bool matching = true; + while (*p != '\0' && matching) { + switch (*p) { + case '*': + // Step forward until we match the next character after * + while (*n != '\0' && *n != p[1]) { + n++; + } + if (*n != '\0') { + // If this isn't the last possibility, save it for later + backtrack.push_back(std::make_pair(p, n)); + } + break; + case '?': + // Any character matches unless we're at the end of the name + if (*n != '\0') { + n++; + } else { + matching = false; + } + break; + default: + // Non-wildcard characters match literally + if (*n == *p) { + n++; + } else { + matching = false; + } + break; + } + p++; + } + + // If we haven't failed matching and we've reached the end of the name, then success + if (matching && *n == '\0') { + return true; + } + + // If there are no other paths to tray, then fail + if (backtrack.empty()) { + return false; + } + + // Restore pointers from backtrack stack + p = backtrack.back().first; + n = backtrack.back().second; + backtrack.pop_back(); + + // Advance name pointer by one because the current position didn't work + n++; + } +} + std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name, unsigned int line) { - _files[name].insert(line); + if (name.find_first_of("*?") != std::string::npos) { + for (std::string::const_iterator i = name.begin(); i != name.end(); ++i) { + if (*i == '*') { + std::string::const_iterator j = i + 1; + if (j != name.end() && (*j == '*' || *j == '?')) { + return "Failed to add suppression. Syntax error in glob."; + } + } + } + _globs[name].insert(line); + } else { + _files[name].insert(line); + } return ""; } @@ -128,14 +200,26 @@ bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, if (_files.find("") != _files.end()) return true; - if (_files.find(file) == _files.end()) + std::set lineset; + + std::map >::const_iterator f = _files.find(file); + if (f != _files.end()) { + lineset.insert(f->second.begin(), f->second.end()); + } + for (std::map >::iterator g = _globs.begin(); g != _globs.end(); ++g) { + if (match(g->first, file)) { + lineset.insert(g->second.begin(), g->second.end()); + } + } + + if (lineset.empty()) return false; // Check should all errors in this file be filtered out - if (std::find(_files[file].begin(), _files[file].end(), 0U) != _files[file].end()) + if (lineset.find(0U) != lineset.end()) return true; - if (std::find(_files[file].begin(), _files[file].end(), line) == _files[file].end()) + if (lineset.find(line) == lineset.end()) return false; return true; diff --git a/man/cppcheck.1.xml b/man/cppcheck.1.xml index 3344d02b3..9332a09ae 100644 --- a/man/cppcheck.1.xml +++ b/man/cppcheck.1.xml @@ -307,7 +307,8 @@ Directory name is matched to all parts of the path. Suppress warnings listed in the file. Filename and line are optional. The format of the single line in file is: [error id]:[filename]:[line]. - You can use --template or --xml to see the error id. + You can use --template or --xml to see the error id. + The filename may contain the wildcard characters * or ?. diff --git a/man/manual.docbook b/man/manual.docbook index 02a25bf73..07285513a 100644 --- a/man/manual.docbook +++ b/man/manual.docbook @@ -385,6 +385,10 @@ gui/test.cpp,16,error,mismatchAllocDealloc,Mismatching allocation and deallocati line flag. Copy and paste the id string from the XML output. + The filename may include the wildcard characters + * or ?, which match any sequence of characters or any single character + respectively. + Here is an example: memleak:file1.cpp diff --git a/test/testsettings.cpp b/test/testsettings.cpp index 88a5eeda5..078324be2 100644 --- a/test/testsettings.cpp +++ b/test/testsettings.cpp @@ -67,11 +67,37 @@ private: void suppressionsGlob() { - Settings::Suppressions suppressions; - std::istringstream s("error:x*.cpp\n"); - ASSERT_EQUALS("", suppressions.parseFile(s)); - ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1)); - ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1)); + // Check for syntax errors in glob + { + Settings::Suppressions suppressions; + std::istringstream s("errorid:**.cpp\n"); + ASSERT_EQUALS("Failed to add suppression. Syntax error in glob.", suppressions.parseFile(s)); + } + + // Check that globbing works + { + Settings::Suppressions suppressions; + std::istringstream s("errorid:x*.cpp\nerrorid:y?.cpp\nerrorid:test.c*"); + ASSERT_EQUALS("", suppressions.parseFile(s)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp.cpp", 1)); + ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "abc.cpp", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "ya.cpp", 1)); + ASSERT_EQUALS(false, suppressions.isSuppressed("errorid", "y.cpp", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.c", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "test.cpp", 1)); + } + + // Check that both a filename match and a glob match apply + { + Settings::Suppressions suppressions; + std::istringstream s("errorid:x*.cpp\nerrorid:xyz.cpp:1\nerrorid:a*.cpp:1\nerrorid:abc.cpp:2"); + ASSERT_EQUALS("", suppressions.parseFile(s)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "xyz.cpp", 2)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 1)); + ASSERT_EQUALS(true, suppressions.isSuppressed("errorid", "abc.cpp", 2)); + } } }; From ee0f5ff7b350d212b03943f1ae0afe374a92505c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 12:42:16 +0100 Subject: [PATCH 05/24] Uninitialized variables: Added TODO test case --- test/testuninitvar.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/testuninitvar.cpp b/test/testuninitvar.cpp index 3dc598f83..1aee1c480 100644 --- a/test/testuninitvar.cpp +++ b/test/testuninitvar.cpp @@ -46,6 +46,7 @@ private: TEST_CASE(uninitvar_references); // references TEST_CASE(uninitvar_strncpy); // strncpy doesn't always 0-terminate TEST_CASE(uninitvar_func); // analyse functions + TEST_CASE(uninitvar_func2); // usage of 'void a(int *p) { *p = 0; }' TEST_CASE(uninitvar_typeof); // typeof } @@ -1420,6 +1421,28 @@ private: ASSERT_EQUALS("", errout.str()); } + // valid and invalid use of 'void a(int *p) { *p = 0; }' + void uninitvar_func2() + { + const std::string funca("void a(int *p) { *p = 0; }\n"); + + // ok - initialized pointer + checkUninitVar((funca + + "void b() {\n" + " int buf[10];\n" + " a(buf);\n" + "}\n").c_str()); + ASSERT_EQUALS("", errout.str()); + + // not ok - uninitialized pointer + checkUninitVar((funca + + "void b() {\n" + " int *p;\n" + " a(p);\n" + "}\n").c_str()); + TODO_ASSERT_EQUALS("error", "", errout.str()); + } + void uninitvar_typeof() { checkUninitVar("void f() {\n" From 2657d36d03fa6e6cc471f995c4c3ba1dfa220616 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 14:27:07 +0100 Subject: [PATCH 06/24] Fixed #2502 (False positive: redundant assingment of object to itself) --- lib/checkother.cpp | 11 ++++++++++- test/testother.cpp | 9 +++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/checkother.cpp b/lib/checkother.cpp index 799fadbcf..f75f5f83f 100644 --- a/lib/checkother.cpp +++ b/lib/checkother.cpp @@ -317,12 +317,21 @@ void CheckOther::checkSelfAssignment() if (!_settings->_checkCodingStyle) return; + // POD variables.. + std::set pod; + for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) + { + if (tok->isStandardType() && tok->next()->varId() && Token::Match(tok->tokAt(2), "[,);]")) + pod.insert(tok->next()->varId()); + } + const char selfAssignmentPattern[] = "%var% = %var% ;|=|)"; const Token *tok = Token::findmatch(_tokenizer->tokens(), selfAssignmentPattern); while (tok) { if (Token::Match(tok->previous(), "[;{}]") && - tok->varId() && tok->varId() == tok->tokAt(2)->varId()) + tok->varId() && tok->varId() == tok->tokAt(2)->varId() && + pod.find(tok->varId()) != pod.end()) { selfAssignmentError(tok, tok->str()); } diff --git a/test/testother.cpp b/test/testother.cpp index 1e7eca1d3..bdd9261af 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -1157,14 +1157,12 @@ private: check("void foo()\n" "{\n" " int x = x;\n" - " return 0;\n" "}\n"); ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"x\" to itself\n", errout.str()); check("void foo()\n" "{\n" " std::string var = var = \"test\";\n" - " return 0;\n" "}\n"); TODO_ASSERT_EQUALS("[test.cpp:3]: (warning) Redundant assignment of \"var\" to itself\n", "", errout.str()); @@ -1182,6 +1180,13 @@ private: " *x = x;\n" "}\n"); ASSERT_EQUALS("", errout.str()); + + // non-primitive type -> there might be some side effects + check("void foo()\n" + "{\n" + " Fred fred; fred = fred;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); } void testScanf1() From 7507f64ee725902acca53486ab0d38e30818dc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 15:39:26 +0100 Subject: [PATCH 07/24] Fixed #2558 (false positive: (error) Returning reference to auto variable) --- lib/checkautovariables.h | 8 +++++++- test/testautovariables.cpp | 17 +++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/lib/checkautovariables.h b/lib/checkautovariables.h index a1faf1450..d042bdfc5 100644 --- a/lib/checkautovariables.h +++ b/lib/checkautovariables.h @@ -42,12 +42,18 @@ public: : Check(myName(), tokenizer, settings, errorLogger) { } + /** @brief Run checks against the normal token list */ + void runChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) + { + CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger); + checkAutoVariables.returnReference(); + } + void runSimplifiedChecks(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) { CheckAutoVariables checkAutoVariables(tokenizer, settings, errorLogger); checkAutoVariables.autoVariables(); checkAutoVariables.returnPointerToLocalArray(); - checkAutoVariables.returnReference(); checkAutoVariables.returncstr(); } diff --git a/test/testautovariables.cpp b/test/testautovariables.cpp index 221258cc1..5131b86e1 100644 --- a/test/testautovariables.cpp +++ b/test/testautovariables.cpp @@ -47,6 +47,10 @@ private: Tokenizer tokenizer(&settings, this); std::istringstream istr(code); tokenizer.tokenize(istr, "test.cpp"); + + CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this); + checkAutoVariables.runChecks(&tokenizer, &settings, this); + tokenizer.simplifyTokenList(); // Assign variable ids @@ -56,10 +60,8 @@ private: tokenizer.fillFunctionList(); // Check auto variables - CheckAutoVariables checkAutoVariables(&tokenizer, &settings, this); checkAutoVariables.autoVariables(); checkAutoVariables.returnPointerToLocalArray(); - checkAutoVariables.returnReference(); checkAutoVariables.returncstr(); } @@ -81,6 +83,7 @@ private: // return reference.. TEST_CASE(returnReference1); TEST_CASE(returnReference2); + TEST_CASE(returnReference3); // return c_str().. TEST_CASE(returncstr1); @@ -351,6 +354,16 @@ private: ASSERT_EQUALS("[test.cpp:11]: (error) Returning reference to temporary\n", errout.str()); } + void returnReference3() + { + check("double & f(double & rd) {\n" + " double ret = getValue();\n" + " rd = ret;\n" + " return rd;\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + } + void returncstr1() { check("const char *foo()\n" From 07e8325e50cc5a99651cc9baf56edfa38ed13765 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 16:51:59 +0100 Subject: [PATCH 08/24] Fixed #2549 (segmentation fault of cppcheck) --- lib/tokenize.cpp | 17 +++++++++++++++-- test/testtokenize.cpp | 13 +++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 352363f67..eb527394b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2780,8 +2780,21 @@ void Tokenizer::simplifyTemplates() { tok->insertToken(","); tok = tok->next(); - tok->insertToken((*it)->strAt(1)); - tok = tok->next(); + const Token *from = (*it)->next(); + std::stack links; + while (from && (!links.empty() || (from->str() != "," && from->str() != ">"))) + { + tok->insertToken(from->str()); + tok = tok->next(); + if (Token::Match(tok, "(|[")) + links.push(tok); + else if (!links.empty() && Token::Match(tok, ")|]")) + { + Token::createMutualLinks(links.top(), tok); + links.pop(); + } + from = from->next(); + } ++it; } } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index ae11bd0ed..e07d202b0 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -264,6 +264,7 @@ private: TEST_CASE(removeattribute); TEST_CASE(cpp0xtemplate1); TEST_CASE(cpp0xtemplate2); + TEST_CASE(cpp0xtemplate3); TEST_CASE(cpp0xdefault); TEST_CASE(arraySize); @@ -4634,6 +4635,18 @@ private: "list < list < int >> ints ;", tokenizeAndStringify(code)); } + void cpp0xtemplate3() + { + // #2549 + const char *code = "template\n" + "struct S\n" + "{};\n" + "S s;\n"; + TODO_ASSERT_EQUALS(";\n\n\nS < int , ( int ) 0 > s ;", // wanted result + ";\n\n\nS < int , ( T ) 0 > s ;", // current result + tokenizeAndStringify(code)); + } + void cpp0xdefault() { { From 518a495334bcb00dba99db1514bc8c235cecf396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 18:34:12 +0100 Subject: [PATCH 09/24] Fixed #2576 (False positive: (error) Buffer access out-of-bounds) --- lib/checkbufferoverrun.cpp | 2 +- test/testbufferoverrun.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/checkbufferoverrun.cpp b/lib/checkbufferoverrun.cpp index a0f417975..85963c36e 100644 --- a/lib/checkbufferoverrun.cpp +++ b/lib/checkbufferoverrun.cpp @@ -791,7 +791,7 @@ void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &ar return; // Get index variable and stopsize. - bool condition_out_of_bounds = true; + bool condition_out_of_bounds = bool(size > 0); if (MathLib::toLongNumber(max_counter_value) < size) condition_out_of_bounds = false; diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index d7137ee35..4111dfa50 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -135,6 +135,7 @@ private: TEST_CASE(buffer_overrun_15); // ticket #1787 TEST_CASE(buffer_overrun_16); TEST_CASE(buffer_overrun_17); // ticket #2548 + TEST_CASE(buffer_overrun_18); // ticket #2576 - for, calculation with loop variable TEST_CASE(buffer_overrun_bailoutIfSwitch); // ticket #2378 : bailoutIfSwitch // It is undefined behaviour to point out of bounds of an array @@ -1883,6 +1884,35 @@ private: ASSERT_EQUALS("[test.cpp:3]: (error) Buffer access out-of-bounds\n", errout.str()); } + void buffer_overrun_18() // ticket #2576 + { + check("class A {\n" + " void foo();\n" + " bool b[7];\n" + "};\n" + "\n" + "void A::foo() {\n" + " for (int i=0; i<6; i++) {\n" + " b[i] = b[i+1];\n" + " }\n" + "}\n"); + ASSERT_EQUALS("", errout.str()); + + check("class A {\n" + " void foo();\n" + " bool b[7];\n" + "};\n" + "\n" + "void A::foo() {\n" + " for (int i=0; i<7; i++) {\n" + " b[i] = b[i+1];\n" + " }\n" + "}\n"); + TODO_ASSERT_EQUALS("error", // wanted result + "", // current result + errout.str()); + } + void buffer_overrun_bailoutIfSwitch() { // No false positive From 654116af61d893f8cb4576ac2f536782a7980d85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 19:43:33 +0100 Subject: [PATCH 10/24] Tokenizer::simplifyTemplates: Broke out handling for 'template<>..' --- lib/tokenize.cpp | 11 ++++++++++- lib/tokenize.h | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index eb527394b..3344e7b24 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2548,7 +2548,7 @@ static void removeTemplates(Token *tok) } } -void Tokenizer::simplifyTemplates() +std::set Tokenizer::simplifyTemplatesExpandSpecialized() { std::set expandedtemplates; @@ -2614,6 +2614,15 @@ void Tokenizer::simplifyTemplates() } } + return expandedtemplates; +} + +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates; + + expandedtemplates = simplifyTemplatesExpandSpecialized(); + // Locate templates.. std::list templates; for (Token *tok = _tokens; tok; tok = tok->next()) diff --git a/lib/tokenize.h b/lib/tokenize.h index d70a03c76..1ae96b4f0 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -25,6 +25,7 @@ #include #include #include +#include class Token; class ErrorLogger; @@ -395,6 +396,12 @@ public: */ void simplifyTemplates(); + /** + * Expand specialized templates : "template<>.." + * \return names of expanded templates + */ + std::set simplifyTemplatesExpandSpecialized(); + /** * Used after simplifyTemplates to perform a little cleanup. * Sometimes the simplifyTemplates isn't fully successful and then From 25d6bfe3c4950ead12981c160b3659b6b9c2b4b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 20:12:07 +0100 Subject: [PATCH 11/24] Tokenizer::simplifyTemplates: broke out the functionality that extract a list of template declarations --- lib/tokenize.cpp | 17 +++++++++++------ lib/tokenize.h | 9 ++++++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3344e7b24..1f77f1a65 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2617,13 +2617,8 @@ std::set Tokenizer::simplifyTemplatesExpandSpecialized() return expandedtemplates; } -void Tokenizer::simplifyTemplates() +std::list Tokenizer::simplifyTemplatesGetTemplateDeclarations() { - std::set expandedtemplates; - - expandedtemplates = simplifyTemplatesExpandSpecialized(); - - // Locate templates.. std::list templates; for (Token *tok = _tokens; tok; tok = tok->next()) { @@ -2648,6 +2643,16 @@ void Tokenizer::simplifyTemplates() } } } + return templates; +} + +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); + + // Locate templates.. + std::list templates(simplifyTemplatesGetTemplateDeclarations()); + if (templates.empty()) { removeTemplates(_tokens); diff --git a/lib/tokenize.h b/lib/tokenize.h index 1ae96b4f0..2691b967a 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -398,10 +399,16 @@ public: /** * Expand specialized templates : "template<>.." - * \return names of expanded templates + * @return names of expanded templates */ std::set simplifyTemplatesExpandSpecialized(); + /** + * Get template declarations + * @return list of template declarations + */ + std::list simplifyTemplatesGetTemplateDeclarations(); + /** * Used after simplifyTemplates to perform a little cleanup. * Sometimes the simplifyTemplates isn't fully successful and then From 00bdf618f2c89189e62b49fa9aa67e6370b377a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 20:17:58 +0100 Subject: [PATCH 12/24] Tokenizer::simplifyTemplates: Broke out the functionality that extract a list of template instantiations --- lib/tokenize.cpp | 66 +++++++++++++++++++++++++++--------------------- lib/tokenize.h | 6 +++++ 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 1f77f1a65..abf414ec5 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2646,37 +2646,10 @@ std::list Tokenizer::simplifyTemplatesGetTemplateDeclarations() return templates; } -void Tokenizer::simplifyTemplates() +std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() { - std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); - - // Locate templates.. - std::list templates(simplifyTemplatesGetTemplateDeclarations()); - - if (templates.empty()) - { - removeTemplates(_tokens); - return; - } - - // There are templates.. - // Remove "typename" unless used in template arguments.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "typename") - tok->deleteThis(); - - if (Token::simpleMatch(tok, "template <")) - { - while (tok && tok->str() != ">") - tok = tok->next(); - if (!tok) - break; - } - } - - // Locate possible instantiations of templates.. std::list used; + for (Token *tok = _tokens; tok; tok = tok->next()) { // template definition.. skip it @@ -2717,6 +2690,41 @@ void Tokenizer::simplifyTemplates() } } + return used; +} + +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); + + // Locate templates.. + std::list templates(simplifyTemplatesGetTemplateDeclarations()); + + if (templates.empty()) + { + removeTemplates(_tokens); + return; + } + + // There are templates.. + // Remove "typename" unless used in template arguments.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "typename") + tok->deleteThis(); + + if (Token::simpleMatch(tok, "template <")) + { + while (tok && tok->str() != ">") + tok = tok->next(); + if (!tok) + break; + } + } + + // Locate possible instantiations of templates.. + std::list used(simplifyTemplatesGetTemplateInstantiations()); + // No template instantiations? Then remove all templates. if (used.empty()) { diff --git a/lib/tokenize.h b/lib/tokenize.h index 2691b967a..9470d7089 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -409,6 +409,12 @@ public: */ std::list simplifyTemplatesGetTemplateDeclarations(); + /** + * Get template instantiations + * @return list of template instantiations + */ + std::list simplifyTemplatesGetTemplateInstantiations(); + /** * Used after simplifyTemplates to perform a little cleanup. * Sometimes the simplifyTemplates isn't fully successful and then From 9021f0f180959aa08167ed5eebf63d5a1a508ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 20:27:44 +0100 Subject: [PATCH 13/24] Tokenizer::simplifyTemplates: Broke out the functionality that handles default template arguments --- lib/tokenize.cpp | 91 +++++++++++++++++++++++++----------------------- lib/tokenize.h | 8 +++++ 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index abf414ec5..6755c007f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2693,50 +2693,11 @@ std::list Tokenizer::simplifyTemplatesGetTemplateInstantiations() return used; } -void Tokenizer::simplifyTemplates() + +void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list &templates, + const std::list &instantiations) { - std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); - - // Locate templates.. - std::list templates(simplifyTemplatesGetTemplateDeclarations()); - - if (templates.empty()) - { - removeTemplates(_tokens); - return; - } - - // There are templates.. - // Remove "typename" unless used in template arguments.. - for (Token *tok = _tokens; tok; tok = tok->next()) - { - if (tok->str() == "typename") - tok->deleteThis(); - - if (Token::simpleMatch(tok, "template <")) - { - while (tok && tok->str() != ">") - tok = tok->next(); - if (!tok) - break; - } - } - - // Locate possible instantiations of templates.. - std::list used(simplifyTemplatesGetTemplateInstantiations()); - - // No template instantiations? Then remove all templates. - if (used.empty()) - { - removeTemplates(_tokens); - return; - } - - - - - // Template arguments with default values - for (std::list::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) + for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { // template parameters with default value has syntax such as: // x = y @@ -2772,7 +2733,7 @@ void Tokenizer::simplifyTemplates() continue; // iterate through all template instantiations - for (std::list::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2) + for (std::list::const_iterator iter2 = instantiations.begin(); iter2 != instantiations.end(); ++iter2) { Token *tok = *iter2; @@ -2828,7 +2789,49 @@ void Tokenizer::simplifyTemplates() (*it)->deleteThis(); } } +} +void Tokenizer::simplifyTemplates() +{ + std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); + + // Locate templates.. + std::list templates(simplifyTemplatesGetTemplateDeclarations()); + + if (templates.empty()) + { + removeTemplates(_tokens); + return; + } + + // There are templates.. + // Remove "typename" unless used in template arguments.. + for (Token *tok = _tokens; tok; tok = tok->next()) + { + if (tok->str() == "typename") + tok->deleteThis(); + + if (Token::simpleMatch(tok, "template <")) + { + while (tok && tok->str() != ">") + tok = tok->next(); + if (!tok) + break; + } + } + + // Locate possible instantiations of templates.. + std::list used(simplifyTemplatesGetTemplateInstantiations()); + + // No template instantiations? Then remove all templates. + if (used.empty()) + { + removeTemplates(_tokens); + return; + } + + // Template arguments with default values + simplifyTemplatesUseDefaultArgumentValues(templates, used); // expand templates bool done = false; diff --git a/lib/tokenize.h b/lib/tokenize.h index 9470d7089..d06843a01 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -415,6 +415,14 @@ public: */ std::list simplifyTemplatesGetTemplateInstantiations(); + /** + * simplify template instantiations (use default argument values) + * @param templates list of template declarations + * @param instantiations list of template instantiations + */ + void simplifyTemplatesUseDefaultArgumentValues(const std::list &templates, + const std::list &instantiations); + /** * Used after simplifyTemplates to perform a little cleanup. * Sometimes the simplifyTemplates isn't fully successful and then From 4d1aae5859f4c4da89d5ca49343bd0ca4d10a8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 20:58:45 +0100 Subject: [PATCH 14/24] Tokenizer::simplifyTemplates: Broke out the functionality that instantiates a template --- lib/tokenize.cpp | 630 ++++++++++++++++++++++++----------------------- lib/tokenize.h | 7 + 2 files changed, 327 insertions(+), 310 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 6755c007f..2c2e6d5e1 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2791,6 +2791,325 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list &used, + const Token *tok, + std::set &expandedtemplates) +{ + // this variable is not used at the moment. the intention was to + // allow continous instantiations until all templates has been expanded + bool done = false; + + std::vector type; + for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) + { + if (Token::Match(tok, "%var% ,|>")) + type.push_back(tok); + } + // bail out if the end of the file was reached + if (!tok) + return; + + // get the position of the template name + unsigned char namepos = 0; + if (Token::Match(tok, "> class|struct %type% {|:")) + namepos = 2; + else if (Token::Match(tok, "> %type% *|&| %type% (")) + namepos = 2; + else if (Token::Match(tok, "> %type% %type% *|&| %type% (")) + namepos = 3; + else + { + // debug message that we bail out.. + if (_settings->debugwarnings) + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok->linenr(); + loc.setfile(file(tok)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::debug, + "simplifyTemplates: bailing out", + "debug"); + + if (_errorLogger) + _errorLogger->reportErr(errmsg); + else + Check::reportError(errmsg); + } + return; + } + if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&")) + ++namepos; + + // name of template function/class.. + const std::string name(tok->strAt(namepos)); + + const bool isfunc(tok->strAt(namepos + 1) == "("); + + // locate template usage.. + + std::string s(name + " <"); + for (unsigned int i = 0; i < type.size(); ++i) + { + if (i > 0) + s += ","; + s += " %any% "; + } + const std::string pattern(s + "> "); + + std::string::size_type sz1 = used.size(); + unsigned int recursiveCount = 0; + + for (std::list::const_iterator iter2 = used.begin(); iter2 != used.end(); ++iter2) + { + // If the size of "used" has changed, simplify calculations + if (sz1 != used.size()) + { + sz1 = used.size(); + simplifyCalculations(); + recursiveCount++; + if (recursiveCount > 100) + { + // bail out.. + break; + } + } + + Token * const tok2 = *iter2; + + if (tok2->str() != name) + continue; + + if (Token::Match(tok2->previous(), "[;{}=]") && + !Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str())) + continue; + + // New type.. + std::vector types2; + s = ""; + std::string s1(name + " < "); + for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) + { + if (!tok3->next()) + { + s.clear(); + break; + } + s1 += tok3->str(); + s1 += " "; + if (tok3->str() != ",") + types2.push_back(*tok3); + // add additional type information + if (tok3->isUnsigned()) + s += "unsigned"; + else if (tok3->isSigned()) + s += "signed"; + if (tok3->isLong()) + s += "long"; + s += tok3->str(); + } + s1 += ">"; + const std::string type2(s); + + if (type2.empty() || type.size() != types2.size()) + { + if (_settings->debugwarnings) + { + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = tok2->linenr(); + loc.setfile(file(tok2)); + locationList.push_back(loc); + + const ErrorLogger::ErrorMessage errmsg(locationList, + Severity::debug, + "Failed to instantiate template. The checking continues anyway.", + "debug"); + + _errorLogger->reportErr(errmsg); + } + if (type2.empty()) + continue; + break; + } + + // New classname/funcname.. + const std::string name2(name + "<" + type2 + ">"); + + if (expandedtemplates.find(name2) == expandedtemplates.end()) + { + expandedtemplates.insert(name2); + // Copy template.. + int _indentlevel = 0; + int _parlevel = 0; + for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + ++_indentlevel; + else if (tok3->str() == "}") + --_indentlevel; + else if (tok3->str() == "(") + ++_parlevel; + else if (tok3->str() == ")") + --_parlevel; + + // Start of template.. + if (tok3 == tok) + { + tok3 = tok3->next(); + } + + // member function implemented outside class definition + else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str())) + { + addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); + while (tok3->str() != "::") + tok3 = tok3->next(); + } + + // not part of template.. go on to next token + else + continue; + + int indentlevel = 0; + std::stack braces; // holds "{" tokens + std::stack brackets; // holds "(" tokens + std::stack brackets2; // holds "[" tokens + + for (; tok3; tok3 = tok3->next()) + { + if (tok3->str() == "{") + ++indentlevel; + + else if (tok3->str() == "}") + { + if (indentlevel <= 1 && brackets.empty() && brackets2.empty()) + { + // there is a bug if indentlevel is 0 + // the "}" token should only be added if indentlevel is 1 but I add it always intentionally + // if indentlevel ever becomes 0, cppcheck will write: + // ### Error: Invalid number of character { + addtoken("}", tok3->linenr(), tok3->fileIndex()); + Token::createMutualLinks(braces.top(), _tokensBack); + braces.pop(); + break; + } + --indentlevel; + } + + + if (tok3->isName()) + { + // search for this token in the type vector + unsigned int itype = 0; + while (itype < type.size() && type[itype]->str() != tok3->str()) + ++itype; + + // replace type with given type.. + if (itype < type.size()) + { + addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex()); + continue; + } + } + + // replace name.. + if (Token::Match(tok3, (name + " !!<").c_str())) + { + addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); + continue; + } + + // copy + addtoken(tok3, tok3->linenr(), tok3->fileIndex()); + if (Token::Match(tok3, "%type% <")) + { + if (!Token::Match(tok3, (name + " <").c_str())) + done = false; + used.push_back(_tokensBack); + } + + // link() newly tokens manually + if (tok3->str() == "{") + { + braces.push(_tokensBack); + } + else if (tok3->str() == "}") + { + assert(braces.empty() == false); + Token::createMutualLinks(braces.top(), _tokensBack); + braces.pop(); + } + else if (tok3->str() == "(") + { + brackets.push(_tokensBack); + } + else if (tok3->str() == "[") + { + brackets2.push(_tokensBack); + } + else if (tok3->str() == ")") + { + assert(brackets.empty() == false); + Token::createMutualLinks(brackets.top(), _tokensBack); + brackets.pop(); + } + else if (tok3->str() == "]") + { + assert(brackets2.empty() == false); + Token::createMutualLinks(brackets2.top(), _tokensBack); + brackets2.pop(); + } + + } + + assert(braces.empty()); + assert(brackets.empty()); + } + } + + // Replace all these template usages.. + for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) + { + if (Token::simpleMatch(tok4, s1.c_str())) + { + bool match = true; + Token * tok5 = tok4->tokAt(2); + unsigned int count = 0; + while (tok5->str() != ">") + { + if (tok5->str() != ",") + { + if (tok5->isUnsigned() != types2[count].isUnsigned() || + tok5->isSigned() != types2[count].isSigned() || + tok5->isLong() != types2[count].isLong()) + { + match = false; + break; + } + count++; + } + tok5 = tok5->next(); + } + + if (match) + { + tok4->str(name2); + while (tok4->next()->str() != ">") + { + used.remove(tok4->next()); + tok4->deleteNext(); + } + used.remove(tok4->next()); + tok4->deleteNext(); + } + } + } + } +} + void Tokenizer::simplifyTemplates() { std::set expandedtemplates(simplifyTemplatesExpandSpecialized()); @@ -2840,316 +3159,7 @@ void Tokenizer::simplifyTemplates() done = true; for (std::list::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { - Token *tok = *iter1; - std::vector type; - for (tok = tok->tokAt(2); tok && tok->str() != ">"; tok = tok->next()) - { - if (Token::Match(tok, "%var% ,|>")) - type.push_back(tok); - } - // bail out if the end of the file was reached - if (!tok) - break; - - // get the position of the template name - unsigned char namepos = 0; - if (Token::Match(tok, "> class|struct %type% {|:")) - namepos = 2; - else if (Token::Match(tok, "> %type% *|&| %type% (")) - namepos = 2; - else if (Token::Match(tok, "> %type% %type% *|&| %type% (")) - namepos = 3; - else - { - // debug message that we bail out.. - if (_settings->debugwarnings) - { - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok->linenr(); - loc.setfile(file(tok)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::debug, - "simplifyTemplates: bailing out", - "debug"); - - if (_errorLogger) - _errorLogger->reportErr(errmsg); - else - Check::reportError(errmsg); - } - continue; - } - if ((tok->tokAt(namepos)->str() == "*" || tok->tokAt(namepos)->str() == "&")) - ++namepos; - - // name of template function/class.. - const std::string name(tok->strAt(namepos)); - - const bool isfunc(tok->strAt(namepos + 1) == "("); - - // locate template usage.. - - std::string s(name + " <"); - for (unsigned int i = 0; i < type.size(); ++i) - { - if (i > 0) - s += ","; - s += " %any% "; - } - const std::string pattern(s + "> "); - - std::string::size_type sz1 = used.size(); - unsigned int recursiveCount = 0; - - for (std::list::iterator iter2 = used.begin(); iter2 != used.end(); ++iter2) - { - // If the size of "used" has changed, simplify calculations - if (sz1 != used.size()) - { - sz1 = used.size(); - simplifyCalculations(); - recursiveCount++; - if (recursiveCount > 100) - { - // bail out.. - break; - } - } - - Token * const tok2 = *iter2; - - if (tok2->str() != name) - continue; - - if (Token::Match(tok2->previous(), "[;{}=]") && - !Token::Match(tok2, (pattern + (isfunc ? "(" : "*| %var%")).c_str())) - continue; - - // New type.. - std::vector types2; - s = ""; - std::string s1(name + " < "); - for (const Token *tok3 = tok2->tokAt(2); tok3 && tok3->str() != ">"; tok3 = tok3->next()) - { - if (!tok3->next()) - { - s.clear(); - break; - } - s1 += tok3->str(); - s1 += " "; - if (tok3->str() != ",") - types2.push_back(*tok3); - // add additional type information - if (tok3->isUnsigned()) - s += "unsigned"; - else if (tok3->isSigned()) - s += "signed"; - if (tok3->isLong()) - s += "long"; - s += tok3->str(); - } - s1 += ">"; - const std::string type2(s); - - if (type2.empty() || type.size() != types2.size()) - { - if (_settings->debugwarnings) - { - std::list locationList; - ErrorLogger::ErrorMessage::FileLocation loc; - loc.line = tok2->linenr(); - loc.setfile(file(tok2)); - locationList.push_back(loc); - - const ErrorLogger::ErrorMessage errmsg(locationList, - Severity::debug, - "Failed to instantiate template. The checking continues anyway.", - "debug"); - - _errorLogger->reportErr(errmsg); - } - if (type2.empty()) - continue; - break; - } - - // New classname/funcname.. - const std::string name2(name + "<" + type2 + ">"); - - if (expandedtemplates.find(name2) == expandedtemplates.end()) - { - expandedtemplates.insert(name2); - // Copy template.. - int _indentlevel = 0; - int _parlevel = 0; - for (const Token *tok3 = _tokens; tok3; tok3 = tok3->next()) - { - if (tok3->str() == "{") - ++_indentlevel; - else if (tok3->str() == "}") - --_indentlevel; - else if (tok3->str() == "(") - ++_parlevel; - else if (tok3->str() == ")") - --_parlevel; - - // Start of template.. - if (tok3 == tok) - { - tok3 = tok3->next(); - } - - // member function implemented outside class definition - else if (_indentlevel == 0 && _parlevel == 0 && Token::Match(tok3, (pattern + " :: ~| %var% (").c_str())) - { - addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); - while (tok3->str() != "::") - tok3 = tok3->next(); - } - - // not part of template.. go on to next token - else - continue; - - int indentlevel = 0; - std::stack braces; // holds "{" tokens - std::stack brackets; // holds "(" tokens - std::stack brackets2; // holds "[" tokens - - for (; tok3; tok3 = tok3->next()) - { - if (tok3->str() == "{") - ++indentlevel; - - else if (tok3->str() == "}") - { - if (indentlevel <= 1 && brackets.empty() && brackets2.empty()) - { - // there is a bug if indentlevel is 0 - // the "}" token should only be added if indentlevel is 1 but I add it always intentionally - // if indentlevel ever becomes 0, cppcheck will write: - // ### Error: Invalid number of character { - addtoken("}", tok3->linenr(), tok3->fileIndex()); - Token::createMutualLinks(braces.top(), _tokensBack); - braces.pop(); - break; - } - --indentlevel; - } - - - if (tok3->isName()) - { - // search for this token in the type vector - unsigned int itype = 0; - while (itype < type.size() && type[itype]->str() != tok3->str()) - ++itype; - - // replace type with given type.. - if (itype < type.size()) - { - addtoken(&types2[itype], tok3->linenr(), tok3->fileIndex()); - continue; - } - } - - // replace name.. - if (Token::Match(tok3, (name + " !!<").c_str())) - { - addtoken(name2.c_str(), tok3->linenr(), tok3->fileIndex()); - continue; - } - - // copy - addtoken(tok3, tok3->linenr(), tok3->fileIndex()); - if (Token::Match(tok3, "%type% <")) - { - if (!Token::Match(tok3, (name + " <").c_str())) - done = false; - used.push_back(_tokensBack); - } - - // link() newly tokens manually - if (tok3->str() == "{") - { - braces.push(_tokensBack); - } - else if (tok3->str() == "}") - { - assert(braces.empty() == false); - Token::createMutualLinks(braces.top(), _tokensBack); - braces.pop(); - } - else if (tok3->str() == "(") - { - brackets.push(_tokensBack); - } - else if (tok3->str() == "[") - { - brackets2.push(_tokensBack); - } - else if (tok3->str() == ")") - { - assert(brackets.empty() == false); - Token::createMutualLinks(brackets.top(), _tokensBack); - brackets.pop(); - } - else if (tok3->str() == "]") - { - assert(brackets2.empty() == false); - Token::createMutualLinks(brackets2.top(), _tokensBack); - brackets2.pop(); - } - - } - - assert(braces.empty()); - assert(brackets.empty()); - } - } - - // Replace all these template usages.. - for (Token *tok4 = tok2; tok4; tok4 = tok4->next()) - { - if (Token::simpleMatch(tok4, s1.c_str())) - { - bool match = true; - Token * tok5 = tok4->tokAt(2); - unsigned int count = 0; - while (tok5->str() != ">") - { - if (tok5->str() != ",") - { - if (tok5->isUnsigned() != types2[count].isUnsigned() || - tok5->isSigned() != types2[count].isSigned() || - tok5->isLong() != types2[count].isLong()) - { - match = false; - break; - } - count++; - } - tok5 = tok5->next(); - } - - if (match) - { - tok4->str(name2); - while (tok4->next()->str() != ">") - { - used.remove(tok4->next()); - tok4->deleteNext(); - } - used.remove(tok4->next()); - tok4->deleteNext(); - } - } - } - } + simplifyTemplatesInstantiate(used, *iter1, expandedtemplates); } } diff --git a/lib/tokenize.h b/lib/tokenize.h index d06843a01..579c233bd 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -423,6 +423,13 @@ public: void simplifyTemplatesUseDefaultArgumentValues(const std::list &templates, const std::list &instantiations); + /** + * Simplify templates : expand all instantiatiations for a template + */ + void simplifyTemplatesInstantiate(std::list &used, + const Token *tok, + std::set &expandedtemplates); + /** * Used after simplifyTemplates to perform a little cleanup. * Sometimes the simplifyTemplates isn't fully successful and then From de75bdfed5f837fce707e936cc32a9b8adfba03e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sat, 12 Feb 2011 21:11:20 +0100 Subject: [PATCH 15/24] Tokenizer: comments/refactorings --- lib/tokenize.cpp | 8 ++++---- lib/tokenize.h | 8 ++++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 2c2e6d5e1..ad2e81738 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -2791,8 +2791,8 @@ void Tokenizer::simplifyTemplatesUseDefaultArgumentValues(const std::list &used, - const Token *tok, +void Tokenizer::simplifyTemplatesInstantiate(const Token *tok, + std::list &used, std::set &expandedtemplates) { // this variable is not used at the moment. the intention was to @@ -3157,9 +3157,9 @@ void Tokenizer::simplifyTemplates() //while (!done) { done = true; - for (std::list::iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) + for (std::list::const_iterator iter1 = templates.begin(); iter1 != templates.end(); ++iter1) { - simplifyTemplatesInstantiate(used, *iter1, expandedtemplates); + simplifyTemplatesInstantiate(*iter1, used, expandedtemplates); } } diff --git a/lib/tokenize.h b/lib/tokenize.h index 579c233bd..cc076e120 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -425,9 +425,13 @@ public: /** * Simplify templates : expand all instantiatiations for a template + * @todo It seems that inner templates should be instantiated recursively + * @param tok token where the template declaration begins + * @param used a list of template usages (not necessarily just for this template) + * @param expandedtemplates all templates that has been expanded so far. The full names are stored. */ - void simplifyTemplatesInstantiate(std::list &used, - const Token *tok, + void simplifyTemplatesInstantiate(const Token *tok, + std::list &used, std::set &expandedtemplates); /** From 2aefa5deb5e49d2cffc165b8fcf108186473c7d8 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sat, 12 Feb 2011 15:35:48 -0500 Subject: [PATCH 16/24] fix #2577 (segmentation fault of cppcheck) --- lib/symboldatabase.cpp | 2 +- test/testclass.cpp | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 864b4a71c..d29cc5a52 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -227,7 +227,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti // out of line function if (Token::Match(end, ") const| ;") || - Token::Match(end, ") const| = %any% ;")) + Token::Match(end, ") const| = %any%")) { // find the function implementation later tok = end->next(); diff --git a/test/testclass.cpp b/test/testclass.cpp index fd284f8fb..b16e4978c 100644 --- a/test/testclass.cpp +++ b/test/testclass.cpp @@ -191,6 +191,7 @@ private: TEST_CASE(symboldatabase10); // ticket #2537 TEST_CASE(symboldatabase11); // ticket #2539 TEST_CASE(symboldatabase12); // ticket #2547 + TEST_CASE(symboldatabase13); // ticket #2577 } // Check the operator Equal @@ -5528,6 +5529,16 @@ private: ASSERT_EQUALS("", errout.str()); } + void symboldatabase13() + { + // ticket #2577 - segmentation fault + checkConst("class foo {\n" + " void bar2 () = A::f;\n" + "};\n"); + + ASSERT_EQUALS("", errout.str()); + } + }; REGISTER_TEST(TestClass) From 421b32efb46dd7d99f0e7d4ad410d61dde22eb71 Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 13 Feb 2011 09:55:45 +1300 Subject: [PATCH 17/24] use std::stack instead of std::list where appropriate --- lib/settings.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index bf9f6a58e..88cb556ab 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -25,6 +25,7 @@ #include #include // std::isdigit, std::isalnum, etc #include +#include Settings::Settings() { @@ -120,7 +121,7 @@ bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, cons { const char *p = pattern.c_str(); const char *n = name.c_str(); - std::list > backtrack; + std::stack > backtrack; for (;;) { bool matching = true; @@ -133,7 +134,7 @@ bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, cons } if (*n != '\0') { // If this isn't the last possibility, save it for later - backtrack.push_back(std::make_pair(p, n)); + backtrack.push(std::make_pair(p, n)); } break; case '?': @@ -167,9 +168,9 @@ bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, cons } // Restore pointers from backtrack stack - p = backtrack.back().first; - n = backtrack.back().second; - backtrack.pop_back(); + p = backtrack.top().first; + n = backtrack.top().second; + backtrack.pop(); // Advance name pointer by one because the current position didn't work n++; From 1418c12261b4fa70643c32c02f90150236ee32cd Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 13 Feb 2011 10:01:32 +1300 Subject: [PATCH 18/24] astyle formatting --- lib/settings.cpp | 100 +++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 39 deletions(-) diff --git a/lib/settings.cpp b/lib/settings.cpp index 88cb556ab..dbd4f37c7 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -123,47 +123,60 @@ bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, cons const char *n = name.c_str(); std::stack > backtrack; - for (;;) { + for (;;) + { bool matching = true; - while (*p != '\0' && matching) { - switch (*p) { - case '*': - // Step forward until we match the next character after * - while (*n != '\0' && *n != p[1]) { - n++; - } - if (*n != '\0') { - // If this isn't the last possibility, save it for later - backtrack.push(std::make_pair(p, n)); - } - break; - case '?': - // Any character matches unless we're at the end of the name - if (*n != '\0') { - n++; - } else { - matching = false; - } - break; - default: - // Non-wildcard characters match literally - if (*n == *p) { - n++; - } else { - matching = false; - } - break; + while (*p != '\0' && matching) + { + switch (*p) + { + case '*': + // Step forward until we match the next character after * + while (*n != '\0' && *n != p[1]) + { + n++; + } + if (*n != '\0') + { + // If this isn't the last possibility, save it for later + backtrack.push(std::make_pair(p, n)); + } + break; + case '?': + // Any character matches unless we're at the end of the name + if (*n != '\0') + { + n++; + } + else + { + matching = false; + } + break; + default: + // Non-wildcard characters match literally + if (*n == *p) + { + n++; + } + else + { + matching = false; + } + break; } p++; } // If we haven't failed matching and we've reached the end of the name, then success - if (matching && *n == '\0') { + if (matching && *n == '\0') + { return true; } // If there are no other paths to tray, then fail - if (backtrack.empty()) { + if (backtrack.empty()) + { return false; } @@ -179,17 +192,23 @@ bool Settings::Suppressions::FileMatcher::match(const std::string &pattern, cons std::string Settings::Suppressions::FileMatcher::addFile(const std::string &name, unsigned int line) { - if (name.find_first_of("*?") != std::string::npos) { - for (std::string::const_iterator i = name.begin(); i != name.end(); ++i) { - if (*i == '*') { + if (name.find_first_of("*?") != std::string::npos) + { + for (std::string::const_iterator i = name.begin(); i != name.end(); ++i) + { + if (*i == '*') + { std::string::const_iterator j = i + 1; - if (j != name.end() && (*j == '*' || *j == '?')) { + if (j != name.end() && (*j == '*' || *j == '?')) + { return "Failed to add suppression. Syntax error in glob."; } } } _globs[name].insert(line); - } else { + } + else + { _files[name].insert(line); } return ""; @@ -204,11 +223,14 @@ bool Settings::Suppressions::FileMatcher::isSuppressed(const std::string &file, std::set lineset; std::map >::const_iterator f = _files.find(file); - if (f != _files.end()) { + if (f != _files.end()) + { lineset.insert(f->second.begin(), f->second.end()); } - for (std::map >::iterator g = _globs.begin(); g != _globs.end(); ++g) { - if (match(g->first, file)) { + for (std::map >::iterator g = _globs.begin(); g != _globs.end(); ++g) + { + if (match(g->first, file)) + { lineset.insert(g->second.begin(), g->second.end()); } } From b3e19c24d384465b38eec44ee19e4cff0a932939 Mon Sep 17 00:00:00 2001 From: Raphael Geissert Date: Sat, 12 Feb 2011 15:40:30 -0600 Subject: [PATCH 19/24] Fix build when PATH_MAX is not defined POSIX says it _may_ be defined. Alternative implementation follows POSIX.1-2008. --- cli/filelister_unix.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/cli/filelister_unix.cpp b/cli/filelister_unix.cpp index f9263eb78..e961f9a84 100644 --- a/cli/filelister_unix.cpp +++ b/cli/filelister_unix.cpp @@ -60,8 +60,13 @@ void FileListerUnix::recursiveAddFiles2(std::vector &relative, if (filename[filename.length()-1] != '/') { // File +#ifdef PATH_MAX char fname[PATH_MAX]; if (realpath(filename.c_str(), fname) == NULL) +#else + char *fname; + if ((fname = realpath(filename.c_str(), NULL)) == NULL) +#endif { continue; } @@ -69,6 +74,9 @@ void FileListerUnix::recursiveAddFiles2(std::vector &relative, // Does absolute path exist? then bail out if (std::find(absolute.begin(), absolute.end(), std::string(fname)) != absolute.end()) { +#ifndef PATH_MAX + free(fname); +#endif continue; } @@ -77,6 +85,10 @@ void FileListerUnix::recursiveAddFiles2(std::vector &relative, relative.push_back(filename); absolute.push_back(fname); } + +#ifndef PATH_MAX + free(fname); +#endif } else { From a4fd5e873ec4ed110073219363b4e60eace21c0e Mon Sep 17 00:00:00 2001 From: Greg Hewgill Date: Sun, 13 Feb 2011 20:45:04 +1300 Subject: [PATCH 20/24] change failing tests into TODO_ASSERT_EQUALS --- test/testpreprocessor.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index 192f53dfb..dca4c9985 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -1258,8 +1258,10 @@ private: preprocessor.preprocess(istr, actual, "file.c"); // Compare results.. - ASSERT_EQUALS(2, static_cast(actual.size())); - ASSERT_EQUALS("\n\n\n\n", actual[""]); + TODO_ASSERT_EQUALS(2, + 1, static_cast(actual.size())); + TODO_ASSERT_EQUALS("\n\n\n\n", + "\n\nfoo();\n\n", actual[""]); } } From ad22aebf8cfd26730a6f1701cea3652490e4dd40 Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 13 Feb 2011 13:34:55 -0500 Subject: [PATCH 21/24] Really fix: #2376 (simplifyTypedef: upx-ucl) --- lib/tokenize.cpp | 151 ++++++++++++++++++++--------------------------- 1 file changed, 63 insertions(+), 88 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ad2e81738..ed76477ee 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -854,6 +854,65 @@ static Token *splitDefinitionFromTypedef(Token *tok) return tok; } +/* This function is called when processing function related typedefs. + * If simplifyTypedef generates an "Internal Error" message and the + * code that generated it deals in some way with functions, then this + * fucntion will probably need to be extended to handle a new function + * related pattern */ +static Token *processFunc(Token *tok2, bool inOperator) +{ + if (tok2->next() && tok2->next()->str() != ")" && + tok2->next()->str() != ",") + { + // skip over tokens for some types of canonicalization + if (Token::Match(tok2->next(), "( * %type% ) (")) + tok2 = tok2->tokAt(5)->link(); + else if (Token::Match(tok2->next(), "* ( * %type% ) (")) + tok2 = tok2->tokAt(6)->link(); + else if (Token::Match(tok2->next(), "* ( %type% [") && + Token::Match(tok2->tokAt(4)->link(), "] ) ;|=")) + tok2 = tok2->tokAt(4)->link()->next(); + else if (Token::Match(tok2->next(), "* ( * %type% (")) + tok2 = tok2->tokAt(5)->link()->next(); + else + { + if (tok2->next()->str() == "(") + tok2 = tok2->next()->link(); + else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) + { + tok2 = tok2->next(); + + while (Token::Match(tok2, "*|&") && + !Token::Match(tok2->next(), ")|>")) + tok2 = tok2->next(); + + // skip over namespace + while (Token::Match(tok2, "%var% ::")) + tok2 = tok2->tokAt(2); + + if (tok2->str() == "(" && + tok2->link()->next()->str() == "(") + { + tok2 = tok2->link(); + + if (tok2->next()->str() == "(") + tok2 = tok2->next()->link(); + } + + // skip over typedef parameter + if (tok2->next()->str() == "(") + { + tok2 = tok2->next()->link(); + + if (tok2->next()->str() == "(") + tok2 = tok2->next()->link(); + } + } + } + } + return tok2; +} + void Tokenizer::simplifyTypedef() { std::vector spaceInfo; @@ -1473,49 +1532,7 @@ void Tokenizer::simplifyTypedef() tok2 = copyTokens(tok2, funcStart, funcEnd); if (!inCast) - { - if (tok2->next() && tok2->next()->str() != ")" && - tok2->next()->str() != ",") - { - if (Token::Match(tok2->next(), "( * %type% ) (")) - tok2 = tok2->tokAt(5)->link(); - else - { - if (tok2->next()->str() == "(") - tok2 = tok2->next()->link(); - else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) - { - tok2 = tok2->next(); - - while (Token::Match(tok2, "*|&") && - !Token::Match(tok2->next(), ")|>")) - tok2 = tok2->next(); - - // skip over namespace - while (Token::Match(tok2, "%var% ::")) - tok2 = tok2->tokAt(2); - - if (tok2->str() == "(" && - tok2->link()->next()->str() == "(") - { - tok2 = tok2->link(); - - if (tok2->next()->str() == "(") - tok2 = tok2->next()->link(); - } - - // skip over typedef parameter - else if (tok2->next()->str() == "(") - { - tok2 = tok2->next()->link(); - - if (tok2->next()->str() == "(") - tok2 = tok2->next()->link(); - } - } - } - } - } + tok2 = processFunc(tok2, inOperator); tok2->insertToken(")"); tok2 = tok2->next(); @@ -1586,45 +1603,7 @@ void Tokenizer::simplifyTypedef() } if (!inCast) - { - if (tok2->next() && tok2->next()->str() != ")" && - tok2->next()->str() != ",") - { - if (Token::Match(tok2->next(), "( * %type% ) (")) - tok2 = tok2->tokAt(5)->link(); - else if (Token::Match(tok2->next(), "* ( * %type% ) (")) - tok2 = tok2->tokAt(6)->link(); - else if (Token::Match(tok2->next(), "* ( %type% [") && - Token::Match(tok2->tokAt(4)->link(), "] ) ;|=")) - tok2 = tok2->tokAt(4)->link()->next(); - else - { - if (tok2->next()->str() == "(") - tok2 = tok2->next()->link(); - else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) - { - tok2 = tok2->next(); - - while (Token::Match(tok2, "*|&") && - !Token::Match(tok2->next(), ")|>")) - tok2 = tok2->next(); - - // skip over namespace - while (Token::Match(tok2, "%var% ::")) - tok2 = tok2->tokAt(2); - - // skip over typedef parameter - if (tok2->next()->str() == "(") - { - tok2 = tok2->next()->link(); - - if (tok2->next()->str() == "(") - tok2 = tok2->next()->link(); - } - } - } - } - } + tok2 = processFunc(tok2, inOperator); if (needParen) { @@ -2290,14 +2269,10 @@ bool Tokenizer::tokenize(std::istream &code, // typedef.. simplifyTypedef(); - // Fix internal error by updating links (#2376) - // TODO: Remove this "createLinks". Make sure that the testcase - // TestSimplifyTokens::simplifyTypedefFunction8 - // doesn't fail. - if (!createLinks()) + // catch bad typedef canonicalization + if (!validate()) { // Source has syntax errors, can't proceed - cppcheckError(0); return false; } From c03ace73781f4fea6bd90b421a8a3199b72fb68e Mon Sep 17 00:00:00 2001 From: Robert Reif Date: Sun, 13 Feb 2011 14:11:22 -0500 Subject: [PATCH 22/24] Fix #2579 (segmentation fault of cppcheck) --- lib/tokenize.cpp | 2 +- test/testsimplifytokens.cpp | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ed76477ee..346405b8f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -8748,7 +8748,7 @@ void Tokenizer::simplifyStructDecl() } // unnamed anonymous struct/union so remove it - else if (tok->next()->str() == ";") + else if (tok->next() && tok->next()->str() == ";") { if (tok1->str() == "union") { diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 902b4567f..b79b99f58 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -304,7 +304,8 @@ private: TEST_CASE(initstruct); // struct ABC { } abc; => struct ABC { }; ABC abc; - TEST_CASE(simplifyStructDecl); + TEST_CASE(simplifyStructDecl1); + TEST_CASE(simplifyStructDecl2); // ticket #2579 // register int var; => int var; // inline int foo() {} => int foo() {} @@ -6222,7 +6223,7 @@ private: tok("; struct A a = { .buf = {0} };")); } - void simplifyStructDecl() + void simplifyStructDecl1() { { const char code[] = "struct ABC { } abc;"; @@ -6365,6 +6366,13 @@ private: } } + void simplifyStructDecl2() // ticket #2479 (segmentation fault) + { + const char code[] = "struct { char c; }"; + const char expected[] = "struct { char c ; }"; + ASSERT_EQUALS(expected, tok(code, false)); + } + void removeUnwantedKeywords() { ASSERT_EQUALS("int var ;", tok("register int var ;", true)); From 87cc42e6f0b0c8db37a314e5ef5be2c48cc3f4bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 21:42:35 +0100 Subject: [PATCH 23/24] Buffer overruns: Removed TODO test case. We intentionally don't check struct/class arrays fully to avoid false positives --- test/testbufferoverrun.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 4111dfa50..7de1c7775 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -1897,20 +1897,6 @@ private: " }\n" "}\n"); ASSERT_EQUALS("", errout.str()); - - check("class A {\n" - " void foo();\n" - " bool b[7];\n" - "};\n" - "\n" - "void A::foo() {\n" - " for (int i=0; i<7; i++) {\n" - " b[i] = b[i+1];\n" - " }\n" - "}\n"); - TODO_ASSERT_EQUALS("error", // wanted result - "", // current result - errout.str()); } void buffer_overrun_bailoutIfSwitch() From 87cf0949f2cd01c47194e058afe655fcff8e2ff3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 13 Feb 2011 21:48:13 +0100 Subject: [PATCH 24/24] Buffer overruns: Removed TODO test case. We intentionally don't check struct/class arrays fully to avoid false positives --- test/testbufferoverrun.cpp | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/test/testbufferoverrun.cpp b/test/testbufferoverrun.cpp index 7de1c7775..768507400 100644 --- a/test/testbufferoverrun.cpp +++ b/test/testbufferoverrun.cpp @@ -84,7 +84,6 @@ private: TEST_CASE(array_index_7); TEST_CASE(array_index_8); TEST_CASE(array_index_9); - TEST_CASE(array_index_10); TEST_CASE(array_index_11); TEST_CASE(array_index_12); TEST_CASE(array_index_13); @@ -598,27 +597,6 @@ private: } - void array_index_10() - { - check("struct ABC\n" - "{\n" - " char str[10];\n" - "};\n" - "\n" - "static void memclr( char *data )\n" - "{\n" - " data[10] = 0;\n" - "}\n" - "\n" - "static void f(struct ABC *abc)\n" - "{\n" - " memclr(abc->str);\n" - "}\n"); - TODO_ASSERT_EQUALS("[test.cpp:13] -> [test.cpp:8]: (possible error) Array index out of bounds\n", - "", errout.str()); - } - - void array_index_11() { check("class ABC\n"