Library: added <formatstr> and <strz> to argument checks

This commit is contained in:
Daniel Marjamäki 2013-07-22 20:21:45 +02:00
parent 20f81f92d9
commit a1fafa7f06
5 changed files with 69 additions and 5 deletions

View File

@ -439,7 +439,26 @@ void CheckIO::checkWrongPrintfScanfArguments()
const Token* argListTok = 0; // Points to first va_list argument
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);
if (tok->strAt(3) == ",") {
argListTok = tok->tokAt(4);

View File

@ -121,16 +121,24 @@ bool Library::load(const char exename[], const char path[])
const int nr = atoi(functionnode->Attribute("nr"));
bool notnull = false;
bool notuninit = false;
bool formatstr = false;
bool strz = false;
for (const tinyxml2::XMLElement *argnode = functionnode->FirstChildElement(); argnode; argnode = argnode->NextSiblingElement()) {
if (strcmp(argnode->Name(), "not-null") == 0)
notnull = true;
else if (strcmp(argnode->Name(), "not-uninit") == 0)
notuninit = true;
else if (strcmp(argnode->Name(), "formatstr") == 0)
notuninit = true;
else if (strcmp(argnode->Name(), "strz") == 0)
notuninit = true;
else
return false;
}
argumentChecks[name][nr].notnull = notnull;
argumentChecks[name][nr].notuninit = notuninit;
argumentChecks[name][nr].formatstr = formatstr;
argumentChecks[name][nr].strz = strz;
} else
return false;
}

View File

@ -81,8 +81,14 @@ public:
}
struct ArgumentChecks {
ArgumentChecks() {
notnull = notuninit = formatstr = strz = false;
}
bool notnull;
bool notuninit;
bool formatstr;
bool strz;
};
// function name, argument nr => argument data
@ -98,6 +104,16 @@ public:
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;
private:

View File

@ -48,9 +48,11 @@ private:
TEST_CASE(testPrintfArgument);
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..
errout.str("");
@ -62,6 +64,9 @@ private:
settings.inconclusive = inconclusive;
settings.platform(platform);
if (lib)
settings.library = *lib;
// Tokenize..
Tokenizer tokenizer(&settings, this);
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: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)

View File

@ -2116,7 +2116,7 @@ private:
// nothing bad..
{
Library library;
Library::ArgumentChecks arg = {false, false};
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
@ -2130,7 +2130,7 @@ private:
// for 1st parameter null pointer is not ok..
{
Library library;
struct Library::ArgumentChecks arg = {false, false};
struct Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][1].notnull = true;
@ -2146,7 +2146,7 @@ private:
// for 2nd parameter uninit data is not ok..
{
Library library;
Library::ArgumentChecks arg = {false, false};
Library::ArgumentChecks arg;
library.argumentChecks["x"][1] = arg;
library.argumentChecks["x"][2] = arg;
library.argumentChecks["x"][2].notuninit = true;