use correct checkScope function in CheckBufferOverrun for single dimension member arrays

This commit is contained in:
Robert Reif 2011-09-11 19:21:13 -04:00
parent 19928e26d1
commit 0d6592dd2e
3 changed files with 54 additions and 35 deletions

View File

@ -847,16 +847,16 @@ void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &ar
} }
void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::string> &varname, const ArrayInfo &info) void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::string> &varname, const ArrayInfo &arrayInfo)
{ {
// Only handling 1-dimensional arrays yet.. // Only handling 1-dimensional arrays yet..
/** @todo false negatives: handle multi-dimension arrays someday */ /** @todo false negatives: handle multi-dimension arrays someday */
if (info.num().size() > 1) if (arrayInfo.num().size() > 1)
return; return;
const MathLib::bigint size = info.num(0); const MathLib::bigint size = arrayInfo.num(0);
const MathLib::bigint total_size = info.element_size() * info.num(0); const MathLib::bigint total_size = arrayInfo.element_size() * arrayInfo.num(0);
unsigned int varid = info.varid(); unsigned int varid = arrayInfo.varid();
std::string varnames; std::string varnames;
for (unsigned int i = 0; i < varname.size(); ++i) for (unsigned int i = 0; i < varname.size(); ++i)
@ -880,7 +880,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
{ {
std::vector<MathLib::bigint> indexes; std::vector<MathLib::bigint> indexes;
indexes.push_back(index); indexes.push_back(index);
arrayIndexOutOfBoundsError(tok->tokAt(varc), info, indexes); arrayIndexOutOfBoundsError(tok->tokAt(varc), arrayInfo, indexes);
} }
} }
@ -926,7 +926,7 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
{ {
std::vector<MathLib::bigint> indexes; std::vector<MathLib::bigint> indexes;
indexes.push_back(index); indexes.push_back(index);
arrayIndexOutOfBoundsError(tok->tokAt(1 + varc), info, indexes); arrayIndexOutOfBoundsError(tok->tokAt(1 + varc), arrayInfo, indexes);
} }
tok = tok->tokAt(4 + varc); tok = tok->tokAt(4 + varc);
continue; continue;
@ -935,22 +935,22 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
// memset, memcmp, memcpy, strncpy, fgets.. // memset, memcmp, memcpy, strncpy, fgets..
if (varid == 0 && size > 0) if (varid == 0 && size > 0)
{ {
ArrayInfo arrayInfo(0U, ArrayInfo arrayInfo1(0U,
varnames, varnames,
(unsigned int)(total_size / size), (unsigned int)(total_size / size),
(unsigned int)size); (unsigned int)size);
if (Token::Match(tok, ("%var% ( " + varnames + " ,").c_str())) if (Token::Match(tok, ("%var% ( " + varnames + " ,").c_str()))
checkFunctionParameter(*tok, 1, arrayInfo); checkFunctionParameter(*tok, 1, arrayInfo1);
if (Token::Match(tok, ("%var% ( %var% , " + varnames + " ,").c_str())) if (Token::Match(tok, ("%var% ( %var% , " + varnames + " ,").c_str()))
checkFunctionParameter(*tok, 2, arrayInfo); checkFunctionParameter(*tok, 2, arrayInfo1);
} }
// Loop.. // Loop..
if (Token::simpleMatch(tok, "for (")) if (Token::simpleMatch(tok, "for ("))
{ {
const ArrayInfo arrayInfo(varid, varnames, (unsigned int)size, (unsigned int)total_size); const ArrayInfo arrayInfo1(varid, varnames, (unsigned int)size, (unsigned int)total_size);
bool bailout = false; bool bailout = false;
checkScopeForBody(tok, arrayInfo, bailout); checkScopeForBody(tok, arrayInfo1, bailout);
if (bailout) if (bailout)
break; break;
continue; continue;
@ -1026,8 +1026,8 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
if (varid == 0) if (varid == 0)
continue; continue;
const ArrayInfo arrayInfo(varid, varnames, size, total_size / size); const ArrayInfo arrayInfo1(varid, varnames, size, total_size / size);
checkFunctionCall(tok, arrayInfo); checkFunctionCall(tok, arrayInfo1);
} }
// undefined behaviour: result of pointer arithmetic is out of bounds // undefined behaviour: result of pointer arithmetic is out of bounds
@ -1328,7 +1328,12 @@ void CheckBufferOverrun::checkGlobalAndLocalVariable()
const Token *tok = var->nameToken(); const Token *tok = var->nameToken();
if (var->scope() && var->scope()->isClassOrStruct()) if (var->scope() && var->scope()->isClassOrStruct())
{ {
tok = var->scope()->classEnd->next(); // Only handle multi-dimension member arrays because single
// dimension arrays are handled in another check.
if (var->dimensions().size() > 1)
tok = var->scope()->classEnd->next();
else
continue;
} }
else else
{ {
@ -1617,9 +1622,19 @@ void CheckBufferOverrun::checkStructVariable()
if (!CheckTok) if (!CheckTok)
continue; continue;
// The version of checkScope below doesn't handle multi-dimension arrays
// yet so the other version of checkScope which does is used in another check.
// Ignore this variable because it is a mult-dimension array.
if (arrayInfo.num().size() > 1)
continue;
// Check variable usage.. // Check variable usage..
ArrayInfo temp = arrayInfo; ArrayInfo temp = arrayInfo;
temp.varid(0); temp.varid(0); // do variable lookup by variable and member names rather than varid
std::string varnames; // use class and member name for messages
for (unsigned int i = 0; i < varname.size(); ++i)
varnames += (i == 0 ? "" : ".") + varname[i];
temp.varname(varnames);
checkScope(CheckTok, varname, temp); checkScope(CheckTok, varname, temp);
} }
} }

View File

@ -188,6 +188,10 @@ public:
{ {
return _varname; return _varname;
} }
void varname(const std::string &name)
{
_varname = name;
}
}; };
/** Check for buffer overruns (based on ArrayInfo) */ /** Check for buffer overruns (based on ArrayInfo) */

View File

@ -500,7 +500,7 @@ private:
" struct ABC abc;\n" " struct ABC abc;\n"
" abc.str[10] = 0;\n" " abc.str[10] = 0;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'str[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Array 'abc.str[10]' index 10 out of bounds\n", errout.str());
check("struct ABC\n" check("struct ABC\n"
"{\n" "{\n"
@ -512,7 +512,7 @@ private:
" struct ABC abc;\n" " struct ABC abc;\n"
" return abc.str[10];\n" " return abc.str[10];\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'str[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Array 'abc.str[10]' index 10 out of bounds\n", errout.str());
// This is not out of bounds because it is a variable length array // This is not out of bounds because it is a variable length array
check("struct ABC\n" check("struct ABC\n"
@ -539,7 +539,7 @@ private:
" struct ABC* x = (struct ABC *)malloc(sizeof(struct ABC) + 10);\n" " struct ABC* x = (struct ABC *)malloc(sizeof(struct ABC) + 10);\n"
" x->str[1] = 0;" " x->str[1] = 0;"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:10]: (error) Array 'str[1]' index 1 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:10]: (error) Array 'x.str[1]' index 1 out of bounds\n", errout.str());
// This is not out of bounds because it is a variable length array // This is not out of bounds because it is a variable length array
// and the index is within the memory allocated. // and the index is within the memory allocated.
@ -581,7 +581,7 @@ private:
" struct ABC* x = (struct ABC *)malloc(sizeof(ABC) + 10);\n" " struct ABC* x = (struct ABC *)malloc(sizeof(ABC) + 10);\n"
" x->str[11] = 0;" " x->str[11] = 0;"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'str[11]' index 11 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Array 'x.str[11]' index 11 out of bounds\n", errout.str());
// This is out of bounds because it is outside the memory allocated // This is out of bounds because it is outside the memory allocated
/** @todo this doesn't work because of a bug in sizeof(struct) */ /** @todo this doesn't work because of a bug in sizeof(struct) */
@ -608,7 +608,7 @@ private:
" struct ABC* x = (struct ABC *)malloc(sizeof(ABC));\n" " struct ABC* x = (struct ABC *)malloc(sizeof(ABC));\n"
" x->str[1] = 0;" " x->str[1] = 0;"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'str[1]' index 1 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Array 'x.str[1]' index 1 out of bounds\n", errout.str());
// This is out of bounds because it is not a variable array // This is out of bounds because it is not a variable array
check("struct ABC\n" check("struct ABC\n"
@ -621,7 +621,7 @@ private:
" struct ABC x;\n" " struct ABC x;\n"
" x.str[1] = 0;" " x.str[1] = 0;"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'str[1]' index 1 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:9]: (error) Array 'x.str[1]' index 1 out of bounds\n", errout.str());
check("struct foo\n" check("struct foo\n"
"{\n" "{\n"
@ -649,7 +649,7 @@ private:
"{\n" "{\n"
" abc->str[10] = 0;\n" " abc->str[10] = 0;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:8]: (error) Array 'str[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:8]: (error) Array 'abc.str[10]' index 10 out of bounds\n", errout.str());
} }
@ -667,7 +667,7 @@ private:
" struct ABC abc;\n" " struct ABC abc;\n"
" abc.str[SIZE] = 0;\n" " abc.str[SIZE] = 0;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:11]: (error) Array 'str[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:11]: (error) Array 'abc.str[10]' index 10 out of bounds\n", errout.str());
} }
void array_index_9() void array_index_9()
@ -757,7 +757,7 @@ private:
" abc->str[10] = 0;\n" " abc->str[10] = 0;\n"
" }\n" " }\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:13]: (error) Array 'str[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:13]: (error) Array 'abc.str[10]' index 10 out of bounds\n", errout.str());
} }
@ -1231,12 +1231,12 @@ private:
" ptest->b[10][2] = 4;\n" " ptest->b[10][2] = 4;\n"
" ptest->b[0][19] = 4;\n" " ptest->b[0][19] = 4;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:9]: (error) Array 'a[10]' index 10 out of bounds\n" ASSERT_EQUALS("[test.cpp:10]: (error) Array 'b[10][5]' index b[10][2] out of bounds\n"
"[test.cpp:14]: (error) Array 'a[10]' index 10 out of bounds\n"
"[test.cpp:10]: (error) Array 'b[10][5]' index b[10][2] out of bounds\n"
"[test.cpp:11]: (error) Array 'b[10][5]' index b[0][19] out of bounds\n" "[test.cpp:11]: (error) Array 'b[10][5]' index b[0][19] out of bounds\n"
"[test.cpp:15]: (error) Array 'b[10][5]' index b[10][2] out of bounds\n" "[test.cpp:15]: (error) Array 'b[10][5]' index b[10][2] out of bounds\n"
"[test.cpp:16]: (error) Array 'b[10][5]' index b[0][19] out of bounds\n", errout.str()); "[test.cpp:16]: (error) Array 'b[10][5]' index b[0][19] out of bounds\n"
"[test.cpp:9]: (error) Array 'test.a[10]' index 10 out of bounds\n"
"[test.cpp:14]: (error) Array 'ptest.a[10]' index 10 out of bounds\n", errout.str());
check("struct TEST\n" check("struct TEST\n"
"{\n" "{\n"
@ -1264,14 +1264,14 @@ private:
" struct Struct { unsigned m_Var[1]; } s;\n" " struct Struct { unsigned m_Var[1]; } s;\n"
" s.m_Var[1] = 1;\n" " s.m_Var[1] = 1;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:3]: (error) Array 'm_Var[1]' index 1 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:3]: (error) Array 's.m_Var[1]' index 1 out of bounds\n", errout.str());
check("struct Struct { unsigned m_Var[1]; };\n" check("struct Struct { unsigned m_Var[1]; };\n"
"void f() {\n" "void f() {\n"
" struct Struct s;\n" " struct Struct s;\n"
" s.m_Var[1] = 1;\n" " s.m_Var[1] = 1;\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'm_Var[1]' index 1 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:4]: (error) Array 's.m_Var[1]' index 1 out of bounds\n", errout.str());
check("struct Struct { unsigned m_Var[1]; };\n" check("struct Struct { unsigned m_Var[1]; };\n"
"void f() {\n" "void f() {\n"
@ -2794,7 +2794,7 @@ private:
" Fred *f = new Fred;\n" " Fred *f = new Fred;\n"
" return f->c[10];\n" " return f->c[10];\n"
"}\n"); "}\n");
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'c[10]' index 10 out of bounds\n", errout.str()); ASSERT_EQUALS("[test.cpp:5]: (error) Array 'f.c[10]' index 10 out of bounds\n", errout.str());
check("void foo()\n" check("void foo()\n"
"{\n" "{\n"