From d6d55c2db48014aca7a70513adecba404a4ccbc0 Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Mon, 18 May 2009 23:32:04 +0300 Subject: [PATCH] Fix ticket #315 (Segmentation fault when checking Linux kernel) http://apps.sourceforge.net/trac/cppcheck/ticket/315 --- src/preprocessor.cpp | 70 +++++++++++++++++++++++++++++++++++---- test/testpreprocessor.cpp | 23 +++++++++++++ 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/src/preprocessor.cpp b/src/preprocessor.cpp index eec7e76e3..b99373d46 100644 --- a/src/preprocessor.cpp +++ b/src/preprocessor.cpp @@ -713,10 +713,8 @@ public: return _name; } - const std::string code(const std::vector ¶ms2) const + bool code(const std::vector ¶ms2, std::string ¯ocode) const { - std::string macrocode; - if (_params.empty()) { std::string::size_type pos = _macro.find(" "); @@ -765,12 +763,18 @@ public: optcomma = false; str += params2[j]; } - break; } - if (stringify) + else if (i >= params2.size()) + { + // Macro had more parameters than caller used. + macrocode = ""; + return false; + } + else if (stringify) str = "\"" + params2[i] + "\""; else str = params2[i]; + break; } } @@ -788,7 +792,7 @@ public: } } - return macrocode; + return true; } }; @@ -879,6 +883,7 @@ std::string Preprocessor::expandMacros(std::string code, const std::string &file if (errorLogger) { + // TODO, duplicate code. Refactor std::string fname(filename); int lineno = 0; for (std::string::size_type p = pos1; p > 0; --p) @@ -1022,7 +1027,58 @@ std::string Preprocessor::expandMacros(std::string code, const std::string &file continue; // Create macro code.. - const std::string macrocode(std::string(numberOfNewlines, '\n') + macro.code(params)); + std::string tempMacro; + if (!macro.code(params, tempMacro)) + { + // Syntax error in code + if (errorLogger) + { + std::string fname(filename); + int lineno = 1; + for (std::string::size_type p = pos1; p > 0; --p) + { + // newline.. + if (code[p-1] == '\n') + lineno++; + + // #file.. + else if (code[p-1] == '#') + { + // Previous char should be a newline.. + if (p == 1 || code[p-2] == '\n') + { + // #file.. + if (code.substr(p - 1, 6) == "#file ") + { + fname = code.substr(p + 5, code.find("\n", p) - p - 5); + break; + } + + else + ++lineno; + } + } + + // start of file.. + else if (p == 1) + ++lineno; + } + + std::list locationList; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.line = lineno; + loc.file = fname; + locationList.push_back(loc); + errorLogger->reportErr( + ErrorLogger::ErrorMessage(locationList, + "error", + std::string("Syntax error. Not enough parameters for macro '") + macro.name() + "'.", + "syntaxError")); + } + return ""; + } + + const std::string macrocode(std::string(numberOfNewlines, '\n') + tempMacro); // Insert macro code.. if (!macro.params().empty()) diff --git a/test/testpreprocessor.cpp b/test/testpreprocessor.cpp index ec994fa12..ac2f94783 100644 --- a/test/testpreprocessor.cpp +++ b/test/testpreprocessor.cpp @@ -124,6 +124,7 @@ private: TEST_CASE(define_part_of_func); TEST_CASE(conditionalDefine); TEST_CASE(multiline_comment); + TEST_CASE(macro_parameters); } @@ -1008,6 +1009,28 @@ private: ASSERT_EQUALS("", errout.str()); } + void macro_parameters() + { + errout.str(""); + const char filedata[] = "#define BC(a, b, c, arg...) \\\n" + "AB(a, b, c, ## arg)\n" + "\n" + "void f()\n" + "{\n" + " BC(3);\n" + "}\n"; + + // Preprocess => actual result.. + std::istringstream istr(filedata); + std::map actual; + Preprocessor preprocessor; + preprocessor.preprocess(istr, actual, "file.c", std::list(), this); + + // Compare results.. + ASSERT_EQUALS(1, static_cast(actual.size())); + ASSERT_EQUALS("", actual[""]); + ASSERT_EQUALS("[file.c:6]: (error) Syntax error. Not enough parameters for macro 'BC'.\n", errout.str()); + } };