diff --git a/cfg/std.cfg b/cfg/std.cfg index 36f0b53d9..d0ff90e10 100644 --- a/cfg/std.cfg +++ b/cfg/std.cfg @@ -4507,20 +4507,7 @@ - - false - - - - - - - - - - - - + false diff --git a/lib/library.cpp b/lib/library.cpp index 63d8712cf..412ec5be6 100644 --- a/lib/library.cpp +++ b/lib/library.cpp @@ -178,119 +178,17 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) if (name_char == nullptr) return Error(MISSING_ATTRIBUTE, "name"); std::string name = name_char; - - for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { - const std::string functionnodename = functionnode->Name(); - if (functionnodename == "noreturn") - _noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0); - else if (functionnodename == "pure") - functionpure.insert(name); - else if (functionnodename == "const") { - functionconst.insert(name); - functionpure.insert(name); // a constant function is pure - } else if (functionnodename == "leak-ignore") - leakignore.insert(name); - else if (functionnodename == "use-retval") - useretval.insert(name); - else if (functionnodename == "arg" && functionnode->Attribute("nr") != nullptr) { - const bool bAnyArg = strcmp(functionnode->Attribute("nr"),"any")==0; - const int nr = (bAnyArg) ? -1 : atoi(functionnode->Attribute("nr")); - bool notbool = false; - bool notnull = false; - bool notuninit = false; - bool formatstr = false; - bool strz = false; - std::string& valid = argumentChecks[name][nr].valid; - std::list& minsizes = argumentChecks[name][nr].minsizes; - for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) { - const std::string argnodename = argnode->Name(); - if (argnodename == "not-bool") - notbool = true; - else if (argnodename == "not-null") - notnull = true; - else if (argnodename == "not-uninit") - notuninit = true; - else if (argnodename == "formatstr") - formatstr = true; - else if (argnodename == "strz") - strz = true; - else if (argnodename == "valid") { - // Validate the validation expression - const char *p = argnode->GetText(); - bool error = false; - bool range = false; - for (; *p; p++) { - if (std::isdigit(*p)) - error |= (*(p+1) == '-'); - else if (*p == ':') - error |= range; - else if (*p == '-') - error |= (!std::isdigit(*(p+1))); - else if (*p == ',') - range = false; - else - error = true; - - range |= (*p == ':'); - } - if (error) - return Error(BAD_ATTRIBUTE_VALUE, argnode->GetText()); - - // Set validation expression - valid = argnode->GetText(); - } - - else if (argnodename == "minsize") { - const char *typeattr = argnode->Attribute("type"); - if (!typeattr) - return Error(MISSING_ATTRIBUTE, "type"); - - ArgumentChecks::MinSize::Type type; - if (strcmp(typeattr,"strlen")==0) - type = ArgumentChecks::MinSize::STRLEN; - else if (strcmp(typeattr,"argvalue")==0) - type = ArgumentChecks::MinSize::ARGVALUE; - else if (strcmp(typeattr,"sizeof")==0) - type = ArgumentChecks::MinSize::SIZEOF; - else if (strcmp(typeattr,"mul")==0) - type = ArgumentChecks::MinSize::MUL; - else - return Error(BAD_ATTRIBUTE_VALUE, typeattr); - - const char *argattr = argnode->Attribute("arg"); - if (!argattr) - return Error(MISSING_ATTRIBUTE, "arg"); - if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9') - return Error(BAD_ATTRIBUTE_VALUE, argattr); - - minsizes.push_back(ArgumentChecks::MinSize(type,argattr[0]-'0')); - if (type == ArgumentChecks::MinSize::MUL) { - const char *arg2attr = argnode->Attribute("arg2"); - if (!arg2attr) - return Error(MISSING_ATTRIBUTE, "arg2"); - if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9') - return Error(BAD_ATTRIBUTE_VALUE, arg2attr); - minsizes.back().arg2 = arg2attr[0] - '0'; - } - } - - else - unknown_elements.insert(argnodename); - } - argumentChecks[name][nr].notbool = notbool; - argumentChecks[name][nr].notnull = notnull; - argumentChecks[name][nr].notuninit = notuninit; - argumentChecks[name][nr].formatstr = formatstr; - argumentChecks[name][nr].strz = strz; - } else if (functionnodename == "ignorefunction") { - _ignorefunction.insert(name); - } else if (functionnodename == "formatstr") { - const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan"); - const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure"); - _formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue()); - } else - unknown_elements.insert(functionnodename); + while (name.find(",") != std::string::npos) { + const std::string::size_type pos = name.find(","); + const Error &err = loadFunction(node, name.substr(0,pos), unknown_elements); + if (err.errorcode != ErrorCode::OK) + return err; + name.erase(0,pos+1); } + + const Error &err = loadFunction(node, name, unknown_elements); + if (err.errorcode != ErrorCode::OK) + return err; } else if (nodename == "reflection") { @@ -581,6 +479,126 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc) return Error(OK); } +Library::Error Library::loadFunction(const tinyxml2::XMLElement * const node, const std::string &name, std::set &unknown_elements) +{ + if (name.empty()) + return Error(OK); + + for (const tinyxml2::XMLElement *functionnode = node->FirstChildElement(); functionnode; functionnode = functionnode->NextSiblingElement()) { + const std::string functionnodename = functionnode->Name(); + if (functionnodename == "noreturn") + _noreturn[name] = (strcmp(functionnode->GetText(), "true") == 0); + else if (functionnodename == "pure") + functionpure.insert(name); + else if (functionnodename == "const") { + functionconst.insert(name); + functionpure.insert(name); // a constant function is pure + } else if (functionnodename == "leak-ignore") + leakignore.insert(name); + else if (functionnodename == "use-retval") + useretval.insert(name); + else if (functionnodename == "arg" && functionnode->Attribute("nr") != nullptr) { + const bool bAnyArg = strcmp(functionnode->Attribute("nr"),"any")==0; + const int nr = (bAnyArg) ? -1 : atoi(functionnode->Attribute("nr")); + bool notbool = false; + bool notnull = false; + bool notuninit = false; + bool formatstr = false; + bool strz = false; + std::string& valid = argumentChecks[name][nr].valid; + std::list& minsizes = argumentChecks[name][nr].minsizes; + for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) { + const std::string argnodename = argnode->Name(); + if (argnodename == "not-bool") + notbool = true; + else if (argnodename == "not-null") + notnull = true; + else if (argnodename == "not-uninit") + notuninit = true; + else if (argnodename == "formatstr") + formatstr = true; + else if (argnodename == "strz") + strz = true; + else if (argnodename == "valid") { + // Validate the validation expression + const char *p = argnode->GetText(); + bool error = false; + bool range = false; + for (; *p; p++) { + if (std::isdigit(*p)) + error |= (*(p+1) == '-'); + else if (*p == ':') + error |= range; + else if (*p == '-') + error |= (!std::isdigit(*(p+1))); + else if (*p == ',') + range = false; + else + error = true; + + range |= (*p == ':'); + } + if (error) + return Error(BAD_ATTRIBUTE_VALUE, argnode->GetText()); + + // Set validation expression + valid = argnode->GetText(); + } + + else if (argnodename == "minsize") { + const char *typeattr = argnode->Attribute("type"); + if (!typeattr) + return Error(MISSING_ATTRIBUTE, "type"); + + ArgumentChecks::MinSize::Type type; + if (strcmp(typeattr,"strlen")==0) + type = ArgumentChecks::MinSize::STRLEN; + else if (strcmp(typeattr,"argvalue")==0) + type = ArgumentChecks::MinSize::ARGVALUE; + else if (strcmp(typeattr,"sizeof")==0) + type = ArgumentChecks::MinSize::SIZEOF; + else if (strcmp(typeattr,"mul")==0) + type = ArgumentChecks::MinSize::MUL; + else + return Error(BAD_ATTRIBUTE_VALUE, typeattr); + + const char *argattr = argnode->Attribute("arg"); + if (!argattr) + return Error(MISSING_ATTRIBUTE, "arg"); + if (strlen(argattr) != 1 || argattr[0]<'0' || argattr[0]>'9') + return Error(BAD_ATTRIBUTE_VALUE, argattr); + + minsizes.push_back(ArgumentChecks::MinSize(type,argattr[0]-'0')); + if (type == ArgumentChecks::MinSize::MUL) { + const char *arg2attr = argnode->Attribute("arg2"); + if (!arg2attr) + return Error(MISSING_ATTRIBUTE, "arg2"); + if (strlen(arg2attr) != 1 || arg2attr[0]<'0' || arg2attr[0]>'9') + return Error(BAD_ATTRIBUTE_VALUE, arg2attr); + minsizes.back().arg2 = arg2attr[0] - '0'; + } + } + + else + unknown_elements.insert(argnodename); + } + argumentChecks[name][nr].notbool = notbool; + argumentChecks[name][nr].notnull = notnull; + argumentChecks[name][nr].notuninit = notuninit; + argumentChecks[name][nr].formatstr = formatstr; + argumentChecks[name][nr].strz = strz; + } else if (functionnodename == "ignorefunction") { + _ignorefunction.insert(name); + } else if (functionnodename == "formatstr") { + const tinyxml2::XMLAttribute* scan = functionnode->FindAttribute("scan"); + const tinyxml2::XMLAttribute* secure = functionnode->FindAttribute("secure"); + _formatstr[name] = std::make_pair(scan && scan->BoolValue(), secure && secure->BoolValue()); + } else + unknown_elements.insert(functionnodename); + } + return Error(OK); +} + bool Library::isargvalid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const { const ArgumentChecks *ac = getarg(ftok, argnr); diff --git a/lib/library.h b/lib/library.h index 83ce7d9e0..883853c2b 100644 --- a/lib/library.h +++ b/lib/library.h @@ -33,6 +33,7 @@ class TokenList; namespace tinyxml2 { class XMLDocument; + class XMLElement; } /// @addtogroup Core @@ -379,6 +380,9 @@ public: } private: + // load a xml node + Error loadFunction(const tinyxml2::XMLElement * const node, const std::string &name, std::set &unknown_elements); + class ExportedFunctions { public: void addPrefix(const std::string& prefix) { diff --git a/test/testlibrary.cpp b/test/testlibrary.cpp index 4e5eed258..7aa6fb3c9 100644 --- a/test/testlibrary.cpp +++ b/test/testlibrary.cpp @@ -292,23 +292,32 @@ private: void function_namespace() const { const char xmldata[] = "\n" "\n" - " \n" + " \n" " false\n" " \n" ""; tinyxml2::XMLDocument doc; doc.Parse(xmldata, sizeof(xmldata)); - TokenList tokenList(nullptr); - std::istringstream istr("Foo::foo();"); - tokenList.createTokens(istr); - Library library; library.load(doc); ASSERT(library.use.empty()); ASSERT(library.leakignore.empty()); ASSERT(library.argumentChecks.empty()); - ASSERT(library.isnotnoreturn(tokenList.front()->tokAt(2))); + + { + TokenList tokenList(nullptr); + std::istringstream istr("Foo::foo();"); + tokenList.createTokens(istr); + ASSERT(library.isnotnoreturn(tokenList.front()->tokAt(2))); + } + + { + TokenList tokenList(nullptr); + std::istringstream istr("bar();"); + tokenList.createTokens(istr); + ASSERT(library.isnotnoreturn(tokenList.front())); + } } void memory() const {