Fix #12272 (removeContradiction() Avoid use-after-free on multiple remove) (#5707)

As reported in
https://sourceforge.net/p/cppcheck/discussion/general/thread/fa43fb8ab1/
removeContradiction() minValue/maxValue.remove(..) can access free'd
memory as it removes all matching values by iterating over the complete
list. Creating a full copy instead of a reference avoids this issue.

Signed-off-by: Dirk Müller <dirk@dmllr.de>
This commit is contained in:
Dirk Mueller 2023-12-19 20:44:22 +01:00 committed by GitHub
parent 49da3e3821
commit 76695f6be2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 42 additions and 34 deletions

View File

@ -240,21 +240,25 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
if (!inlineSuppressionsBlockBegin.empty()) { if (!inlineSuppressionsBlockBegin.empty()) {
const Suppressions::Suppression lastBeginSuppression = inlineSuppressionsBlockBegin.back(); const Suppressions::Suppression lastBeginSuppression = inlineSuppressionsBlockBegin.back();
for (const Suppressions::Suppression &supprBegin : inlineSuppressionsBlockBegin) auto supprBegin = inlineSuppressionsBlockBegin.begin();
while (supprBegin != inlineSuppressionsBlockBegin.end())
{ {
if (lastBeginSuppression.lineNumber != supprBegin.lineNumber) if (lastBeginSuppression.lineNumber != supprBegin->lineNumber) {
++supprBegin;
continue; continue;
}
if (suppr.symbolName == supprBegin.symbolName && suppr.lineNumber > supprBegin.lineNumber) { if (suppr.symbolName == supprBegin->symbolName && suppr.lineNumber > supprBegin->lineNumber) {
suppr.lineBegin = supprBegin.lineNumber; suppr.lineBegin = supprBegin->lineNumber;
suppr.lineEnd = suppr.lineNumber; suppr.lineEnd = suppr.lineNumber;
suppr.lineNumber = supprBegin.lineNumber; suppr.lineNumber = supprBegin->lineNumber;
suppr.type = Suppressions::Type::block; suppr.type = Suppressions::Type::block;
inlineSuppressionsBlockBegin.remove(supprBegin); inlineSuppressionsBlockBegin.erase(supprBegin);
suppressions.addSuppression(std::move(suppr)); suppressions.addSuppression(std::move(suppr));
throwError = false; throwError = false;
break; break;
} }
++supprBegin;
} }
} }

View File

@ -2052,64 +2052,68 @@ static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y)
return std::abs(x.intvalue - y.intvalue) == 1; return std::abs(x.intvalue - y.intvalue) == 1;
} }
static bool removePointValue(std::list<ValueFlow::Value>& values, ValueFlow::Value& x) static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x)
{ {
const bool isPoint = x.bound == ValueFlow::Value::Bound::Point; const bool isPoint = x->bound == ValueFlow::Value::Bound::Point;
if (!isPoint) if (!isPoint)
x.decreaseRange(); x->decreaseRange();
else else
values.remove(x); x = values.erase(x);
return isPoint; return isPoint;
} }
static bool removeContradiction(std::list<ValueFlow::Value>& values) static bool removeContradiction(std::list<ValueFlow::Value>& values)
{ {
bool result = false; bool result = false;
for (ValueFlow::Value& x : values) { for (auto itx = values.begin(); itx != values.end(); ++itx) {
if (x.isNonValue()) if (itx->isNonValue())
continue; continue;
for (ValueFlow::Value& y : values) {
if (y.isNonValue()) auto ity = itx;
++ity;
for (; ity != values.end(); ++ity) {
if (ity->isNonValue())
continue; continue;
if (x == y) if (*itx == *ity)
continue; continue;
if (x.valueType != y.valueType) if (itx->valueType != ity->valueType)
continue; continue;
if (x.isImpossible() == y.isImpossible()) if (itx->isImpossible() == ity->isImpossible())
continue; continue;
if (x.isSymbolicValue() && !ValueFlow::Value::sameToken(x.tokvalue, y.tokvalue)) if (itx->isSymbolicValue() && !ValueFlow::Value::sameToken(itx->tokvalue, ity->tokvalue))
continue; continue;
if (!x.equalValue(y)) { if (!itx->equalValue(*ity)) {
auto compare = [](const ValueFlow::Value& x, const ValueFlow::Value& y) { auto compare = [](const std::list<ValueFlow::Value>::const_iterator& x, const std::list<ValueFlow::Value>::const_iterator& y) {
return x.compareValue(y, less{}); return x->compareValue(*y, less{});
}; };
const ValueFlow::Value& maxValue = std::max(x, y, compare); auto itMax = std::max(itx, ity, compare);
const ValueFlow::Value& minValue = std::min(x, y, compare); auto itMin = std::min(itx, ity, compare);
// TODO: Adjust non-points instead of removing them // TODO: Adjust non-points instead of removing them
if (maxValue.isImpossible() && maxValue.bound == ValueFlow::Value::Bound::Upper) { if (itMax->isImpossible() && itMax->bound == ValueFlow::Value::Bound::Upper) {
values.remove(minValue); values.erase(itMin);
return true; return true;
} }
if (minValue.isImpossible() && minValue.bound == ValueFlow::Value::Bound::Lower) { if (itMin->isImpossible() && itMin->bound == ValueFlow::Value::Bound::Lower) {
values.remove(maxValue); values.erase(itMax);
return true; return true;
} }
continue; continue;
} }
const bool removex = !x.isImpossible() || y.isKnown(); const bool removex = !itx->isImpossible() || ity->isKnown();
const bool removey = !y.isImpossible() || x.isKnown(); const bool removey = !ity->isImpossible() || itx->isKnown();
if (x.bound == y.bound) { if (itx->bound == ity->bound) {
if (removex) if (removex)
values.remove(x); values.erase(itx);
if (removey) if (removey)
values.remove(y); values.erase(ity);
// itx and ity are invalidated
return true; return true;
} }
result = removex || removey; result = removex || removey;
bool bail = false; bool bail = false;
if (removex && removePointValue(values, x)) if (removex && removePointValue(values, itx))
bail = true; bail = true;
if (removey && removePointValue(values, y)) if (removey && removePointValue(values, ity))
bail = true; bail = true;
if (bail) if (bail)
return true; return true;