Bug 228096 - REGRESSION (r278702): Cannot login to appaloosa-store.com/users/sign_in
Summary: REGRESSION (r278702): Cannot login to appaloosa-store.com/users/sign_in
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: Chris Dumez
URL:
Keywords: InRadar
Depends on:
Blocks: 226857
  Show dependency treegraph
 
Reported: 2021-07-19 18:59 PDT by Chris Dumez
Modified: 2021-07-21 12:46 PDT (History)
11 users (show)

See Also:


Attachments
Patch (5.05 KB, patch)
2021-07-19 19:04 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (6.38 KB, patch)
2021-07-20 09:37 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Chris Dumez 2021-07-19 18:59:34 PDT
r278702 broke the login page on appaloosa-store.com.
Comment 1 Chris Dumez 2021-07-19 18:59:46 PDT
<rdar://80596391>
Comment 2 Chris Dumez 2021-07-19 19:04:35 PDT
Created attachment 433843 [details]
Patch
Comment 3 Alex Christensen 2021-07-20 08:59:27 PDT
Comment on attachment 433843 [details]
Patch

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

> Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:358
> +        data.append(m_buffer->data(), m_buffer->size());

This could also call forEachSegment to have fewer copies.
Comment 4 Chris Dumez 2021-07-20 09:01:02 PDT
Comment on attachment 433843 [details]
Patch

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

>> Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:358
>> +        data.append(m_buffer->data(), m_buffer->size());
> 
> This could also call forEachSegment to have fewer copies.

Good idea. Will update.
Comment 5 Chris Dumez 2021-07-20 09:37:24 PDT
Created attachment 433878 [details]
Patch
Comment 6 EWS 2021-07-20 10:33:03 PDT
Committed r280085 (239810@main): <https://commits.webkit.org/239810@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 433878 [details].
Comment 7 Darin Adler 2021-07-21 12:03:27 PDT
Comment on attachment 433878 [details]
Patch

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

> Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:362
> +    if (buffer->hasOneRef())
> +        data = buffer->takeData(); // Avoid copying the data in the case where the buffer isn't shared.
> +    else {
> +        buffer->forEachSegment([&data](auto& span) {
> +            data.append(span);
> +        });
> +    }

If this pattern comes up again, perhaps we should consider a function with this logic? A safer "takeData" that will only do so when it’s singly owned, and would instead copy the data into a vector when it’s shared. The trick would be how to abstract the two different approaches, but I think it might be relevant. Here’s one possible implementation:

    Vector<uint8_t> extractData(Ref<SharedBuffer>&& buffer)
    {
        return buffer->hasOneRef() ? buffer->takeData() : buffer->copyData();
    }

And, since the forEachSegment/append optimization is important, we would move that optimization into SharedBuffer::copyData, unless there are some contexts where the current implementation of SharedBuffer::copyData is superior for some reason.
Comment 8 Chris Dumez 2021-07-21 12:05:35 PDT
(In reply to Darin Adler from comment #7)
> Comment on attachment 433878 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=433878&action=review
> 
> > Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:362
> > +    if (buffer->hasOneRef())
> > +        data = buffer->takeData(); // Avoid copying the data in the case where the buffer isn't shared.
> > +    else {
> > +        buffer->forEachSegment([&data](auto& span) {
> > +            data.append(span);
> > +        });
> > +    }
> 
> If this pattern comes up again, perhaps we should consider a function with
> this logic? A safer "takeData" that will only do so when it’s singly owned,
> and would instead copy the data into a vector when it’s shared. The trick
> would be how to abstract the two different approaches, but I think it might
> be relevant. Here’s one possible implementation:
> 
>     Vector<uint8_t> extractData(Ref<SharedBuffer>&& buffer)
>     {
>         return buffer->hasOneRef() ? buffer->takeData() : buffer->copyData();
>     }
> 
> And, since the forEachSegment/append optimization is important, we would
> move that optimization into SharedBuffer::copyData, unless there are some
> contexts where the current implementation of SharedBuffer::copyData is
> superior for some reason.

Yes, I think this is a good idea.
Now that I have experienced this bug, I actually think takeData() is too dangerous and we should just replace it with the safer alternative that copies when refCount is > 1.