Fixed #3907 (improve check: detect buffer overrun when using && or || in for loop)
This commit is contained in:
parent
ac524c56ad
commit
4e98cb3ed9
|
@ -283,29 +283,41 @@ static const Token *for_init(const Token *tok, unsigned int &varid, std::string
|
||||||
|
|
||||||
|
|
||||||
/** Parse for condition */
|
/** Parse for condition */
|
||||||
static bool for_condition(const Token * const tok2, unsigned int varid, std::string &min_value, std::string &max_value, bool &maxMinFlipped)
|
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% ;", varid) ||
|
if (Token::Match(tok2, "%varid% < %num% ;|&&|%oror%", varid) ||
|
||||||
Token::Match(tok2, "%varid% != %num% ; ++ %varid%", varid) ||
|
Token::Match(tok2, "%varid% != %num% ; ++ %varid%", varid) ||
|
||||||
Token::Match(tok2, "%varid% != %num% ; %varid% ++", varid)) {
|
Token::Match(tok2, "%varid% != %num% ; %varid% ++", varid)) {
|
||||||
maxMinFlipped = false;
|
maxMinFlipped = false;
|
||||||
const MathLib::bigint value = MathLib::toLongNumber(tok2->strAt(2));
|
const MathLib::bigint value = MathLib::toLongNumber(tok2->strAt(2));
|
||||||
max_value = MathLib::toString<MathLib::bigint>(value - 1);
|
max_value = MathLib::toString<MathLib::bigint>(value - 1);
|
||||||
} else if (Token::Match(tok2, "%varid% <= %num% ;", varid)) {
|
} else if (Token::Match(tok2, "%varid% <= %num% ;|&&|%oror%", varid)) {
|
||||||
maxMinFlipped = false;
|
maxMinFlipped = false;
|
||||||
max_value = tok2->strAt(2);
|
max_value = tok2->strAt(2);
|
||||||
} else if (Token::Match(tok2, "%num% < %varid% ;", varid) ||
|
} else if (Token::Match(tok2, "%num% < %varid% ;|&&|%oror%", varid) ||
|
||||||
Token::Match(tok2, "%num% != %varid% ; ++ %varid%", varid) ||
|
Token::Match(tok2, "%num% != %varid% ; ++ %varid%", varid) ||
|
||||||
Token::Match(tok2, "%num% != %varid% ; %varid% ++", varid)) {
|
Token::Match(tok2, "%num% != %varid% ; %varid% ++", varid)) {
|
||||||
maxMinFlipped = true;
|
maxMinFlipped = true;
|
||||||
const MathLib::bigint value = MathLib::toLongNumber(tok2->str());
|
const MathLib::bigint value = MathLib::toLongNumber(tok2->str());
|
||||||
max_value = min_value;
|
max_value = min_value;
|
||||||
min_value = MathLib::toString<MathLib::bigint>(value + 1);
|
min_value = MathLib::toString<MathLib::bigint>(value + 1);
|
||||||
} else if (Token::Match(tok2, "%num% <= %varid% ;", varid)) {
|
} else if (Token::Match(tok2, "%num% <= %varid% ;|&&|%oror%", varid)) {
|
||||||
maxMinFlipped = true;
|
maxMinFlipped = true;
|
||||||
max_value = min_value;
|
max_value = min_value;
|
||||||
min_value = tok2->str();
|
min_value = tok2->str();
|
||||||
} else {
|
} 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 false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -746,10 +758,20 @@ void CheckBufferOverrun::checkScopeForBody(const Token *tok, const ArrayInfo &ar
|
||||||
if (MathLib::toLongNumber(max_counter_value) < size)
|
if (MathLib::toLongNumber(max_counter_value) < size)
|
||||||
condition_out_of_bounds = false;
|
condition_out_of_bounds = false;
|
||||||
|
|
||||||
if (!for3(tok2->tokAt(4), counter_varid, min_counter_value, max_counter_value, maxMinFlipped))
|
// 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;
|
||||||
|
if (!for3(tok2->next(), counter_varid, min_counter_value, max_counter_value, maxMinFlipped))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Token::Match(tok2->tokAt(4), "%var% =|+=|-=") && MathLib::toLongNumber(max_counter_value) <= size)
|
if (Token::Match(tok2->next(), "%var% =|+=|-=") && MathLib::toLongNumber(max_counter_value) <= size)
|
||||||
condition_out_of_bounds = false;
|
condition_out_of_bounds = false;
|
||||||
|
|
||||||
// Goto the end parenthesis of the for-statement: "for (x; y; z)" ..
|
// Goto the end parenthesis of the for-statement: "for (x; y; z)" ..
|
||||||
|
|
|
@ -123,6 +123,7 @@ private:
|
||||||
TEST_CASE(array_index_for); // FN: for,if
|
TEST_CASE(array_index_for); // FN: for,if
|
||||||
TEST_CASE(array_index_for_neq); // #2211: Using != in condition
|
TEST_CASE(array_index_for_neq); // #2211: Using != in condition
|
||||||
TEST_CASE(array_index_for_question); // #2561: for, ?:
|
TEST_CASE(array_index_for_question); // #2561: for, ?:
|
||||||
|
TEST_CASE(array_index_for_andand_oror); // FN: using && or || in the for loop condition
|
||||||
TEST_CASE(array_index_vla_for); // #3221: access VLA inside for
|
TEST_CASE(array_index_vla_for); // #3221: access VLA inside for
|
||||||
TEST_CASE(array_index_extern); // FP when using 'extern'. #1684
|
TEST_CASE(array_index_extern); // FP when using 'extern'. #1684
|
||||||
TEST_CASE(array_index_cast); // FP after cast. #2841
|
TEST_CASE(array_index_cast); // FP after cast. #2841
|
||||||
|
@ -1688,6 +1689,43 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void array_index_for_andand_oror() { // #3907 - using && or ||
|
||||||
|
check("void f() {\n"
|
||||||
|
" char data[2];\n"
|
||||||
|
" int x;\n"
|
||||||
|
" for (x = 0; x < 10 && y; x++) {\n"
|
||||||
|
" data[x] = 0;\n"
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer access out-of-bounds: data\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char data[2];\n"
|
||||||
|
" int x;\n"
|
||||||
|
" for (x = 0; x < 10 || y; x++) {\n"
|
||||||
|
" data[x] = 0;\n"
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer access out-of-bounds: data\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char data[2];\n"
|
||||||
|
" int x;\n"
|
||||||
|
" for (x = 0; x <= 10 && y; x++) {\n"
|
||||||
|
" data[x] = 0;\n"
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer access out-of-bounds: data\n", errout.str());
|
||||||
|
|
||||||
|
check("void f() {\n"
|
||||||
|
" char data[2];\n"
|
||||||
|
" int x;\n"
|
||||||
|
" for (x = 0; y && x <= 10; x++) {\n"
|
||||||
|
" data[x] = 0;\n"
|
||||||
|
" }"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:5]: (error) Buffer access out-of-bounds: data\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
void array_index_for_break() {
|
void array_index_for_break() {
|
||||||
check("void f() {\n"
|
check("void f() {\n"
|
||||||
|
|
Loading…
Reference in New Issue