CheckBufferOverrun: Removed old for-loop handling. This is handled through ValueFlow from now on.
This commit is contained in:
parent
b6a40fceb7
commit
6c8558c112
|
@ -262,315 +262,7 @@ static bool bailoutIfSwitch(const Token *tok, const unsigned int varid)
|
|||
// No bailout stuff found => return false
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse for loop initialization statement. Look for a counter variable
|
||||
* \param tok [in] first token inside the parentheses
|
||||
* \param varid [out] varid of counter variable
|
||||
* \param varname [out] name of counter variable
|
||||
* \param init_value [out] init value of counter variable
|
||||
* \return success => pointer to the for loop condition. fail => 0. If 0 is returned and varname has been set then there is
|
||||
* a missing varid for the counter variable
|
||||
*/
|
||||
static const Token *for_init(const Token *tok, unsigned int &varid, std::string &varname, std::string &init_value)
|
||||
{
|
||||
if (Token::Match(tok, "%var% = %any% ;")) {
|
||||
if (tok->tokAt(2)->isNumber()) {
|
||||
init_value = tok->strAt(2);
|
||||
}
|
||||
|
||||
varid = tok->varId();
|
||||
varname = tok->str();
|
||||
if (varid == 0)
|
||||
return 0; // failed
|
||||
|
||||
tok = tok->tokAt(4);
|
||||
} else if (Token::Match(tok, "%type% %var% = %any% ;")) {
|
||||
if (tok->tokAt(3)->isNumber()) {
|
||||
init_value = tok->strAt(3);
|
||||
}
|
||||
|
||||
varid = tok->next()->varId();
|
||||
varname = tok->next()->str();
|
||||
tok = tok->tokAt(5);
|
||||
} else if (Token::Match(tok, "%type% %type% %var% = %any% ;")) {
|
||||
if (tok->tokAt(4)->isNumber()) {
|
||||
init_value = tok->strAt(4);
|
||||
}
|
||||
|
||||
varid = tok->tokAt(2)->varId();
|
||||
varname = tok->strAt(2);
|
||||
tok = tok->tokAt(6);
|
||||
} else
|
||||
return 0;
|
||||
|
||||
if (!init_value.empty() && (Token::Match(tok, "-- %varid%", varid) || Token::Match(tok, "%varid% --", varid))) {
|
||||
init_value = MathLib::subtract(init_value, "1");
|
||||
}
|
||||
|
||||
return tok;
|
||||
}
|
||||
|
||||
|
||||
/** Parse for condition */
|
||||
static bool for_condition(const Token *tok2, unsigned int varid, std::string &min_value, std::string &max_value, bool &maxMinFlipped)
|
||||
{
|
||||
if (Token::Match(tok2, "%varid% < %num% ;|&&|%oror%", varid) ||
|
||||
Token::Match(tok2, "%varid% != %num% ; ++ %varid%", varid) ||
|
||||
Token::Match(tok2, "%varid% != %num% ; %varid% ++", varid)) {
|
||||
maxMinFlipped = false;
|
||||
const MathLib::bigint value = MathLib::toLongNumber(tok2->strAt(2));
|
||||
max_value = MathLib::toString(value - 1);
|
||||
} else if (Token::Match(tok2, "%varid% <= %num% ;|&&|%oror%", varid)) {
|
||||
maxMinFlipped = false;
|
||||
max_value = tok2->strAt(2);
|
||||
} else if (Token::Match(tok2, "%num% < %varid% ;|&&|%oror%", varid) ||
|
||||
Token::Match(tok2, "%num% != %varid% ; ++ %varid%", varid) ||
|
||||
Token::Match(tok2, "%num% != %varid% ; %varid% ++", varid)) {
|
||||
maxMinFlipped = true;
|
||||
const MathLib::bigint value = MathLib::toLongNumber(tok2->str());
|
||||
max_value = min_value;
|
||||
min_value = MathLib::toString(value + 1);
|
||||
} else if (Token::Match(tok2, "%num% <= %varid% ;|&&|%oror%", varid)) {
|
||||
maxMinFlipped = true;
|
||||
max_value = min_value;
|
||||
min_value = tok2->str();
|
||||
} else if (Token::Match(tok2, "%varid% -- ; )", varid) ||
|
||||
Token::Match(tok2, "-- %varid% ; )", varid)) {
|
||||
maxMinFlipped = true;
|
||||
max_value = min_value;
|
||||
min_value = (tok2->str() == "--") ? "1" : "0";
|
||||
} else {
|
||||
// parse condition
|
||||
while (tok2 && tok2->str() != ";") {
|
||||
if (tok2->str() == "(")
|
||||
tok2 = tok2->link();
|
||||
else if (tok2->str() == ")") // unexpected ")" => break
|
||||
break;
|
||||
if (tok2->str() == "&&" || tok2->str() == "||") {
|
||||
if (for_condition(tok2->next(), varid, min_value, max_value, maxMinFlipped))
|
||||
return true;
|
||||
}
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* calculate maximum value of loop variable
|
||||
* @param stepvalue token that contains the step value
|
||||
* @param min_value the minimum value of loop variable
|
||||
* @param max_value maximum value of the loop variable
|
||||
*/
|
||||
static bool for_maxvalue(const Token * const stepvalue, const std::string &min_value, std::string &max_value)
|
||||
{
|
||||
if (!MathLib::isInt(stepvalue->str()))
|
||||
return false;
|
||||
|
||||
// We have for example code: "for(i=2;i<22;i+=6)
|
||||
// We can calculate that max value for i is 20, not 21
|
||||
// 21-2 = 19
|
||||
// 19/6 = 3
|
||||
// 6*3+2 = 20
|
||||
const MathLib::bigint num = MathLib::toLongNumber(stepvalue->str());
|
||||
MathLib::bigint max = MathLib::toLongNumber(max_value);
|
||||
const MathLib::bigint min = MathLib::toLongNumber(min_value);
|
||||
max = ((max - min) / num) * num + min;
|
||||
max_value = MathLib::toString(max);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the third sub-statement in for head
|
||||
* \param tok first token
|
||||
* \param varid variable id of counter
|
||||
* \param min_value min value of counter
|
||||
* \param max_value max value of counter
|
||||
* \param maxMinFlipped counting from max to min
|
||||
*/
|
||||
static bool for3(const Token * const tok,
|
||||
unsigned int varid,
|
||||
std::string &min_value,
|
||||
std::string &max_value,
|
||||
const bool maxMinFlipped)
|
||||
{
|
||||
assert(tok != nullptr);
|
||||
if (Token::Match(tok, "%varid% = %num% + %varid% )", varid)) {
|
||||
if (!for_maxvalue(tok->tokAt(2), min_value, max_value))
|
||||
return false;
|
||||
} else if (Token::Match(tok, "%varid% = %varid% + %num% )", varid)) {
|
||||
if (!for_maxvalue(tok->tokAt(4), min_value, max_value))
|
||||
return false;
|
||||
} else if (Token::Match(tok, "%varid% = %num% - %varid% )", varid)) {
|
||||
if (!for_maxvalue(tok->tokAt(2), min_value, max_value))
|
||||
return false;
|
||||
} else if (Token::Match(tok, "%varid% = %varid% - %num% )", varid)) {
|
||||
if (!for_maxvalue(tok->tokAt(4), min_value, max_value))
|
||||
return false;
|
||||
} else if (Token::Match(tok, "--| %varid% --| )", varid)) {
|
||||
if (!maxMinFlipped && MathLib::toLongNumber(min_value) < MathLib::toLongNumber(max_value)) {
|
||||
// Code relies on the fact that integer will overflow:
|
||||
// for (unsigned int i = 3; i < 5; --i)
|
||||
|
||||
// Set min value in this case to zero.
|
||||
max_value = min_value;
|
||||
min_value = "0";
|
||||
}
|
||||
} else if (! Token::Match(tok, "++| %varid% ++| )", varid)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check is the counter variable increased elsewhere inside the loop or used
|
||||
* for anything else except reading
|
||||
* \param tok1 first token of for-body
|
||||
* \param varid counter variable id
|
||||
* \return bailout needed => true
|
||||
*/
|
||||
static bool for_bailout(const Token * const tok1, unsigned int varid)
|
||||
{
|
||||
for (const Token *loopTok = tok1; loopTok && loopTok != tok1->link(); loopTok = loopTok->next()) {
|
||||
if (loopTok->varId() == varid) {
|
||||
// Counter variable used inside loop
|
||||
if (Token::Match(loopTok->next(), "++|--|=") ||
|
||||
(loopTok->previous()->type() == Token::eIncDecOp)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void CheckBufferOverrun::parse_for_body(const Token *tok, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value)
|
||||
{
|
||||
unsigned int arrayInfoDeclarationId = arrayInfo.declarationId();
|
||||
const std::string pattern = (arrayInfoDeclarationId ? std::string("%varid%") : arrayInfo.varname()) + " [ " + strindex + " ]";
|
||||
|
||||
for (const Token* tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
|
||||
// TestBufferOverrun::array_index_for_question
|
||||
if (tok2->str() == "?") {
|
||||
// does condition check counter variable?
|
||||
bool usesCounter = false;
|
||||
const Token *tok3 = tok2->previous();
|
||||
while (Token::Match(tok3, "%comp%|%num%|%var%|)")) {
|
||||
if (tok3->str() == strindex) {
|
||||
usesCounter = true;
|
||||
break;
|
||||
}
|
||||
tok3 = tok3->previous();
|
||||
}
|
||||
|
||||
// If strindex is used in the condition then skip the
|
||||
// conditional expressions
|
||||
if (usesCounter) {
|
||||
while (tok2 && !Token::Match(tok2, "[)],;]")) {
|
||||
if (tok2->str() == "(" || tok2->str() == "[")
|
||||
tok2 = tok2->link();
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
if (!tok2)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (Token::simpleMatch(tok2, "for (") && Token::simpleMatch(tok2->next()->link(), ") {")) {
|
||||
const Token *endpar = tok2->next()->link();
|
||||
const Token *startbody = endpar->next();
|
||||
const Token *endbody = startbody->link();
|
||||
tok2 = endbody;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Token::Match(tok2, "if|switch")) {
|
||||
if (bailoutIfSwitch(tok2, arrayInfoDeclarationId))
|
||||
break;
|
||||
}
|
||||
|
||||
if (condition_out_of_bounds && Token::Match(tok2, pattern.c_str(), arrayInfoDeclarationId)) {
|
||||
bufferOverrunError(tok2, arrayInfo.varname());
|
||||
break;
|
||||
}
|
||||
|
||||
else if (arrayInfoDeclarationId && tok2->varId() && counter_varid > 0 && !min_counter_value.empty() && !max_counter_value.empty()) {
|
||||
// Is the loop variable used to calculate the array index?
|
||||
// In this scope it is determined if such calculated
|
||||
// array indexes are out of bounds.
|
||||
// Only the minimum and maximum results of the calculation is
|
||||
// determined
|
||||
|
||||
// Minimum calculated array index
|
||||
int min_index = 0;
|
||||
|
||||
// Maximum calculated array index
|
||||
int max_index = 0;
|
||||
|
||||
if (Token::Match(tok2, "%varid% [ %var% +|-|*|/ %num% ]", arrayInfoDeclarationId) &&
|
||||
tok2->tokAt(2)->varId() == counter_varid) {
|
||||
// operator: +-*/
|
||||
const char action = tok2->strAt(3)[0];
|
||||
|
||||
// second operator
|
||||
const std::string &second(tok2->strAt(4));
|
||||
|
||||
//printf("min_index: %s %c %s\n", min_counter_value.c_str(), action, second.c_str());
|
||||
//printf("max_index: %s %c %s\n", max_counter_value.c_str(), action, second.c_str());
|
||||
min_index = std::atoi(MathLib::calculate(min_counter_value, second, action).c_str());
|
||||
max_index = std::atoi(MathLib::calculate(max_counter_value, second, action).c_str());
|
||||
} else if (Token::Match(tok2, "%varid% [ %num% +|-|*|/ %var% ]", arrayInfoDeclarationId) &&
|
||||
tok2->tokAt(4)->varId() == counter_varid) {
|
||||
// operator: +-*/
|
||||
const char action = tok2->strAt(3)[0];
|
||||
|
||||
// first operand
|
||||
const std::string &first(tok2->strAt(2));
|
||||
|
||||
//printf("min_index: %s %c %s\n", first.c_str(), action, min_counter_value.c_str());
|
||||
//printf("max_index: %s %c %s\n", first.c_str(), action, max_counter_value.c_str());
|
||||
|
||||
min_index = std::atoi(MathLib::calculate(first, min_counter_value, action).c_str());
|
||||
max_index = std::atoi(MathLib::calculate(first, max_counter_value, action).c_str());
|
||||
}
|
||||
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
//printf("min_index = %d, max_index = %d, size = %d\n", min_index, max_index, size);
|
||||
if (min_index < 0 || max_index < 0) {
|
||||
std::vector<MathLib::bigint> indexes;
|
||||
indexes.push_back(std::min(min_index, max_index));
|
||||
arrayIndexOutOfBoundsError(tok2, arrayInfo, indexes);
|
||||
}
|
||||
|
||||
// skip 0 length arrays
|
||||
if (arrayInfo.num(0) == 0)
|
||||
;
|
||||
|
||||
// taking address.
|
||||
else if (tok2->previous()->str() == "&" && max_index == arrayInfo.num(0))
|
||||
;
|
||||
|
||||
else if (arrayInfo.num(0) && (min_index >= arrayInfo.num(0) || max_index >= arrayInfo.num(0))) {
|
||||
std::vector<MathLib::bigint> indexes;
|
||||
indexes.push_back(std::max(min_index, max_index));
|
||||
arrayIndexOutOfBoundsError(tok2, arrayInfo, indexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void CheckBufferOverrun::checkFunctionParameter(const Token &tok, unsigned int par, const ArrayInfo &arrayInfo, const std::list<const Token *>& callstack)
|
||||
{
|
||||
|
@ -790,132 +482,6 @@ void CheckBufferOverrun::checkFunctionCall(const Token *tok, const ArrayInfo &ar
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &arrayInfo, bool &bailout)
|
||||
{
|
||||
bailout = false;
|
||||
|
||||
// Check if there is a break in the body..
|
||||
{
|
||||
const Token *bodyStart = tok->next()->link()->next();
|
||||
const Token *bodyEnd = bodyStart->link();
|
||||
if (Token::findsimplematch(bodyStart, "break ;", bodyEnd))
|
||||
return;
|
||||
}
|
||||
|
||||
const Token *tok2 = tok->tokAt(2);
|
||||
const MathLib::bigint size = arrayInfo.num(0);
|
||||
|
||||
std::string counter_name;
|
||||
unsigned int counter_varid = 0;
|
||||
std::string counter_init_value;
|
||||
|
||||
tok2 = for_init(tok2, counter_varid, counter_name, counter_init_value);
|
||||
if (tok2 == 0 && !counter_name.empty())
|
||||
_tokenizer->getSymbolDatabase()->debugMessage(tok, "for loop variable \'" + counter_name + "\' has varid 0.");
|
||||
if (tok2 == 0 || counter_varid == 0)
|
||||
return;
|
||||
|
||||
bool maxMinFlipped = false;
|
||||
std::string min_counter_value = counter_init_value;
|
||||
std::string max_counter_value;
|
||||
if (!for_condition(tok2, counter_varid, min_counter_value, max_counter_value, maxMinFlipped)) {
|
||||
// Can't understand the condition. Check that the start value
|
||||
// is used correctly
|
||||
const Token * const startForScope = tok->next()->link()->next();
|
||||
if (!for_bailout(startForScope, counter_varid)) {
|
||||
// Get index variable and stopsize.
|
||||
bool condition_out_of_bounds = bool(size > 0);
|
||||
if (MathLib::toLongNumber(counter_init_value) < size)
|
||||
condition_out_of_bounds = false;
|
||||
|
||||
parse_for_body(startForScope, arrayInfo, counter_name, condition_out_of_bounds, counter_varid, counter_init_value, counter_init_value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Get index variable and stopsize.
|
||||
bool condition_out_of_bounds = bool(size > 0);
|
||||
if (MathLib::toLongNumber(max_counter_value) < size)
|
||||
condition_out_of_bounds = false;
|
||||
|
||||
// Goto the end of the condition
|
||||
while (tok2 && tok2->str() != ";") {
|
||||
if (tok2->str() == "(")
|
||||
tok2 = tok2->link();
|
||||
else if (tok2->str() == ")") // unexpected ")" => break
|
||||
break;
|
||||
tok2 = tok2->next();
|
||||
}
|
||||
if (!tok2 || tok2->str() != ";")
|
||||
return;
|
||||
const bool hasFor3 = tok2->next()->str() != ")";
|
||||
if (hasFor3 && !for3(tok2->next(), counter_varid, min_counter_value, max_counter_value, maxMinFlipped))
|
||||
return;
|
||||
|
||||
if (Token::Match(tok2->next(), "%var% =") && MathLib::toLongNumber(max_counter_value) < size)
|
||||
condition_out_of_bounds = false;
|
||||
|
||||
// Goto the end parentheses of the for-statement: "for (x; y; z)" ..
|
||||
tok2 = tok->next()->link();
|
||||
if (!tok2 || !tok2->tokAt(5)) {
|
||||
bailout = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check is the counter variable increased elsewhere inside the loop or used
|
||||
// for anything else except reading
|
||||
if (for_bailout(tok2->next(), counter_varid)) {
|
||||
bailout = true;
|
||||
return;
|
||||
}
|
||||
|
||||
parse_for_body(tok2->next(), arrayInfo, counter_name, condition_out_of_bounds, counter_varid, min_counter_value, max_counter_value);
|
||||
}
|
||||
|
||||
void CheckBufferOverrun::arrayIndexInForLoop(const Token *tok, const ArrayInfo &arrayInfo)
|
||||
{
|
||||
const MathLib::bigint size = arrayInfo.num(0);
|
||||
const Token *tok3 = tok->tokAt(2);
|
||||
std::string counter_name;
|
||||
unsigned int counter_varid = 0;
|
||||
std::string counter_init_value;
|
||||
|
||||
tok3 = for_init(tok3, counter_varid, counter_name, counter_init_value);
|
||||
if (tok3 == 0 && !counter_name.empty())
|
||||
_tokenizer->getSymbolDatabase()->debugMessage(tok, "for loop variable \'" + counter_name + "\' has varid 0.");
|
||||
if (tok3 == 0 || counter_varid == 0)
|
||||
return;
|
||||
|
||||
bool maxMinFlipped = false;
|
||||
std::string min_counter_value = counter_init_value;
|
||||
std::string max_counter_value;
|
||||
|
||||
if (!for_condition(tok3, counter_varid, min_counter_value, max_counter_value, maxMinFlipped))
|
||||
return;
|
||||
|
||||
const MathLib::bigint max_value = MathLib::toLongNumber(max_counter_value);
|
||||
|
||||
// Skip condition
|
||||
while (tok3 && tok3->str() != ";")
|
||||
tok3 = tok3->next();
|
||||
|
||||
if (max_value > size && Token::simpleMatch(tok3, "; ) {")) {
|
||||
const Token * const endToken = tok3->linkAt(2);
|
||||
const Token *useToken = nullptr;
|
||||
bool incrementInLoop = false;
|
||||
for (const Token *loopTok = tok3->tokAt(3); loopTok != endToken; loopTok = loopTok->next()) {
|
||||
if (Token::Match(loopTok, "%varid% [ %var% ++| ]", arrayInfo.declarationId()) && loopTok->tokAt(2)->varId() == counter_varid)
|
||||
useToken = loopTok;
|
||||
if (Token::Match(loopTok, "%varid% ++", counter_varid))
|
||||
incrementInLoop = true;
|
||||
}
|
||||
|
||||
if ((useToken != nullptr) && incrementInLoop)
|
||||
bufferOverrunError(useToken, arrayInfo.varname());
|
||||
}
|
||||
}
|
||||
|
||||
void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::string> &varname, const ArrayInfo &arrayInfo)
|
||||
{
|
||||
const MathLib::bigint size = arrayInfo.num(0);
|
||||
|
@ -1054,18 +620,6 @@ void CheckBufferOverrun::checkScope(const Token *tok, const std::vector<std::str
|
|||
checkFunctionParameter(*tok, 2, arrayInfo, callstack);
|
||||
}
|
||||
|
||||
// Loop..
|
||||
if (Token::simpleMatch(tok, "for (")) {
|
||||
/*
|
||||
const ArrayInfo arrayInfo1(declarationId, varnames, (unsigned int)size, (unsigned int)total_size);
|
||||
bool bailout = false;
|
||||
checkScopeForBody(tok, arrayInfo1, bailout);
|
||||
if (bailout)
|
||||
break;
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
// Writing data into array..
|
||||
if ((declarationId > 0 && Token::Match(tok, "strcpy|strcat ( %varid% , %str% )", declarationId)) ||
|
||||
(declarationId == 0 && Token::Match(tok, ("strcpy|strcat ( " + varnames + " , %str% )").c_str()))) {
|
||||
|
@ -1276,16 +830,6 @@ void CheckBufferOverrun::checkScope(const Token *tok, const ArrayInfo &arrayInfo
|
|||
continue;
|
||||
|
||||
else if (Token::Match(tok, "%var% (")) {
|
||||
// Loop..
|
||||
if (Token::simpleMatch(tok, "for (")) {
|
||||
bool bailout = false;
|
||||
arrayIndexInForLoop(tok, arrayInfo);
|
||||
checkScopeForBody(tok, arrayInfo, bailout);
|
||||
if (bailout)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check function call..
|
||||
checkFunctionCall(tok, arrayInfo, std::list<const Token*>());
|
||||
|
||||
|
|
|
@ -180,12 +180,6 @@ public:
|
|||
/** Check for buffer overruns */
|
||||
void checkScope(const Token *tok, const std::vector<std::string> &varname, const ArrayInfo &arrayInfo);
|
||||
|
||||
/** Check scope helper function - parse for body */
|
||||
void checkScopeForBody(const Token *tok, const ArrayInfo &arrayInfo, bool &bailout);
|
||||
|
||||
/** Helper function used when parsing for-loops */
|
||||
void parse_for_body(const Token *tok2, const ArrayInfo &arrayInfo, const std::string &strindex, bool condition_out_of_bounds, unsigned int counter_varid, const std::string &min_counter_value, const std::string &max_counter_value);
|
||||
|
||||
/** Check readlink or readlinkat() buffer usage */
|
||||
void checkReadlinkBufferUsage(const Token *ftok, const Token *scope_begin, const unsigned int varid, const MathLib::bigint total_size);
|
||||
|
||||
|
@ -208,7 +202,6 @@ public:
|
|||
|
||||
void arrayIndexOutOfBoundsError(const Token *tok, const ArrayInfo &arrayInfo, const std::vector<MathLib::bigint> &index);
|
||||
void arrayIndexOutOfBoundsError(const Token *tok, const ArrayInfo &arrayInfo, const std::vector<ValueFlow::Value> &index);
|
||||
void arrayIndexInForLoop(const Token *tok, const ArrayInfo &arrayInfo);
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
@ -1,2 +1 @@
|
|||
[samples\bufferAccessOutOfBounds\bad.c:6]: (error) Buffer is accessed out of bounds: a
|
||||
[samples\bufferAccessOutOfBounds\bad.c:6]: (error) Array 'a[2]' accessed at index 2, which is out of bounds.
|
||||
|
|
|
@ -166,8 +166,7 @@ private:
|
|||
TEST_CASE(buffer_overrun_21);
|
||||
TEST_CASE(buffer_overrun_22); // #3124
|
||||
TEST_CASE(buffer_overrun_23); // #3153
|
||||
TEST_CASE(buffer_overrun_24); // #4106
|
||||
TEST_CASE(buffer_overrun_25); // #4096
|
||||
TEST_CASE(buffer_overrun_24); // index variable is changed in for-loop
|
||||
TEST_CASE(buffer_overrun_26); // #4432 (segmentation fault)
|
||||
TEST_CASE(buffer_overrun_27); // #4444 (segmentation fault)
|
||||
TEST_CASE(buffer_overrun_28); // Out of bound char array access
|
||||
|
@ -402,8 +401,7 @@ private:
|
|||
" for (i = 0; i < 100; i++)\n"
|
||||
" sum += val[i];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Buffer is accessed out of bounds: val\n"
|
||||
"[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -414,8 +412,7 @@ private:
|
|||
" for (i = 1; i < 100; i++)\n"
|
||||
" sum += val[i];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Buffer is accessed out of bounds: val\n"
|
||||
"[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
|
||||
|
@ -427,8 +424,7 @@ private:
|
|||
" for (i = a; i < 100; i++)\n"
|
||||
" sum += val[i];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Buffer is accessed out of bounds: val\n"
|
||||
"[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Array 'val[50]' accessed at index 99, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -460,8 +456,7 @@ private:
|
|||
" a[i] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:3]: (error) Array 'a[10]' accessed at index 49, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Array 'a[10]' accessed at index 49, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -832,8 +827,7 @@ private:
|
|||
" for (int i = 0; i < 4; i+=2)\n"
|
||||
" a[i] = 0;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:4]: (error) Array 'a[2]' accessed at index 2, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[2]' accessed at index 2, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f() {\n" // #4398
|
||||
" int a[2];\n"
|
||||
|
@ -1049,8 +1043,7 @@ private:
|
|||
" for (int i = 3; 0 <= i; i--)\n"
|
||||
" a[i] = i;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:5]: (error) Array 'a[3]' accessed at index 3, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'a[3]' accessed at index 3, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
|
@ -1068,8 +1061,7 @@ private:
|
|||
" for (int i = 0; i < 10; i++)\n"
|
||||
" a[i-1] = a[i];\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'a[10]' accessed at index -1, which is out of bounds.\n"
|
||||
"[test.cpp:5]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
void array_index_28() {
|
||||
|
@ -1533,7 +1525,7 @@ private:
|
|||
" printf(\"files(%i): %s\n\", 3-i, buffer[3-i]);\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'buffer[3]' accessed at index 3, which is out of bounds.\n", errout.str());
|
||||
TODO_ASSERT_EQUALS("[test.cpp:4]: (error) Array 'buffer[3]' accessed at index 3, which is out of bounds.\n", "", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" int buffer[9];\n"
|
||||
|
@ -1542,8 +1534,7 @@ private:
|
|||
" buffer[i] = i;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: buffer\n"
|
||||
"[test.cpp:5]: (error) Array 'buffer[9]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'buffer[9]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
|
||||
// Correct access limits -> i from 9 to 0
|
||||
check("void f() {\n"
|
||||
|
@ -1780,8 +1771,7 @@ private:
|
|||
" data[i] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: data\n"
|
||||
"[test.cpp:5]: (error) Array 'data[8]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'data[8]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f()\n"
|
||||
"{\n"
|
||||
|
@ -1827,8 +1817,7 @@ private:
|
|||
" data[x] = 0;\n"
|
||||
" }"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: data\n"
|
||||
"[test.cpp:5]: (error) Array 'data[2]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'data[2]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char data[2];\n"
|
||||
|
@ -1837,8 +1826,7 @@ private:
|
|||
" data[x] = 0;\n"
|
||||
" }"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: data\n"
|
||||
"[test.cpp:5]: (error) Array 'data[2]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'data[2]' accessed at index 9, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char data[2];\n"
|
||||
|
@ -1847,8 +1835,7 @@ private:
|
|||
" data[x] = 0;\n"
|
||||
" }"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: data\n"
|
||||
"[test.cpp:5]: (error) Array 'data[2]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'data[2]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char data[2];\n"
|
||||
|
@ -1857,8 +1844,7 @@ private:
|
|||
" data[x] = 0;\n"
|
||||
" }"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: data\n"
|
||||
"[test.cpp:5]: (error) Array 'data[2]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'data[2]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
void array_index_for_continue() {
|
||||
|
@ -1896,8 +1882,7 @@ private:
|
|||
" a[i] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:6]: (error) Array 'a[10]' accessed at index 19, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Array 'a[10]' accessed at index 19, which is out of bounds.\n", errout.str());
|
||||
|
||||
// Ticket #2385 - No false positive
|
||||
check("void f() {\n"
|
||||
|
@ -1918,8 +1903,7 @@ private:
|
|||
" a[i] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:4]: (error) Array 'a[10]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[10]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
void array_index_for_neq() {
|
||||
|
@ -1930,8 +1914,7 @@ private:
|
|||
" a[i] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:4]: (error) Array 'a[5]' accessed at index 9, which is out of bounds.\n",
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[5]' accessed at index 9, which is out of bounds.\n",
|
||||
errout.str());
|
||||
}
|
||||
|
||||
|
@ -1951,8 +1934,7 @@ private:
|
|||
" some_condition ? 0 : a[i-1];\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array 'a[10]' accessed at index -1, which is out of bounds.\n"
|
||||
"[test.cpp:4]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:4]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" int a[10];\n"
|
||||
|
@ -1961,8 +1943,7 @@ private:
|
|||
" a[i-1] = 0;\n"
|
||||
" }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'a[10]' accessed at index -1, which is out of bounds.\n"
|
||||
"[test.cpp:5]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array index -1 is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
void array_index_for_varid0() { // #4228: No varid for counter variable
|
||||
|
@ -2284,8 +2265,7 @@ private:
|
|||
" for (i = 0; i <= 10; ++i)\n"
|
||||
" a[i] = 0;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:7]: (error) Buffer is accessed out of bounds: a\n"
|
||||
"[test.cpp:7]: (error) Array 'a[10]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:7]: (error) Array 'a[10]' accessed at index 10, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
|
||||
|
@ -2296,8 +2276,7 @@ private:
|
|||
" for (int i = 0; i < 8; ++i)\n"
|
||||
" p[i] = 0;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: p\n"
|
||||
"[test.cpp:5]: (error) Array 'p[2]' accessed at index 7, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Array 'p[2]' accessed at index 7, which is out of bounds.\n", errout.str());
|
||||
|
||||
// No false positive
|
||||
check("void foo(int x, int y)\n"
|
||||
|
@ -2627,8 +2606,7 @@ private:
|
|||
" for (size_t i = 0; i <= 4; i++)\n"
|
||||
" dst[i] = src[i];\n"
|
||||
"} } }\n");
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Buffer is accessed out of bounds: dst\n"
|
||||
"[test.cpp:6]: (error) Array 'dst[4]' accessed at index 4, which is out of bounds.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:6]: (error) Array 'dst[4]' accessed at index 4, which is out of bounds.\n", errout.str());
|
||||
}
|
||||
|
||||
void buffer_overrun_22() { // ticket #3124
|
||||
|
@ -2672,7 +2650,8 @@ private:
|
|||
}
|
||||
|
||||
|
||||
void buffer_overrun_24() { // ticket #4106
|
||||
void buffer_overrun_24() { // index variable is changed in for-loop
|
||||
// ticket #4106
|
||||
check("void main() {\n"
|
||||
" int array[] = {1,2};\n"
|
||||
" int x = 0;\n"
|
||||
|
@ -2680,17 +2659,9 @@ private:
|
|||
" x += array[i];\n"
|
||||
" i++; }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: array\n", errout.str());
|
||||
TODO_ASSERT_EQUALS("error", "", errout.str());
|
||||
|
||||
check("void main() {\n"
|
||||
" int array[] = {1,2};\n"
|
||||
" for( int i = 0; i<6; ) {\n"
|
||||
" i++; }\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
}
|
||||
|
||||
void buffer_overrun_25() { // ticket #4096
|
||||
// ticket #4096
|
||||
check("void main() {\n"
|
||||
" int array[] = {1,2};\n"
|
||||
" int x = 0;\n"
|
||||
|
@ -2698,8 +2669,7 @@ private:
|
|||
" x += array[i++];\n"
|
||||
" }\n"
|
||||
"}");
|
||||
|
||||
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer is accessed out of bounds: array\n", errout.str());
|
||||
TODO_ASSERT_EQUALS("error", "", errout.str());
|
||||
}
|
||||
|
||||
void buffer_overrun_26() { // ticket #4432 (segmentation fault)
|
||||
|
|
Loading…
Reference in New Issue