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 {