Library: added <formatstr> and <strz> to argument checks
This commit is contained in:
parent
20f81f92d9
commit
a1fafa7f06
|
@ -439,7 +439,26 @@ void CheckIO::checkWrongPrintfScanfArguments()
|
||||||
const Token* argListTok = 0; // Points to first va_list argument
|
const Token* argListTok = 0; // Points to first va_list argument
|
||||||
std::string formatString;
|
std::string formatString;
|
||||||
|
|
||||||
if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%")) {
|
if (Token::Match(tok->next(), "( %any%")) {
|
||||||
|
const Token *arg = tok->tokAt(2);
|
||||||
|
int argnr = 1;
|
||||||
|
while (arg) {
|
||||||
|
if (Token::Match(arg, "%str% [,)]") && _settings->library.isargformatstr(tok->str(),argnr)) {
|
||||||
|
formatString = arg->str();
|
||||||
|
if (arg->strAt(1) == ",")
|
||||||
|
argListTok = arg->tokAt(2);
|
||||||
|
else
|
||||||
|
argListTok = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg = arg->nextArgument();
|
||||||
|
argnr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!formatString.empty()) { /* formatstring found in library */ }
|
||||||
|
else if (Token::Match(tok, "printf|scanf|wprintf|wscanf ( %str%")) {
|
||||||
formatString = tok->strAt(2);
|
formatString = tok->strAt(2);
|
||||||
if (tok->strAt(3) == ",") {
|
if (tok->strAt(3) == ",") {
|
||||||
argListTok = tok->tokAt(4);
|
argListTok = tok->tokAt(4);
|
||||||
|
|
|
@ -121,16 +121,24 @@ bool Library::load(const char exename[], const char path[])
|
||||||
const int nr = atoi(functionnode->Attribute("nr"));
|
const int nr = atoi(functionnode->Attribute("nr"));
|
||||||
bool notnull = false;
|
bool notnull = false;
|
||||||
bool notuninit = false;
|
bool notuninit = false;
|
||||||
|
bool formatstr = false;
|
||||||
|
bool strz = false;
|
||||||
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
|
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
|
||||||
if (strcmp(argnode->Name(), "not-null") == 0)
|
if (strcmp(argnode->Name(), "not-null") == 0)
|
||||||
notnull = true;
|
notnull = true;
|
||||||
else if (strcmp(argnode->Name(), "not-uninit") == 0)
|
else if (strcmp(argnode->Name(), "not-uninit") == 0)
|
||||||
notuninit = true;
|
notuninit = true;
|
||||||
|
else if (strcmp(argnode->Name(), "formatstr") == 0)
|
||||||
|
notuninit = true;
|
||||||
|
else if (strcmp(argnode->Name(), "strz") == 0)
|
||||||
|
notuninit = true;
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
argumentChecks[name][nr].notnull = notnull;
|
argumentChecks[name][nr].notnull = notnull;
|
||||||
argumentChecks[name][nr].notuninit = notuninit;
|
argumentChecks[name][nr].notuninit = notuninit;
|
||||||
|
argumentChecks[name][nr].formatstr = formatstr;
|
||||||
|
argumentChecks[name][nr].strz = strz;
|
||||||
} else
|
} else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,8 +81,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ArgumentChecks {
|
struct ArgumentChecks {
|
||||||
|
ArgumentChecks() {
|
||||||
|
notnull = notuninit = formatstr = strz = false;
|
||||||
|
}
|
||||||
|
|
||||||
bool notnull;
|
bool notnull;
|
||||||
bool notuninit;
|
bool notuninit;
|
||||||
|
bool formatstr;
|
||||||
|
bool strz;
|
||||||
};
|
};
|
||||||
|
|
||||||
// function name, argument nr => argument data
|
// function name, argument nr => argument data
|
||||||
|
@ -98,6 +104,16 @@ public:
|
||||||
return arg && arg->notuninit;
|
return arg && arg->notuninit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isargformatstr(const std::string &functionName, int argnr) const {
|
||||||
|
const ArgumentChecks *arg = getarg(functionName,argnr);
|
||||||
|
return arg && arg->formatstr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isargstrz(const std::string &functionName, int argnr) const {
|
||||||
|
const ArgumentChecks *arg = getarg(functionName,argnr);
|
||||||
|
return arg && arg->strz;
|
||||||
|
}
|
||||||
|
|
||||||
std::set<std::string> returnuninitdata;
|
std::set<std::string> returnuninitdata;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -48,9 +48,11 @@ private:
|
||||||
TEST_CASE(testPrintfArgument);
|
TEST_CASE(testPrintfArgument);
|
||||||
|
|
||||||
TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902
|
TEST_CASE(testMicrosoftPrintfArgument); // ticket #4902
|
||||||
|
|
||||||
|
TEST_CASE(testlibrarycfg); // library configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], bool inconclusive = false, bool portability = false, Settings::PlatformType platform = Settings::Unspecified) {
|
void check(const char code[], bool inconclusive = false, bool portability = false, Settings::PlatformType platform = Settings::Unspecified, Library *lib = NULL) {
|
||||||
// Clear the error buffer..
|
// Clear the error buffer..
|
||||||
errout.str("");
|
errout.str("");
|
||||||
|
|
||||||
|
@ -62,6 +64,9 @@ private:
|
||||||
settings.inconclusive = inconclusive;
|
settings.inconclusive = inconclusive;
|
||||||
settings.platform(platform);
|
settings.platform(platform);
|
||||||
|
|
||||||
|
if (lib)
|
||||||
|
settings.library = *lib;
|
||||||
|
|
||||||
// Tokenize..
|
// Tokenize..
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
std::istringstream istr(code);
|
std::istringstream istr(code);
|
||||||
|
@ -797,6 +802,22 @@ private:
|
||||||
"[test.cpp:12]: (warning) %I64u in format string (no. 2) requires an unsigned integer given in the argument list.\n"
|
"[test.cpp:12]: (warning) %I64u in format string (no. 2) requires an unsigned integer given in the argument list.\n"
|
||||||
"[test.cpp:13]: (warning) %I64d in format string (no. 1) requires a signed integer given in the argument list.\n", errout.str());
|
"[test.cpp:13]: (warning) %I64d in format string (no. 1) requires a signed integer given in the argument list.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testlibrarycfg() {
|
||||||
|
const char code[] = "void f() {\n"
|
||||||
|
" format(\"%s\");\n"
|
||||||
|
"}";
|
||||||
|
|
||||||
|
// no error if configuration for 'format' is not provided
|
||||||
|
check(code);
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// error if configuration for 'format' is provided
|
||||||
|
Library lib;
|
||||||
|
lib.argumentChecks["format"][1].formatstr = true;
|
||||||
|
check(code, false, false, Settings::Unspecified, &lib);
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (error) format format string has 1 parameters but only 0 are given.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestIO)
|
REGISTER_TEST(TestIO)
|
||||||
|
|
|
@ -2116,7 +2116,7 @@ private:
|
||||||
// nothing bad..
|
// nothing bad..
|
||||||
{
|
{
|
||||||
Library library;
|
Library library;
|
||||||
Library::ArgumentChecks arg = {false, false};
|
Library::ArgumentChecks arg;
|
||||||
library.argumentChecks["x"][1] = arg;
|
library.argumentChecks["x"][1] = arg;
|
||||||
library.argumentChecks["x"][2] = arg;
|
library.argumentChecks["x"][2] = arg;
|
||||||
|
|
||||||
|
@ -2130,7 +2130,7 @@ private:
|
||||||
// for 1st parameter null pointer is not ok..
|
// for 1st parameter null pointer is not ok..
|
||||||
{
|
{
|
||||||
Library library;
|
Library library;
|
||||||
struct Library::ArgumentChecks arg = {false, false};
|
struct Library::ArgumentChecks arg;
|
||||||
library.argumentChecks["x"][1] = arg;
|
library.argumentChecks["x"][1] = arg;
|
||||||
library.argumentChecks["x"][2] = arg;
|
library.argumentChecks["x"][2] = arg;
|
||||||
library.argumentChecks["x"][1].notnull = true;
|
library.argumentChecks["x"][1].notnull = true;
|
||||||
|
@ -2146,7 +2146,7 @@ private:
|
||||||
// for 2nd parameter uninit data is not ok..
|
// for 2nd parameter uninit data is not ok..
|
||||||
{
|
{
|
||||||
Library library;
|
Library library;
|
||||||
Library::ArgumentChecks arg = {false, false};
|
Library::ArgumentChecks arg;
|
||||||
library.argumentChecks["x"][1] = arg;
|
library.argumentChecks["x"][1] = arg;
|
||||||
library.argumentChecks["x"][2] = arg;
|
library.argumentChecks["x"][2] = arg;
|
||||||
library.argumentChecks["x"][2].notuninit = true;
|
library.argumentChecks["x"][2].notuninit = true;
|
||||||
|
|
Loading…
Reference in New Issue