better detection of variable sized structure in CheckBufferOverrun::checkStructVariable()

This commit is contained in:
Robert Reif 2011-09-09 08:37:24 -04:00
parent 27bfa2a346
commit b0eab2587d
2 changed files with 47 additions and 6 deletions

View File

@ -1571,18 +1571,41 @@ void CheckBufferOverrun::checkStructVariable()
// is variable public struct member? // is variable public struct member?
if (scope->type == Scope::eStruct && var->isPublic()) if (scope->type == Scope::eStruct && var->isPublic())
{ {
// last member of a struct with array size of 0 or 1 could be a variable struct // last member of a struct with array size of 0 or 1 could be a variable sized struct
if (var->dimensions().size() == 1 && var->dimension(0) < 2 && if (var->dimensions().size() == 1 && var->dimension(0) < 2 &&
var->index() == (scope->varlist.size() - 1)) var->index() == (scope->varlist.size() - 1))
{ {
// dynamically allocated so could be variable sized array // dynamically allocated so could be variable sized array
if (tok3->next()->str() == "*")
{
if ((Token::Match(tok3->tokAt(3), "; %var% = malloc ( %num% ) ;") ||
(Token::Match(tok3->tokAt(3), "; %var% = (") &&
Token::Match(tok3->tokAt(6)->link(), ") malloc ( %num% ) ;"))) &&
(tok3->strAt(4) == tok3->strAt(2)))
{
MathLib::bigint size;
// find size of allocation
if (tok3->strAt(3) == "(") // has cast
size = MathLib::toLongNumber(tok3->tokAt(6)->link()->strAt(3));
else
size = MathLib::toLongNumber(tok3->strAt(8));
if (size != 100) // magic number for size of class or struct
{
/** @todo false negatives: only true if dynamically allocated with size larger that struct */ /** @todo false negatives: only true if dynamically allocated with size larger that struct */
/** @todo false negatives: calculate real array size based on allocated size */ /** @todo false negatives: calculate real array size based on allocated size */
if (tok3->next()->str() == "*")
continue; continue;
} }
} }
// size unknown so assume it is a dynamically sized struct
else
continue;
}
}
}
// Goto end of statement. // Goto end of statement.
const Token *CheckTok = NULL; const Token *CheckTok = NULL;
while (tok3 && tok3 != func_scope->classEnd) while (tok3 && tok3 != func_scope->classEnd)

View File

@ -2435,7 +2435,16 @@ private:
check("struct Foo { char a[1]; };\n" check("struct Foo { char a[1]; };\n"
"void f()\n" "void f()\n"
"{\n" "{\n"
" struct Foo *x = malloc(10);\n" " struct Foo *x = malloc(sizeof(Foo));\n"
" sprintf(x.a, \"aa\");\n"
" free(x);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer access out-of-bounds\n", errout.str());
check("struct Foo { char a[1]; };\n"
"void f()\n"
"{\n"
" struct Foo *x = malloc(sizeof(Foo) + 10);\n"
" sprintf(x.a, \"aa\");\n" " sprintf(x.a, \"aa\");\n"
" free(x);\n" " free(x);\n"
"}\n"); "}\n");
@ -2526,7 +2535,16 @@ private:
check("struct Foo { char a[1]; };\n" check("struct Foo { char a[1]; };\n"
"void f()\n" "void f()\n"
"{\n" "{\n"
" struct Foo *x = malloc(10);\n" " struct Foo *x = malloc(sizeof(Foo));\n"
" snprintf(x.a, 2, \"aa\");\n"
" free(x);\n"
"}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) snprintf size is out of bounds\n", errout.str());
check("struct Foo { char a[1]; };\n"
"void f()\n"
"{\n"
" struct Foo *x = malloc(sizeof(Foo) + 10);\n"
" snprintf(x.a, 2, \"aa\");\n" " snprintf(x.a, 2, \"aa\");\n"
" free(x);\n" " free(x);\n"
"}\n"); "}\n");