RESOLVED FIXED 236454
Keep promise in scope when calling DeferredPromise::reject
https://bugs.webkit.org/show_bug.cgi?id=236454
Summary Keep promise in scope when calling DeferredPromise::reject
Gabriel Nava Marino
Reported 2022-02-10 10:46:12 PST
Attachments
Patch (1.74 KB, patch)
2022-02-10 10:47 PST, Gabriel Nava Marino
no flags
Patch (1.75 KB, patch)
2022-02-11 09:49 PST, Gabriel Nava Marino
no flags
Patch (1.68 KB, patch)
2022-02-14 10:58 PST, Gabriel Nava Marino
no flags
Patch (1.90 KB, patch)
2022-02-14 14:10 PST, Gabriel Nava Marino
no flags
Patch (2.30 KB, patch)
2022-02-17 13:32 PST, Gabriel Nava Marino
no flags
Gabriel Nava Marino
Comment 1 2022-02-10 10:47:52 PST
youenn fablet
Comment 2 2022-02-10 10:50:11 PST
Comment on attachment 451567 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=451567&action=review > Source/WebCore/ChangeLog:9 > + could go through a path that invokes GC on its owner and it. 'and it' is probably missing a word.
Gabriel Nava Marino
Comment 3 2022-02-10 14:23:48 PST
(In reply to youenn fablet from comment #2) > Comment on attachment 451567 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=451567&action=review > > > Source/WebCore/ChangeLog:9 > > + could go through a path that invokes GC on its owner and it. > > 'and it' is probably missing a word. Here, I am referring to the promise (i.e. "Keep promise in scope as ... invokes GC on its owner and it.")
Gabriel Nava Marino
Comment 4 2022-02-11 09:49:50 PST
EWS
Comment 5 2022-02-11 11:38:00 PST
Committed r289640 (247145@main): <https://commits.webkit.org/247145@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 451714 [details].
Darin Adler
Comment 6 2022-02-11 11:38:59 PST
Comment on attachment 451714 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=451714&action=review > Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp:135 > + Ref protectedThis(*this); This is not the correct fix given our overall approach to reference counting. The burden of protecting "this" is on the caller, not the reject function. I suppose that consistently protecting the wrapped object in every DOM function might be prohibitive, but we chose that approach a while back, and I am worried about mixing approaches.
Gabriel Nava Marino
Comment 7 2022-02-14 10:58:02 PST
(In reply to Darin Adler from comment #6) > Comment on attachment 451714 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=451714&action=review > > > Source/WebCore/bindings/js/JSDOMPromiseDeferred.cpp:135 > > + Ref protectedThis(*this); > > This is not the correct fix given our overall approach to reference > counting. The burden of protecting "this" is on the caller, not the reject > function. I suppose that consistently protecting the wrapped object in every > DOM function might be prohibitive, but we chose that approach a while back, > and I am worried about mixing approaches. Thank you for the context on the convention. I have updated the patch so that the caller protects the deferred promise.
Gabriel Nava Marino
Comment 8 2022-02-14 10:58:37 PST
Darin Adler
Comment 9 2022-02-14 11:18:20 PST
Comment on attachment 451924 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=451924&action=review > Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:274 > + Ref protectedPromise { promise }; Seems this doesn’t make sense. The "promise" captured is already protected, so this wouldn’t have any effect.
Gabriel Nava Marino
Comment 10 2022-02-14 11:26:34 PST
(In reply to Darin Adler from comment #9) > Comment on attachment 451924 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=451924&action=review > > > Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:274 > > + Ref protectedPromise { promise }; > > Seems this doesn’t make sense. The "promise" captured is already protected, > so this wouldn’t have any effect. The lambda owns the promise, but during execution, the lambda and its owner hierarchy (i.e. FetchBodyConsumer, FormDataConsumer, ...) are deallocated during garbage collection while calling DeferredPromise::reject. This can be see in the backtrace attached to the radar.
Darin Adler
Comment 11 2022-02-14 11:30:35 PST
Comment on attachment 451924 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=451924&action=review >>> Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:274 >>> + Ref protectedPromise { promise }; >> >> Seems this doesn’t make sense. The "promise" captured is already protected, so this wouldn’t have any effect. > > The lambda owns the promise, but during execution, the lambda and its owner hierarchy (i.e. FetchBodyConsumer, FormDataConsumer, ...) are deallocated during garbage collection while calling DeferredPromise::reject. > > This can be see in the backtrace attached to the radar. Given this maybe we should have a local variable at the top of the entire function: [..., capturedPromise = WTFMove(promise), ...] auto promise = WTFMove(capturedPromise); This might be a good idiom for situations like this, not just this one case.
Gabriel Nava Marino
Comment 12 2022-02-14 14:09:21 PST
(In reply to Darin Adler from comment #11) > Comment on attachment 451924 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=451924&action=review > > >>> Source/WebCore/Modules/fetch/FetchBodyConsumer.cpp:274 > >>> + Ref protectedPromise { promise }; > >> > >> Seems this doesn’t make sense. The "promise" captured is already protected, so this wouldn’t have any effect. > > > > The lambda owns the promise, but during execution, the lambda and its owner hierarchy (i.e. FetchBodyConsumer, FormDataConsumer, ...) are deallocated during garbage collection while calling DeferredPromise::reject. > > > > This can be see in the backtrace attached to the radar. > > Given this maybe we should have a local variable at the top of the entire > function: > > [..., capturedPromise = WTFMove(promise), ...] > > auto promise = WTFMove(capturedPromise); > > This might be a good idiom for situations like this, not just this one case. Thank you for the recommendation, I will update the patch and add this idiom to my notes to add in similar situations.
Gabriel Nava Marino
Comment 13 2022-02-14 14:10:20 PST
Gabriel Nava Marino
Comment 14 2022-02-16 12:55:31 PST
The updated patch is resulting in a crash that I am now investigating: stderr: ASSERTION FAILED: m_ptr /Volumes/Data/worker/macOS-AppleSilicon-Big-Sur-Debug-Build-EWS/build/WebKitBuild/Debug/usr/local/include/wtf/Ref.h(129) : T &WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise>>::leakRef() [T = WebCore::DeferredPromise, Traits = WTF::RawPtrTraits<WebCore::DeferredPromise>] 1 0x13db56258 WTFCrash 2 0x118b0a7b0 WebCore::JSDOMGlobalObject* JSC::jsCast<WebCore::JSDOMGlobalObject*, JSC::JSGlobalObject>(JSC::JSGlobalObject*) 3 0x11a3dfbe8 WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >::leakRef() 4 0x11a3dfb18 WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >::Ref(WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >&&) 5 0x118e01438 WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >::Ref(WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >&&) 6 0x11a672844 auto WebCore::FetchBodyConsumer::resolveWithFormData(WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >&&, WTF::String const&, WebCore::FormData const&, WebCore::ScriptExecutionContext*)::$_0::operator()<WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> > >(WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> >&&) 7 0x11a6726a8 WTF::Detail::CallableWrapper<WebCore::FetchBodyConsumer::resolveWithFormData(WTF::Ref<WebCore::DeferredPromise, WTF::RawPtrTraits<WebCore::DeferredPromise> >&&, WTF::String const&, WebCore::FormData const&, WebCore::ScriptExecutionContext*)::$_0, void, WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> > >::call(WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> >) 8 0x11a66bd6c WTF::Function<void (WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> >)>::operator()(WebCore::ExceptionOr<WTF::Span<unsigned char const, 18446744073709551615ul> >) const 9 0x11a66bf9c WebCore::FormDataConsumer::consume(WTF::Span<unsigned char const, 18446744073709551615ul>) 10 0x11a6960e4 auto WebCore::FormDataConsumer::consumeFile(WTF::String const&)::$_24::operator()()::'lambda'(auto&)::operator()<WebCore::ScriptExecutionContext>(auto&) const 11 0x11a695b94 WTF::Detail::CallableWrapper<WebCore::FormDataConsumer::consumeFile(WTF::String const&)::$_24::operator()()::'lambda'(auto&), void, WebCore::ScriptExecutionContext&>::call(WebCore::ScriptExecutionContext&) 12 0x11aec45e0 WTF::Function<void (WebCore::ScriptExecutionContext&)>::operator()(WebCore::ScriptExecutionContext&) const 13 0x11aeae160 WebCore::ScriptExecutionContext::Task::performTask(WebCore::ScriptExecutionContext&) 14 0x11de8dac8 WebCore::WorkerDedicatedRunLoop::Task::performTask(WebCore::WorkerOrWorkletGlobalScope*) 15 0x11de8cfd8 WebCore::WorkerDedicatedRunLoop::runInMode(WebCore::WorkerOrWorkletGlobalScope*, WebCore::ModePredicate const&) 16 0x11de8cc44 WebCore::WorkerDedicatedRunLoop::run(WebCore::WorkerOrWorkletGlobalScope*) 17 0x11de569b0 WebCore::WorkerOrWorkletThread::runEventLoop() 18 0x11df289ac WebCore::ServiceWorkerThread::runEventLoop() 19 0x11de56d28 WebCore::WorkerOrWorkletThread::workerOrWorkletThread() 20 0x11deaca14 WebCore::WorkerThread::createThread()::$_4::operator()() const 21 0x11deac990 WTF::Detail::CallableWrapper<WebCore::WorkerThread::createThread()::$_4, void>::call() 22 0x13db81018 WTF::Function<void ()>::operator()() const 23 0x13dc5c1e8 WTF::Thread::entryPoint(WTF::Thread::NewThreadContext*) 24 0x13dc6a860 WTF::wtfThreadEntryPoint(void*) 25 0x19a2db878 _pthread_start 26 0x19a2d65e0 thread_start LEAK: 1 WebPageProxy
Brady Eidson
Comment 15 2022-02-17 13:13:40 PST
(In reply to Gabriel Nava Marino from comment #14) > The updated patch is resulting in a crash that I am now investigating: I chatted with Garbiel about this on slack. This lambda is called more than once, so it's wrong to WTFMove the promise out unconditionally - It should only be moved out when it's needed for the call to reject()
Gabriel Nava Marino
Comment 16 2022-02-17 13:32:44 PST
Gabriel Nava Marino
Comment 17 2022-02-18 10:47:15 PST
Comment on attachment 452425 [details] Patch Moving to cq? as I noticed the iOS-wk2 test that failed is also having issues in at least one unrelated patch.
EWS
Comment 18 2022-02-18 12:28:38 PST
Committed r290152 (247491@main): <https://commits.webkit.org/247491@main> All reviewed patches have been landed. Closing bug and clearing flags on attachment 452425 [details].
Note You need to log in before you can comment on or make changes to this bug.