From 2564153ce6b2023405cc7a684c9ddf7cdafe6b66 Mon Sep 17 00:00:00 2001 From: firewave Date: Sat, 23 Nov 2024 14:20:15 +0100 Subject: [PATCH] fixed #386 - rewrote define handling [skip ci] --- simplecpp.cpp | 67 ++++++++++++++++++++++++++++++++++-------------- simplecpp.h | 24 ++++++++++++++++-- test.cpp | 70 +++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 130 insertions(+), 31 deletions(-) diff --git a/simplecpp.cpp b/simplecpp.cpp index 0621fe06..57e5f640 100644 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3289,25 +3289,28 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL // use a dummy vector for the macros because as this is not part of the file and would add an empty entry - e.g. /usr/include/poll.h std::vector dummy; + bool strictAnsiDefined = false; + bool strictAnsiUndefined = false; const bool hasInclude = isCpp17OrLater(dui) || isGnu(dui); MacroMap macros; - bool strictAnsiDefined = false; - for (std::list::const_iterator it = dui.defines.begin(); it != dui.defines.end(); ++it) { - const std::string ¯ostr = *it; - const std::string::size_type eq = macrostr.find('='); - const std::string::size_type par = macrostr.find('('); - const std::string macroname = macrostr.substr(0, std::min(eq,par)); - if (macroname == "__STRICT_ANSI__") - strictAnsiDefined = true; - if (dui.undefined.find(macroname) != dui.undefined.end()) + for (std::list::const_iterator it = dui.defines.cbegin(); it != dui.defines.cend(); ++it) { + const std::string& lhs(it->name); + if (it->undef) { + if (lhs == "__STRICT_ANSI__") + strictAnsiUndefined = true; + const MacroMap::iterator m_it = macros.find(lhs); + if (m_it != macros.end()) + macros.erase(m_it); continue; - const std::string lhs(macrostr.substr(0,eq)); - const std::string rhs(eq==std::string::npos ? std::string("1") : macrostr.substr(eq+1)); + } + if (lhs == "__STRICT_ANSI__") + strictAnsiDefined = true; + const std::string rhs(it->value.empty() ? "1" : it->value); const Macro macro(lhs, rhs, dummy); macros.insert(std::pair(macro.name(), macro)); } - const bool strictAnsiUndefined = dui.undefined.find("__STRICT_ANSI__") != dui.undefined.cend(); + // TODO: test left-to-right if (!isGnu(dui) && !strictAnsiDefined && !strictAnsiUndefined) macros.insert(std::pair("__STRICT_ANSI__", Macro("__STRICT_ANSI__", "1", dummy))); @@ -3418,13 +3421,11 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL continue; try { const Macro ¯o = Macro(rawtok->previous, files); - if (dui.undefined.find(macro.name()) == dui.undefined.end()) { - const MacroMap::iterator it = macros.find(macro.name()); - if (it == macros.end()) - macros.insert(std::pair(macro.name(), macro)); - else - it->second = macro; - } + const MacroMap::iterator it = macros.find(macro.name()); + if (it == macros.end()) + macros.insert(std::pair(macro.name(), macro)); + else + it->second = macro; } catch (const std::runtime_error &) { if (outputList) { simplecpp::Output err(files); @@ -3857,3 +3858,31 @@ std::string simplecpp::getCppStdString(const std::string &std) { return getCppStdString(getCppStd(std)); } + +simplecpp::Define simplecpp::Define::parse(const std::string& def, bool prefix) +{ + Define define; + std::string::size_type offset = 0; + if (prefix) { + if (def.size() < 3) + throw 0; + if (def[0] != '-') + throw 0; + if (def[1] == 'U') + define.undef = true; + else if (def[1] != 'D') + throw 0; + offset = 2; + } + const std::string::size_type sep = def.find('='); + if (sep == std::string::npos) { + define.name = def.substr(offset); + } + else { + if (define.undef) + throw 0; + define.name = def.substr(offset, sep - offset); + define.value = def.substr(sep + 1); + } + return define; +} diff --git a/simplecpp.h b/simplecpp.h index a014a6fc..70a26fcf 100644 --- a/simplecpp.h +++ b/simplecpp.h @@ -7,6 +7,7 @@ #define simplecppH #include +#include #include #include #include @@ -389,14 +390,33 @@ namespace simplecpp { long long result; // condition result }; + struct SIMPLECPP_LIB Define { + enum Type : std::uint8_t { + Def, + Undef, + Builtin + }; + + Define() : undef(false) {} + Define(const std::string& def, Type t = Def) : undef(t == Undef) { + const Define d = parse(def, false); + name = d.name; + value = d.value; + } + std::string name; + std::string value; + bool undef; + + static Define parse(const std::string& def, bool prefix = true); /** parse -D/-U string */ + }; + /** * Command line preprocessor settings. * On the command line these are configured by -D, -U, -I, --include, -std */ struct SIMPLECPP_LIB DUI { DUI() : clearIncludeCache(false), removeComments(false) {} - std::list defines; - std::set undefined; + std::list defines; std::list includePaths; std::list includes; std::string std; diff --git a/test.cpp b/test.cpp index f1fe2d1c..10a99a85 100644 --- a/test.cpp +++ b/test.cpp @@ -1706,7 +1706,7 @@ static void strict_ansi_3() "#endif"; simplecpp::DUI dui; dui.std = "c99"; - dui.undefined.insert("__STRICT_ANSI__"); + dui.defines.emplace_back("__STRICT_ANSI__", simplecpp::Define::Undef); ASSERT_EQUALS("", preprocess(code, dui)); } @@ -1717,7 +1717,7 @@ static void strict_ansi_4() "#endif"; simplecpp::DUI dui; dui.std = "gnu99"; - dui.defines.push_back("__STRICT_ANSI__"); + dui.defines.emplace_back("__STRICT_ANSI__"); ASSERT_EQUALS("\nA", preprocess(code, dui)); } @@ -1764,7 +1764,7 @@ static void ifA() ASSERT_EQUALS("", preprocess(code)); simplecpp::DUI dui; - dui.defines.push_back("A=1"); + dui.defines.emplace_back("A=1"); ASSERT_EQUALS("\nX", preprocess(code, dui)); } @@ -1783,7 +1783,7 @@ static void ifDefined() "#endif"; simplecpp::DUI dui; ASSERT_EQUALS("", preprocess(code, dui)); - dui.defines.push_back("A=1"); + dui.defines.emplace_back("A=1"); ASSERT_EQUALS("\nX", preprocess(code, dui)); } @@ -1794,7 +1794,7 @@ static void ifDefinedNoPar() "#endif"; simplecpp::DUI dui; ASSERT_EQUALS("", preprocess(code, dui)); - dui.defines.push_back("A=1"); + dui.defines.emplace_back("A=1"); ASSERT_EQUALS("\nX", preprocess(code, dui)); } @@ -1806,7 +1806,7 @@ static void ifDefinedNested() "#endif"; simplecpp::DUI dui; ASSERT_EQUALS("", preprocess(code, dui)); - dui.defines.push_back("FOO=1"); + dui.defines.emplace_back("FOO=1"); ASSERT_EQUALS("\n\nX", preprocess(code, dui)); } @@ -1818,7 +1818,7 @@ static void ifDefinedNestedNoPar() "#endif"; simplecpp::DUI dui; ASSERT_EQUALS("", preprocess(code, dui)); - dui.defines.push_back("FOO=1"); + dui.defines.emplace_back("FOO=1"); ASSERT_EQUALS("\n\nX", preprocess(code, dui)); } @@ -1871,10 +1871,10 @@ static void ifLogical() simplecpp::DUI dui; ASSERT_EQUALS("", preprocess(code, dui)); dui.defines.clear(); - dui.defines.push_back("A=1"); + dui.defines.emplace_back("A=1"); ASSERT_EQUALS("\nX", preprocess(code, dui)); dui.defines.clear(); - dui.defines.push_back("B=1"); + dui.defines.emplace_back("B=1"); ASSERT_EQUALS("\nX", preprocess(code, dui)); } @@ -2768,7 +2768,7 @@ static void userdef() { const char code[] = "#ifdef A\n123\n#endif\n"; simplecpp::DUI dui; - dui.defines.push_back("A=1"); + dui.defines.emplace_back("A=1"); ASSERT_EQUALS("\n123", preprocess(code, dui)); } @@ -3246,6 +3246,54 @@ static void safe_api() #endif } +static void define_parse() +{ + { + const simplecpp::Define define = simplecpp::Define::parse("-DDEF"); + ASSERT_EQUALS("DEF", define.name); + ASSERT_EQUALS("", define.value); + ASSERT_EQUALS(false, define.undef); + } + { + const simplecpp::Define define = simplecpp::Define::parse("-DDEF=1"); + ASSERT_EQUALS("DEF", define.name); + ASSERT_EQUALS("1", define.value); + ASSERT_EQUALS(false, define.undef); + } + { + const simplecpp::Define define = simplecpp::Define::parse("-UDEF"); + ASSERT_EQUALS("DEF", define.name); + ASSERT_EQUALS("", define.value); + ASSERT_EQUALS(true, define.undef); + } + + { + const simplecpp::Define define = simplecpp::Define::parse("DEF", false); + ASSERT_EQUALS("DEF", define.name); + ASSERT_EQUALS("", define.value); + ASSERT_EQUALS(false, define.undef); + } + { + const simplecpp::Define define = simplecpp::Define::parse("DEF=1", false); + ASSERT_EQUALS("DEF", define.name); + ASSERT_EQUALS("1", define.value); + ASSERT_EQUALS(false, define.undef); + } + { + const simplecpp::Define define = simplecpp::Define::parse("-D__has_builtin(x)=(1)", true); + ASSERT_EQUALS("__has_builtin(x)", define.name); + ASSERT_EQUALS("(1)", define.value); + ASSERT_EQUALS(false, define.undef); + } + { + const simplecpp::Define define = simplecpp::Define::parse("__has_builtin(x)=(1)", false); + ASSERT_EQUALS("__has_builtin(x)", define.name); + ASSERT_EQUALS("(1)", define.value); + ASSERT_EQUALS(false, define.undef); + } + // -UDEF=0 +} + static void fuzz_crash() { { @@ -3514,6 +3562,8 @@ int main(int argc, char **argv) TEST_CASE(safe_api); + TEST_CASE(define_parse); + TEST_CASE(fuzz_crash); return numberOfFailedAssertions > 0 ? EXIT_FAILURE : EXIT_SUCCESS;