use correct checkScope function in CheckBufferOverrun for single dimension member arrays
This commit is contained in:
parent
19928e26d1
commit
0d6592dd2e
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) */
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue