Detect buffer overruns when ?: use as sprintf() argument.

This commit is contained in:
Slava Semushin 2009-09-27 00:40:58 +07:00
parent 19ed8e9311
commit acdbb20c99
2 changed files with 30 additions and 3 deletions

View File

@ -432,16 +432,32 @@ void CheckBufferOverrun::checkScope(const Token *tok, const char *varname[], con
len = 0;
const Token *end = tok->next()->link();
bool argumentAlreadyChecked = false;
int lastCheckedArgumentMaxSize = 0;
for (const Token *tok2 = tok->tokAt(6); tok2 && tok2 != end; tok2 = tok2->next())
{
if (tok2->str() == ",")
{
argumentAlreadyChecked = false;
lastCheckedArgumentMaxSize = 0;
}
else if (Token::Match(tok2, "%str%") && argumentAlreadyChecked == false)
else if (Token::Match(tok2, "%str%"))
{
len += (int)Token::getStrLength(tok2);
argumentAlreadyChecked = true;
int argumentSize = static_cast<int>(Token::getStrLength(tok2));
if (argumentAlreadyChecked == false)
{
lastCheckedArgumentMaxSize = argumentSize;
len += argumentSize;
argumentAlreadyChecked = true;
}
else if (argumentSize > lastCheckedArgumentMaxSize)
{
// when sprintf() argument is ternary
// operation we may have two and more
// strings as argument. In this case we
// use length of longest string.
len += (argumentSize - lastCheckedArgumentMaxSize);
lastCheckedArgumentMaxSize = argumentSize;
}
}
}
if (len >= (int)size)

View File

@ -101,6 +101,7 @@ private:
TEST_CASE(sprintf3);
TEST_CASE(sprintf4);
TEST_CASE(sprintf5);
TEST_CASE(sprintf6);
TEST_CASE(snprintf1);
TEST_CASE(snprintf2);
@ -660,6 +661,16 @@ private:
ASSERT_EQUALS("", errout.str());
}
void sprintf6()
{
check("void f(bool condition)\n"
"{\n"
" char buf[3];\n"
" sprintf(buf, \"%s\", condition ? \"11\" : \"222\");\n"
"}\n");
ASSERT_EQUALS("[test.cpp:4]: (possible error) Buffer overrun\n", errout.str());
}
void snprintf1()
{
check("void f()\n"