mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-11-01 08:48:25 +02:00
Bug 1941210 - Strongly grab FetchStreamReader while waiting for writing r=smaug
Nothing strongly grabs ReadableStream nor FetchStreamReader while waiting for nsIAsyncOutputStream to respond. mAsyncWaitReader should now strongly grab the reader until the output stream responds. Differential Revision: https://phabricator.services.mozilla.com/D234031
This commit is contained in:
parent
f51f04f6e1
commit
b9af86bfb4
3 changed files with 35 additions and 1 deletions
|
|
@ -72,9 +72,17 @@ nsresult OutputStreamHolder::AsyncWait(uint32_t aFlags,
|
||||||
uint32_t aRequestedCount,
|
uint32_t aRequestedCount,
|
||||||
nsIEventTarget* aEventTarget) {
|
nsIEventTarget* aEventTarget) {
|
||||||
mAsyncWaitWorkerRef = mWorkerRef;
|
mAsyncWaitWorkerRef = mWorkerRef;
|
||||||
|
// Grab the strong reference for the reader but only when we are waiting for
|
||||||
|
// the output stream, because it means we still have things to write.
|
||||||
|
// (WAIT_CLOSURE_ONLY happens when waiting for ReadableStream to respond, at
|
||||||
|
// which point the pull callback should get an indirect strong reference via
|
||||||
|
// the controller argument.)
|
||||||
|
mAsyncWaitReader =
|
||||||
|
aFlags == nsIAsyncOutputStream::WAIT_CLOSURE_ONLY ? nullptr : mReader;
|
||||||
nsresult rv = mOutput->AsyncWait(this, aFlags, aRequestedCount, aEventTarget);
|
nsresult rv = mOutput->AsyncWait(this, aFlags, aRequestedCount, aEventTarget);
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
mAsyncWaitWorkerRef = nullptr;
|
mAsyncWaitWorkerRef = nullptr;
|
||||||
|
mAsyncWaitReader = nullptr;
|
||||||
}
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
@ -84,10 +92,16 @@ NS_IMETHODIMP OutputStreamHolder::OnOutputStreamReady(
|
||||||
// We may get called back after ::Shutdown()
|
// We may get called back after ::Shutdown()
|
||||||
if (!mReader) {
|
if (!mReader) {
|
||||||
mAsyncWaitWorkerRef = nullptr;
|
mAsyncWaitWorkerRef = nullptr;
|
||||||
|
MOZ_ASSERT(!mAsyncWaitReader);
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
if (!mReader->OnOutputStreamReady()) {
|
|
||||||
|
// mAsyncWaitReader may be reset during OnOutputStreamReady, make sure to let
|
||||||
|
// it live during the call
|
||||||
|
RefPtr<FetchStreamReader> reader = mReader.get();
|
||||||
|
if (!reader->OnOutputStreamReady()) {
|
||||||
mAsyncWaitWorkerRef = nullptr;
|
mAsyncWaitWorkerRef = nullptr;
|
||||||
|
mAsyncWaitReader = nullptr;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@ class OutputStreamHolder final : public nsIOutputStreamCallback {
|
||||||
private:
|
private:
|
||||||
~OutputStreamHolder();
|
~OutputStreamHolder();
|
||||||
|
|
||||||
|
RefPtr<FetchStreamReader> mAsyncWaitReader;
|
||||||
// WeakPtr to avoid cycles
|
// WeakPtr to avoid cycles
|
||||||
WeakPtr<FetchStreamReader> mReader;
|
WeakPtr<FetchStreamReader> mReader;
|
||||||
// To ensure the worker sticks around
|
// To ensure the worker sticks around
|
||||||
|
|
|
||||||
19
testing/web-platform/tests/fetch/api/basic/gc.any.js
Normal file
19
testing/web-platform/tests/fetch/api/basic/gc.any.js
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
// META: global=window,worker
|
||||||
|
// META: script=/common/gc.js
|
||||||
|
|
||||||
|
promise_test(async () => {
|
||||||
|
let i = 0;
|
||||||
|
const repeat = 5;
|
||||||
|
const buffer = await new Response(new ReadableStream({
|
||||||
|
pull(c) {
|
||||||
|
if (i >= repeat) {
|
||||||
|
c.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
++i;
|
||||||
|
c.enqueue(new Uint8Array([0]))
|
||||||
|
garbageCollect();
|
||||||
|
}
|
||||||
|
})).arrayBuffer();
|
||||||
|
assert_equals(buffer.byteLength, repeat, `The buffer should be ${repeat}-byte long`);
|
||||||
|
}, "GC/CC should not abruptly close the stream while being consumed by Response");
|
||||||
Loading…
Reference in a new issue