WebKit Bugzilla
New
Browse
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
Bug 120802
[CSS Shapes] Heap-buffer-overflow in WebCore::ShapeInterval<float>::subtractShapeIntervals
https://bugs.webkit.org/show_bug.cgi?id=120802
Summary
[CSS Shapes] Heap-buffer-overflow in WebCore::ShapeInterval<float>::subtractS...
Hans Muller
Reported
2013-09-05 15:22:05 PDT
The attached test caused a crash when run with a bounds checker, see
https://code.google.com/p/chromium/issues/detail?id=285788
. The source of the problem are several assignments like this: static void subtractShapeIntervals(const ShapeIntervals& a, const ShapeIntervals& b, ShapeIntervals& result) { ... const_iterator aNext = a.begin(); const_iterator bNext = b.begin(); ShapeInterval<T> aValue = *aNext; ShapeInterval<T> bValue = *bNext; while (aNext != a.end() && bNext != b.end()) { if (bValue.contains(aValue)) aValue = *++aNext; // BAD ... } .... } Although the LHS of the assignments aren't used when the corresponding iterator has reached its end, the expression still dereferences an invalid address (a.end() in this case). The loop has been rewritten; we do not dereference the aNext or bNext iterators without checking the end condition.
Attachments
Test case.
(153 bytes, text/html)
2013-09-05 15:22 PDT
,
Hans Muller
no flags
Details
Patch
(5.19 KB, patch)
2013-09-05 15:43 PDT
,
Hans Muller
no flags
Details
Formatted Diff
Diff
View All
Add attachment
proposed patch, testcase, etc.
Hans Muller
Comment 1
2013-09-05 15:22:50 PDT
Created
attachment 210670
[details]
Test case.
Hans Muller
Comment 2
2013-09-05 15:43:23 PDT
Created
attachment 210673
[details]
Patch
Darin Adler
Comment 3
2013-09-06 13:53:44 PDT
Comment on
attachment 210673
[details]
Patch The coding style here is awkward. The names “a/b increment” are not so good. I would call them shouldIncrementA/B instead. Also, the logic seems unnecessarily twisted. I have to read it over and over again to be sure it’s right. Might be worth another look to see if we can make the logic clearer. I think we could probably make a version that uses expressions like *aNext++ and eliminates the local variables that would be a lot less confusing.
Hans Muller
Comment 4
2013-09-09 09:10:57 PDT
(In reply to
comment #3
)
> (From update of
attachment 210673
[details]
) > The coding style here is awkward. The names “a/b increment” are not so good. I would call them shouldIncrementA/B instead. Also, the logic seems unnecessarily twisted. I have to read it over and over again to be sure it’s right. Might be worth another look to see if we can make the logic clearer. I think we could probably make a version that uses expressions like *aNext++ and eliminates the local variables that would be a lot less confusing.
I used aIncrement and bIncrement instead of names that make more sense as English, to emphasize the relationship between aValue, aNext, and aIncrement. I agree that the logic is difficult to follow (it's better than it once was, if that's any consolation). I will take another crack and making it clearer (and hopefully a little shorter) in another patch. Thanks for the review.
WebKit Commit Bot
Comment 5
2013-09-09 09:34:41 PDT
Comment on
attachment 210673
[details]
Patch Clearing flags on attachment: 210673 Committed
r155354
: <
http://trac.webkit.org/changeset/155354
>
WebKit Commit Bot
Comment 6
2013-09-09 09:34:43 PDT
All reviewed patches have been landed. Closing bug.
Hans Muller
Comment 7
2013-09-13 10:26:17 PDT
(In reply to
comment #3
)
> (From update of
attachment 210673
[details]
) > The coding style here is awkward. The names “a/b increment” are not so good. I would call them shouldIncrementA/B instead. Also, the logic seems unnecessarily twisted. I have to read it over and over again to be sure it’s right. Might be worth another look to see if we can make the logic clearer. I think we could probably make a version that uses expressions like *aNext++ and eliminates the local variables that would be a lot less confusing.
I took a run at this. The loop isn't simple enough to just use expressions like *aNext++ so I tried moving the fussy logic about safely managing a mutable interval value per iterator to a separate class: class SubtractShapeIntervalsIterator { public: SubtractShapeIntervalsIterator (const ShapeIntervals& intervals) : m_intervals(intervals) , m_nextInterval(intervals.begin()) { if (!m_intervals.isEmpty()) m_value = *m_nextInterval; } const_iterator shapeIntervalsIterator() const { return m_nextInterval; } bool isEnd() const { return m_intervals.isEmpty() || m_nextInterval == m_intervals.end(); } void next() { if (!m_intervals.isEmpty() && ++m_nextInterval != m_intervals.end()) m_value = *m_nextInterval; } ShapeInterval& value() { ASSERT(!m_intervals.empty() && m_nextInterval != m_intervals.end()); return m_value; } private: const ShapeIntervals& m_intervals; const_iterator m_nextInterval; ShapeInterval m_value; }; Rewriting the loop in terms of this private class makes it a little shorter, but sadly I don't think it's simpler or even more readable. while(!aIterator.isEnd() && !bIterator.isEnd()) { if (bIterator.value().contains(aIterator.value())) { aIterator.next(); } else if (aIterator.value().contains(bIterator.value())) { if (bIterator.value().x1() > aIterator.value().x1()) result.push_back(ShapeInterval<T>(aIterator.value().x1(), bIterator.value().x1())); if (aIterator.value().x2() > bIterator.value().x2()) aIterator.value().setX1(bIterator.value().x2()); else aIterator.next(); bIterator.next(); } else if (aIterator.value().overlaps(bIterator.value())) { if (aIterator.value() < bIterator.value()) { result.push_back(ShapeInterval<T>(aIterator.value().x1(), bIterator.value().x1())); aIterator.next(); } else { aIterator.value().setX1(bIterator.value().x2()); bIterator.next(); } } else { if (aIterator.value() < bIterator.value()) { result.push_back(aIterator.value()); aIterator.next(); } else bIterator.next(); } } if (!aIterator.isEnd()) { result.push_back(aIterator.value()); result.insert(result.end(), aIterator.shapeIntervalsIterator() + 1, a.end()); }
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug