Skip to content

Commit 76695f6

Browse files
authored
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>
1 parent 49da3e3 commit 76695f6

2 files changed

Lines changed: 42 additions & 34 deletions

File tree

lib/preprocessor.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,21 +240,25 @@ static void addInlineSuppressions(const simplecpp::TokenList &tokens, const Sett
240240
if (!inlineSuppressionsBlockBegin.empty()) {
241241
const Suppressions::Suppression lastBeginSuppression = inlineSuppressionsBlockBegin.back();
242242

243-
for (const Suppressions::Suppression &supprBegin : inlineSuppressionsBlockBegin)
243+
auto supprBegin = inlineSuppressionsBlockBegin.begin();
244+
while (supprBegin != inlineSuppressionsBlockBegin.end())
244245
{
245-
if (lastBeginSuppression.lineNumber != supprBegin.lineNumber)
246+
if (lastBeginSuppression.lineNumber != supprBegin->lineNumber) {
247+
++supprBegin;
246248
continue;
249+
}
247250

248-
if (suppr.symbolName == supprBegin.symbolName && suppr.lineNumber > supprBegin.lineNumber) {
249-
suppr.lineBegin = supprBegin.lineNumber;
251+
if (suppr.symbolName == supprBegin->symbolName && suppr.lineNumber > supprBegin->lineNumber) {
252+
suppr.lineBegin = supprBegin->lineNumber;
250253
suppr.lineEnd = suppr.lineNumber;
251-
suppr.lineNumber = supprBegin.lineNumber;
254+
suppr.lineNumber = supprBegin->lineNumber;
252255
suppr.type = Suppressions::Type::block;
253-
inlineSuppressionsBlockBegin.remove(supprBegin);
256+
inlineSuppressionsBlockBegin.erase(supprBegin);
254257
suppressions.addSuppression(std::move(suppr));
255258
throwError = false;
256259
break;
257260
}
261+
++supprBegin;
258262
}
259263
}
260264

lib/token.cpp

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2052,64 +2052,68 @@ static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y)
20522052
return std::abs(x.intvalue - y.intvalue) == 1;
20532053
}
20542054

2055-
static bool removePointValue(std::list<ValueFlow::Value>& values, ValueFlow::Value& x)
2055+
static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x)
20562056
{
2057-
const bool isPoint = x.bound == ValueFlow::Value::Bound::Point;
2057+
const bool isPoint = x->bound == ValueFlow::Value::Bound::Point;
20582058
if (!isPoint)
2059-
x.decreaseRange();
2059+
x->decreaseRange();
20602060
else
2061-
values.remove(x);
2061+
x = values.erase(x);
20622062
return isPoint;
20632063
}
20642064

20652065
static bool removeContradiction(std::list<ValueFlow::Value>& values)
20662066
{
20672067
bool result = false;
2068-
for (ValueFlow::Value& x : values) {
2069-
if (x.isNonValue())
2068+
for (auto itx = values.begin(); itx != values.end(); ++itx) {
2069+
if (itx->isNonValue())
20702070
continue;
2071-
for (ValueFlow::Value& y : values) {
2072-
if (y.isNonValue())
2071+
2072+
auto ity = itx;
2073+
++ity;
2074+
for (; ity != values.end(); ++ity) {
2075+
if (ity->isNonValue())
20732076
continue;
2074-
if (x == y)
2077+
if (*itx == *ity)
20752078
continue;
2076-
if (x.valueType != y.valueType)
2079+
if (itx->valueType != ity->valueType)
20772080
continue;
2078-
if (x.isImpossible() == y.isImpossible())
2081+
if (itx->isImpossible() == ity->isImpossible())
20792082
continue;
2080-
if (x.isSymbolicValue() && !ValueFlow::Value::sameToken(x.tokvalue, y.tokvalue))
2083+
if (itx->isSymbolicValue() && !ValueFlow::Value::sameToken(itx->tokvalue, ity->tokvalue))
20812084
continue;
2082-
if (!x.equalValue(y)) {
2083-
auto compare = [](const ValueFlow::Value& x, const ValueFlow::Value& y) {
2084-
return x.compareValue(y, less{});
2085+
if (!itx->equalValue(*ity)) {
2086+
auto compare = [](const std::list<ValueFlow::Value>::const_iterator& x, const std::list<ValueFlow::Value>::const_iterator& y) {
2087+
return x->compareValue(*y, less{});
20852088
};
2086-
const ValueFlow::Value& maxValue = std::max(x, y, compare);
2087-
const ValueFlow::Value& minValue = std::min(x, y, compare);
2089+
auto itMax = std::max(itx, ity, compare);
2090+
auto itMin = std::min(itx, ity, compare);
20882091
// TODO: Adjust non-points instead of removing them
2089-
if (maxValue.isImpossible() && maxValue.bound == ValueFlow::Value::Bound::Upper) {
2090-
values.remove(minValue);
2092+
if (itMax->isImpossible() && itMax->bound == ValueFlow::Value::Bound::Upper) {
2093+
values.erase(itMin);
20912094
return true;
20922095
}
2093-
if (minValue.isImpossible() && minValue.bound == ValueFlow::Value::Bound::Lower) {
2094-
values.remove(maxValue);
2096+
if (itMin->isImpossible() && itMin->bound == ValueFlow::Value::Bound::Lower) {
2097+
values.erase(itMax);
20952098
return true;
20962099
}
20972100
continue;
20982101
}
2099-
const bool removex = !x.isImpossible() || y.isKnown();
2100-
const bool removey = !y.isImpossible() || x.isKnown();
2101-
if (x.bound == y.bound) {
2102+
const bool removex = !itx->isImpossible() || ity->isKnown();
2103+
const bool removey = !ity->isImpossible() || itx->isKnown();
2104+
if (itx->bound == ity->bound) {
21022105
if (removex)
2103-
values.remove(x);
2106+
values.erase(itx);
21042107
if (removey)
2105-
values.remove(y);
2108+
values.erase(ity);
2109+
// itx and ity are invalidated
21062110
return true;
21072111
}
21082112
result = removex || removey;
21092113
bool bail = false;
2110-
if (removex && removePointValue(values, x))
2114+
if (removex && removePointValue(values, itx))
21112115
bail = true;
2112-
if (removey && removePointValue(values, y))
2116+
if (removey && removePointValue(values, ity))
21132117
bail = true;
21142118
if (bail)
21152119
return true;

0 commit comments

Comments
 (0)