[Webkit-unassigned] [Bug 172552] New: REGRESSION (r206481): Don't assume frameCount() is larger than or equal to the size of the frame cache

bugzilla-daemon at webkit.org bugzilla-daemon at webkit.org
Wed May 24 12:17:39 PDT 2017


https://bugs.webkit.org/show_bug.cgi?id=172552

            Bug ID: 172552
           Summary: REGRESSION (r206481): Don't assume frameCount() is
                    larger than or equal to the size of the frame cache
           Product: WebKit
           Version: WebKit Nightly Build
          Hardware: Unspecified
                OS: Unspecified
            Status: NEW
          Severity: Normal
          Priority: P2
         Component: Images
          Assignee: webkit-unassigned at lists.webkit.org
          Reporter: sabouhallawa at apple.com

Before <http://trac.webkit.org/changeset/206481>, BitmapImage::cacheFrame() had the following statement:

    if (m_frames.size() < numFrames)
        m_frames.grow(numFrames)

Since this change was landed, ImageFrameCache::growFrames() has the following code:

    ASSERT(m_frames.size() <= frameCount());
    m_frames.grow(frameCount());

The assumption was ImageDecoder may change the value of the frameCount() when it receives more data but for sure the value of the new frameCount() is larger than the previous value. And since in ImageFrameCache::growFrames() we want to match m_frames.size() with the current frameCount(), m_frames.size() should be equal to the previous or the current frameCount() which should be equal to or less than the current frameCount(). This means m_frames.size() should be less than or equal to frameCount() always. And this why I replaced the if-satament with just an assertion.

But this assumption does not consider the case when the image is cached and its encoded data is released. In this case, the encoded data will be read incrementally and the current m_frames.size() will be larger than the initial frameCount().

Aside form the assertion will fire in debug build, this would not be a problem if Vector::grow() handles this case safely but it does not. Vector::grow() asserts ASSERT(size >= m_size) but it does not return if (size < m_size). The real problem happens because of this statement in Vector::grow()

    if (begin())
        TypeOperations::initialize(end(), begin() + size);

If size < m_size => begin() + size < begin() + m_size => begin() + size() < end(). So we are sending two pointers to TypeOperations::initialize(), the first is larger than the second. In the case of ImageFrame, this will be VectorInitializer to be called:

template<typename T>
struct VectorInitializer<true, false, T>
{
    static void initialize(T* begin, T* end) 
    {
        for (T* cur = begin; cur != end; ++cur)
            new (NotNull, cur) T;
    }
};

if begin > end, the for loop above will never terminates and will crash because of memory access violation and get a crash like this:

0   com.apple.WebCore                   0x00007fffc0688481 WebCore::ImageFrame::ImageFrame() + 17
1   com.apple.WebCore                   0x00007fffc0689038 WebCore::ImageFrameCache::growFrames() + 152
2   com.apple.WebCore                   0x00007fffc068f71b WebCore::ImageSource::dataChanged(WebCore::SharedBuffer*, bool) + 91
3   com.apple.WebCore                   0x00007fffc0224095 WebCore::CachedImage::setImageDataBuffer(WebCore::SharedBuffer*, bool) + 53
4   com.apple.WebCore                   0x00007fffc0223f8f WebCore::CachedImage::addIncrementalDataBuffer(WebCore::SharedBuffer&) + 63
5   com.apple.WebCore                   0x00007fffc0224132 WebCore::CachedImage::addDataBuffer(WebCore::SharedBuffer&) + 18
6   com.apple.WebCore                   0x00007fffc0fd1ef7 WebCore::SubresourceLoader::didReceiveDataOrBuffer(char const*, int, WTF::RefPtr<WebCore::SharedBuffer>&&, long long, WebCore::DataPayloadType) + 183
7   com.apple.WebCore                   0x00007fffc0fd1f8a WebCore::SubresourceLoader::didReceiveBuffer(WTF::Ref<WebCore::SharedBuffer>&&, long long, WebCore::DataPayloadType) + 42

-- 
You are receiving this mail because:
You are the assignee for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.webkit.org/pipermail/webkit-unassigned/attachments/20170524/86bed08d/attachment.html>


More information about the webkit-unassigned mailing list