Skip to content

Commit 8aa9d71

Browse files
authored
Fix 11844: FP negativeIndex for known loop (#5282)
1 parent c257c70 commit 8aa9d71

4 files changed

Lines changed: 45 additions & 7 deletions

File tree

lib/astutils.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,9 +900,16 @@ bool extractForLoopValues(const Token *forToken,
900900
if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%"))
901901
return false;
902902
std::vector<MathLib::bigint> minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values());
903+
if (minInitValue.empty()) {
904+
const ValueFlow::Value* v = initExpr->astOperand2()->getMinValue(true);
905+
if (v)
906+
minInitValue.push_back(v->intvalue);
907+
}
908+
if (minInitValue.empty())
909+
return false;
903910
varid = initExpr->astOperand1()->varId();
904911
knownInitValue = initExpr->astOperand2()->hasKnownIntValue();
905-
initValue = minInitValue.empty() ? 0 : minInitValue.front();
912+
initValue = minInitValue.front();
906913
partialCond = Token::Match(condExpr, "%oror%|&&");
907914
visitAstNodes(condExpr, [varid, &condExpr](const Token *tok) {
908915
if (Token::Match(tok, "%oror%|&&"))

lib/token.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2415,25 +2415,40 @@ const ValueFlow::Value* Token::getValue(const MathLib::bigint val) const
24152415
return it == mImpl->mValues->end() ? nullptr : &*it;
24162416
}
24172417

2418-
const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const
2418+
template<class Compare>
2419+
static const ValueFlow::Value* getCompareValue(const std::list<ValueFlow::Value>& values,
2420+
bool condition,
2421+
MathLib::bigint path,
2422+
Compare compare)
24192423
{
2420-
if (!mImpl->mValues)
2421-
return nullptr;
24222424
const ValueFlow::Value* ret = nullptr;
2423-
for (const ValueFlow::Value& value : *mImpl->mValues) {
2425+
for (const ValueFlow::Value& value : values) {
24242426
if (!value.isIntValue())
24252427
continue;
24262428
if (value.isImpossible())
24272429
continue;
24282430
if (path > -0 && value.path != 0 && value.path != path)
24292431
continue;
2430-
if ((!ret || value.intvalue > ret->intvalue) &&
2431-
((value.condition != nullptr) == condition))
2432+
if ((!ret || compare(value.intvalue, ret->intvalue)) && ((value.condition != nullptr) == condition))
24322433
ret = &value;
24332434
}
24342435
return ret;
24352436
}
24362437

2438+
const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const
2439+
{
2440+
if (!mImpl->mValues)
2441+
return nullptr;
2442+
return getCompareValue(*mImpl->mValues, condition, path, std::greater<MathLib::bigint>{});
2443+
}
2444+
2445+
const ValueFlow::Value* Token::getMinValue(bool condition, MathLib::bigint path) const
2446+
{
2447+
if (!mImpl->mValues)
2448+
return nullptr;
2449+
return getCompareValue(*mImpl->mValues, condition, path, std::less<MathLib::bigint>{});
2450+
}
2451+
24372452
const ValueFlow::Value* Token::getMovedValue() const
24382453
{
24392454
if (!mImpl->mValues)

lib/token.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,6 +1224,7 @@ class CPPCHECKLIB Token {
12241224
const ValueFlow::Value* getValue(const MathLib::bigint val) const;
12251225

12261226
const ValueFlow::Value* getMaxValue(bool condition, MathLib::bigint path = 0) const;
1227+
const ValueFlow::Value* getMinValue(bool condition, MathLib::bigint path = 0) const;
12271228

12281229
const ValueFlow::Value* getMovedValue() const;
12291230

test/testbufferoverrun.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ class TestBufferOverrun : public TestFixture {
190190
TEST_CASE(array_index_negative7); // #5685
191191
TEST_CASE(array_index_negative8); // #11651
192192
TEST_CASE(array_index_negative9);
193+
TEST_CASE(array_index_negative10);
193194
TEST_CASE(array_index_for_decr);
194195
TEST_CASE(array_index_varnames); // FP: struct member #1576, FN: #1586
195196
TEST_CASE(array_index_for_continue); // for,continue
@@ -2336,6 +2337,20 @@ class TestBufferOverrun : public TestFixture {
23362337
ASSERT_EQUALS("[test.cpp:8]: (error) Array 'a[3]' accessed at index -1, which is out of bounds.\n", errout.str());
23372338
}
23382339

2340+
// #11844
2341+
void array_index_negative10()
2342+
{
2343+
check("struct S { int a[4]; };\n"
2344+
"void f(S* p, int k) {\n"
2345+
" int m = 3;\n"
2346+
" if (k)\n"
2347+
" m = 2;\n"
2348+
" for (int j = m + 1; j <= 4; j++)\n"
2349+
" p->a[j-1];\n"
2350+
"}\n");
2351+
ASSERT_EQUALS("", errout.str());
2352+
}
2353+
23392354
void array_index_for_decr() {
23402355
check("void f()\n"
23412356
"{\n"

0 commit comments

Comments
 (0)