Bug 223236 - [SOUP] SOUP3 crashes inside soup_message_set_request_body
Summary: [SOUP] SOUP3 crashes inside soup_message_set_request_body
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Page Loading (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Nobody
URL:
Keywords: InRadar
Depends on:
Blocks: libsoup3
  Show dependency treegraph
 
Reported: 2021-03-15 21:01 PDT by Lauro Moura
Modified: 2021-03-18 04:13 PDT (History)
10 users (show)

See Also:


Attachments
http/tests/xmlhttprequest/upload-onloadstart-event.html crash log (53.31 KB, text/plain)
2021-03-15 21:01 PDT, Lauro Moura
no flags Details
Patch (3.71 KB, patch)
2021-03-17 03:36 PDT, Carlos Garcia Campos
aperez: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Lauro Moura 2021-03-15 21:01:46 PDT
Created attachment 423293 [details]
http/tests/xmlhttprequest/upload-onloadstart-event.html crash log

http/tests/xmlhttprequest/loadstart-event-init.html
http/tests/xmlhttprequest/redirect-cross-origin-post-sync.html
http/tests/xmlhttprequest/redirect-cross-origin-post.html
http/tests/xmlhttprequest/response-access-on-error.html
http/tests/xmlhttprequest/upload-onabort-progressevent-attributes.html
http/tests/xmlhttprequest/upload-onload-event.html
http/tests/xmlhttprequest/upload-onload-progressevent-attributes.html
http/tests/xmlhttprequest/upload-onloadend-event-after-abort.html
http/tests/xmlhttprequest/upload-onloadend-event-after-load.html
http/tests/xmlhttprequest/upload-onloadstart-event.html
http/tests/xmlhttprequest/upload-onprogress-event.html
http/tests/xmlhttprequest/upload-progress-events.html
http/tests/xmlhttprequest/xmlhttprequest-sync-no-progress-events.html

These happen to crash locally and in the bots (althought not all might be run, due to early exits).

This is only a partial list. Other tests might be affected.

STDERR:
STDERR: (process:2504): libsoup-CRITICAL **: 20:42:47.243: soup_message_set_request_body: assertion 'stream == NULL || G_IS_POLLABLE_INPUT_STREAM (stream)' failed
STDERR: LEAK: 1 WebPageProxy

Tip of trace for http/tests/xmlhttprequest/upload-onloadstart-event.html (full attached)

Thread 1 (Thread 0x7efdae91e9c0 (LWP 2504)):
#0  g_logv (log_domain=0x7efdafbb7943 "libsoup", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=<optimized out>) at ../glib/gmessages.c:1413
#1  0x00007efdb0eb4973 in g_log (log_domain=<optimized out>, log_level=<optimized out>, format=<optimized out>) at ../glib/gmessages.c:1451
#2  0x00007efdbc2257f6 in WebCore::ResourceRequest::updateSoupMessageBody(_SoupMessage*, WebCore::BlobRegistryImpl&) const (this=0x7efd6c2f3788, soupMessage=0x7efd4c0083b0 [SoupMessage], blobRegistry=...
) at ../../Source/WebCore/platform/network/soup/ResourceRequestSoup.cpp:138
#3  0x00007efdbc22556c in WebCore::ResourceRequest::createSoupMessage(WebCore::BlobRegistryImpl&) const (this=0x7efd6c2f3788, blobRegistry=...) at ../../Source/WebCore/platform/network/soup/ResourceReque
stSoup.cpp:90
#4  0x00007efdb8c06b17 in WebKit::NetworkDataTaskSoup::createRequest(WebCore::ResourceRequest&&, WebKit::NetworkDataTaskSoup::WasBlockingCookies) (this=0x7efd6c2f3580, request=..., wasBlockingCookies=Web
Kit::NetworkDataTaskSoup::WasBlockingCookies::No) at ../../Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp:127
#5  0x00007efdb8c065f1 in WebKit::NetworkDataTaskSoup::NetworkDataTaskSoup(WebKit::NetworkSession&, WebKit::NetworkDataTaskClient&, WebCore::ResourceRequest const&, WTF::ObjectIdentifier<WebCore::FrameId
entifierType>, WTF::ObjectIdentifier<WebCore::PageIdentifierType>, WebCore::StoredCredentialsPolicy, WebCore::ContentSniffingPolicy, WebCore::ContentEncodingSniffingPolicy, bool, bool) (this=0x7efd6c2f35
80, session=..., client=..., requestWithCredentials=..., frameID=..., pageID=..., storedCredentialsPolicy=WebCore::StoredCredentialsPolicy::Use, shouldContentSniff=WebCore::ContentSniffingPolicy::DoNotSniffContent, shouldClearReferrerOnHTTPSToHTTPRedirect=true, dataTaskIsForMainFrameNavigation=false) at ../../Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.cpp:81
#6  0x00007efdb88c1b57 in WebKit::NetworkDataTaskSoup::create(WebKit::NetworkSession&, WebKit::NetworkDataTaskClient&, WebCore::ResourceRequest const&, WTF::ObjectIdentifier<WebCore::FrameIdentifierType>, WTF::ObjectIdentifier<WebCore::PageIdentifierType>, WebCore::StoredCredentialsPolicy, WebCore::ContentSniffingPolicy, WebCore::ContentEncodingSniffingPolicy, bool, bool) (session=..., client=..., request=..., frameID=..., pageID=..., storedCredentialsPolicy=WebCore::StoredCredentialsPolicy::Use, shouldContentSniff=WebCore::ContentSniffingPolicy::DoNotSniffContent, shouldContentEncodingSniff=WebCore::ContentEncodingSniffingPolicy::DoNotSniff, shouldClearReferrerOnHTTPSToHTTPRedirect=true, dataTaskIsForMainFrameNavigation=false) at ../../Source/WebKit/NetworkProcess/soup/NetworkDataTaskSoup.h:45
#7  0x00007efdb88acb5d in WebKit::NetworkDataTask::create(WebKit::NetworkSession&, WebKit::NetworkDataTaskClient&, WebKit::NetworkLoadParameters const&) (session=..., client=..., parameters=...) at ../../Source/WebKit/NetworkProcess/NetworkDataTask.cpp:60
#8  0x00007efdb88b015b in WebKit::NetworkLoad::NetworkLoad(WebKit::NetworkLoadClient&, WebCore::BlobRegistryImpl*, WebKit::NetworkLoadParameters&&, WebKit::NetworkSession&) (this=0x7efdae0e1000, client=..., blobRegistry=0x7efdae0d6138, parameters=..., networkSession=...) at ../../Source/WebKit/NetworkProcess/NetworkLoad.cpp:57
Comment 2 Daniel Kolesa 2021-03-16 04:29:13 PDT
the current soup code doesn't really have any requirement for the request body to be pollable, so the soup3 webkit code assumes that it's not necessary, but the upcoming http2 code will require it to be pollable - so the restriction was put in place - so i guess the webkit code will need to be updated
Comment 3 Daniel Kolesa 2021-03-16 04:32:51 PDT
i guess the thing to do here would be to just do the same as the soup2 code - i.e. read all into bytes, then set the request body from bytes rather than from the input stream...
Comment 4 Carlos Garcia Campos 2021-03-16 05:54:40 PDT
(In reply to Daniel Kolesa from comment #3)
> i guess the thing to do here would be to just do the same as the soup2 code
> - i.e. read all into bytes, then set the request body from bytes rather than
> from the input stream...

That's problematic for long file uploads, for example. The WebKit stream can't be pollable because it used GFileInputStream internally that is not pollable. I can make it pollable and only return TRUE from can_poll when not having file streams. But the solution would be to make libsoup work without pollable streams, at least having fallback code that reads using the async apis into an intermediate buffer that is later used to write in the output.
Comment 5 Carlos Garcia Campos 2021-03-17 03:36:24 PDT
Created attachment 423468 [details]
Patch
Comment 6 Daniel Kolesa 2021-03-17 06:19:51 PDT
patch looks good to me, the rest of the fix needs to be in soup (remove the pollable stream requirement and implement a fallback path for when it's not in the http2 backend)
Comment 7 Adrian Perez 2021-03-18 03:40:52 PDT
Comment on attachment 423468 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=423468&action=review

> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:137
> +    // GFileInputStream is not pollable, so the stream is only pollable if FormData doesn't contain EncodedFileData elements.

I wonder if it could be an options to check whether a GInputStream is a GUnixInputStream
(which does implement GPollableInputStream) which would make the file elements pollable,
or whether the GInputStream implements the GFileDescriptorBased interface, in which case
we could use the _get_fd() method and use GPollFD or similar 🤔️

(No need to change anything in this patch, by the way, this is just me mulling ideas
over. If you think any of this makes sense for a follow-up patch it would be nice
to write it down as a TODO and/or make a new Bugzilla issue to track it.)

> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:177
> +    return g_pollable_source_new_full(stream, base.get(), cancellable);

Aren't these two lines equivalent to a plain g_pollable_input_stream_create_source() call?
As in:

   return g_pollable_input_stream_create_source(stream, cancellable);
Comment 8 Carlos Garcia Campos 2021-03-18 03:49:17 PDT
Comment on attachment 423468 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=423468&action=review

>> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:137
>> +    // GFileInputStream is not pollable, so the stream is only pollable if FormData doesn't contain EncodedFileData elements.
> 
> I wonder if it could be an options to check whether a GInputStream is a GUnixInputStream
> (which does implement GPollableInputStream) which would make the file elements pollable,
> or whether the GInputStream implements the GFileDescriptorBased interface, in which case
> we could use the _get_fd() method and use GPollFD or similar 🤔️
> 
> (No need to change anything in this patch, by the way, this is just me mulling ideas
> over. If you think any of this makes sense for a follow-up patch it would be nice
> to write it down as a TODO and/or make a new Bugzilla issue to track it.)

We are always reading local files, so it's always GFileInputStream and not pollable.

>> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:177
>> +    return g_pollable_source_new_full(stream, base.get(), cancellable);
> 
> Aren't these two lines equivalent to a plain g_pollable_input_stream_create_source() call?
> As in:
> 
>    return g_pollable_input_stream_create_source(stream, cancellable);

This is the implementation of g_pollable_input_stream_create_source().
Comment 9 Adrian Perez 2021-03-18 04:11:01 PDT
(In reply to Carlos Garcia Campos from comment #8)
> Comment on attachment 423468 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=423468&action=review
> 
> >> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:137
> >> +    // GFileInputStream is not pollable, so the stream is only pollable if FormData doesn't contain EncodedFileData elements.
> > 
> > I wonder if it could be an options to check whether a GInputStream is a GUnixInputStream
> > (which does implement GPollableInputStream) which would make the file elements pollable,
> > or whether the GInputStream implements the GFileDescriptorBased interface, in which case
> > we could use the _get_fd() method and use GPollFD or similar 🤔️
> > 
> > (No need to change anything in this patch, by the way, this is just me mulling ideas
> > over. If you think any of this makes sense for a follow-up patch it would be nice
> > to write it down as a TODO and/or make a new Bugzilla issue to track it.)
> 
> We are always reading local files, so it's always GFileInputStream and not
> pollable.

👌️

> >> Source/WebCore/platform/network/soup/WebKitFormDataInputStream.cpp:177
> >> +    return g_pollable_source_new_full(stream, base.get(), cancellable);
> > 
> > Aren't these two lines equivalent to a plain g_pollable_input_stream_create_source() call?
> > As in:
> > 
> >    return g_pollable_input_stream_create_source(stream, cancellable);
> 
> This is the implementation of g_pollable_input_stream_create_source().

Right, I did not notice at first, my brain is a bit foggy this morning 😇️
Comment 10 Carlos Garcia Campos 2021-03-18 04:12:53 PDT
Committed r274640 (235467@main): <https://commits.webkit.org/235467@main>
Comment 11 Radar WebKit Bug Importer 2021-03-18 04:13:16 PDT
<rdar://problem/75567967>