Bug 127029 - SubresourceLoader::didFinishLoading() should not assert when a decode error occurs
Summary: SubresourceLoader::didFinishLoading() should not assert when a decode error o...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore Misc. (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Daniel Bates
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2014-01-14 18:53 PST by Joseph Pecoraro
Modified: 2014-02-28 09:25 PST (History)
11 users (show)

See Also:


Attachments
Work-in-progress patch (4.95 KB, patch)
2014-02-26 13:45 PST, Daniel Bates
no flags Details | Formatted Diff | Diff
Patch and Layout test (4.72 KB, patch)
2014-02-26 16:52 PST, Daniel Bates
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph Pecoraro 2014-01-14 18:53:24 PST
Debug iOS WebKit in the Simulator loading apple.com produces:
ASSERT(!m_resource->errorOccurred()); in WebCore::SubresourceLoader::didFinishLoading

--

lldb> p m_resource->status()
(WebCore::CachedResource::Status) $23 = DecodeError

-- 

    bool CachedImage::canBeDrawn() const
    {
        if (!m_image || m_image->isNull())
            return false;

        if (!m_loader || m_loader->reachedTerminalState())
            return true;

        size_t estimatedDecodedImageSize = m_image->width() * m_image->height() * 4; // no overflow check
        return estimatedDecodedImageSize <= m_loader->frameLoader()->frame().settings().maximumDecodedImageSize();
    }

--

lldb> p m_resource->url().m_string.m_impl.m_ptr
(WTF::StringImpl *const) $21 = 0x000000011a2643c0 { length = 63, is8bit = 1, contents = 'http://images.apple.com/v/home/am/images/your_verse_hero_2x.jpg' }

lldb> p m_loader->frameLoader()->frame().settings().maximumDecodedImageSize();
20971520

lldb> p m_image->width() * m_image->height() * 4
27302400

--

Is the maximumDecodedImageSize smaller then it should be, or is this a valid path and the ASSERT should be handled appropriately?
Comment 1 Joseph Pecoraro 2014-01-15 11:37:48 PST
> Is the maximumDecodedImageSize smaller then it should be

No. This is 20 * 1024 * 1024, which is the expected size on iOS.


> or is this a valid path and the ASSERT should be handled appropriately?

I think this is the issue. I think a DecodeError should probably have been handled higher up in the stack to not reach this ASSERT. The reason this ASSERT is not seen on Mac is that there is no max decoded size, and such a DecodeError never gets triggered.
Comment 2 Alexey Proskuryakov 2014-01-15 14:10:23 PST
Would WebKit hit this assertion on Mac if there is a true decode error (e.g. garbage bytes instead of an image resource)? If not, what prevents that from happening?

That said, it seems strange that a platform limitation like this is implemented via simulating a load failure.
Comment 3 Daniel Bates 2014-01-21 10:46:42 PST
(In reply to comment #2)
> Would WebKit hit this assertion on Mac if there is a true decode error (e.g. garbage bytes instead of an image resource)? 

No.

> If not, what prevents that from happening?

Either decoding happens after the resource is loaded (e.g. a font) or, in the case of a CachedImage, we don't explicitly query the status of the image decoder and hence don't update the status of the CachedResource (i.e. CachedResource::setStatus()) when an actual decoder error occurs. CachedImage is implicitly (*) informed about a decode error by the return value of calling Image::setData() in CachedImage::addIncrementalDataBuffer(), <http://trac.webkit.org/browser/trunk/Source/WebCore/loader/cache/CachedImage.cpp?rev=161309#L406> and CachedImage::finishLoading(), <http://trac.webkit.org/browser/trunk/Source/WebCore/loader/cache/CachedImage.cpp?rev=161309#L447>. As aforementioned, we don't use this return value to update the status of the resource.

(*) Looking at the control flow for a bitmap image, Image::setData() => BitmapImage::dataChanged() => ImageSource::isSizeAvailable() => BitmapImage::isSizeAvailable() => ImageSource::isSizeAvailable(). And ImageSource::isSizeAvailable() (as defined in ImageSourceCG.cpp) will return false if the status of the decoder is EOF was encountered unexpectedly (kCGImageStatusUnexpectedEOF), invalid data (kCGImageStatusInvalidData), the image is an unknown type (kCGImageStatusUnknownType), the decoder is in the process of reading the header of the image (kCGImageStatusReadingHeader), and "the operation is not complete" (kCGImageStatusIncomplete). See <https://developer.apple.com/library/ios/documentation/graphicsimaging/reference/CGImageSource/Reference/reference.html> for more details on the aforementioned status codes.

> That said, it seems strange that a platform limitation like this is implemented via simulating a load failure.

This platform limitation doesn't trigger a load failure therefore the assertion failure. That is, when a decode error occurs we continue the load through to completion and hence SubresourceLoader::didFinishLoading() is called.
Comment 4 Alexey Proskuryakov 2014-02-18 11:26:55 PST
<rdar://problem/16093385>
Comment 5 Daniel Bates 2014-02-26 13:45:59 PST
Created attachment 225292 [details]
Work-in-progress patch

Work-in-progress patch. There are some FIXME comments that need to be addressed in this patch. I'm not happy with this patch.
Comment 6 Daniel Bates 2014-02-26 16:52:06 PST
Created attachment 225323 [details]
Patch and Layout test
Comment 7 Daniel Bates 2014-02-26 17:01:03 PST
After speaking with Alexey Proskuryakov in-person today (02/26) we may want to consider removing the setting Settings::maximumDecodedImageSize() and related logic since the logic for this feature is broken. Specifically, when a maximum decoded image size is specified and an image exceeds it during an incremental load we don't cancel the load, see bug #129394. Additionally, when we determine that an image exceeds the maximum decoded image size on load completion we allow it to be decoded (though we may use subsampling) instead of preventing it from being decoded. Although when an image exceeds the maximum decoded image size we remove it from the memory cache, Simon Fraser raised a concern that we may subsequently download it again (and fail with the same decoding error) because we remove it from the memory cache without telling WebKit to prevent subsequent loads for the image. A minor issue is that Settings::maximumDecodedImageSize() seems too stringent for image documents. That is, loading an image file directly.
Comment 8 Daniel Bates 2014-02-28 09:25:11 PST
Committed r164863: <http://trac.webkit.org/changeset/164863>