1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-17 13:35:07 +00:00

LibWeb/Streams: Make ReadRequest GC-allocated

This allows it to keep its edges alive. Fixes an intermittent crash seen
by UBSAN on CI. :^)
This commit is contained in:
Andreas Kling 2023-08-09 18:17:19 +02:00
parent 40bdcdf966
commit 9c3e9e8981
6 changed files with 37 additions and 14 deletions

View file

@ -320,7 +320,7 @@ void readable_stream_error(ReadableStream& stream, JS::Value error)
} }
// https://streams.spec.whatwg.org/#readable-stream-add-read-request // https://streams.spec.whatwg.org/#readable-stream-add-read-request
void readable_stream_add_read_request(ReadableStream& stream, ReadRequest const& read_request) void readable_stream_add_read_request(ReadableStream& stream, ReadRequest& read_request)
{ {
// 1. Assert: stream.[[reader]] implements ReadableStreamDefaultReader. // 1. Assert: stream.[[reader]] implements ReadableStreamDefaultReader.
VERIFY(stream.reader().has_value() && stream.reader()->has<JS::NonnullGCPtr<ReadableStreamDefaultReader>>()); VERIFY(stream.reader().has_value() && stream.reader()->has<JS::NonnullGCPtr<ReadableStreamDefaultReader>>());
@ -1032,7 +1032,7 @@ void readable_byte_stream_controller_error(ReadableByteStreamController& control
} }
// https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue // https://streams.spec.whatwg.org/#abstract-opdef-readablebytestreamcontrollerfillreadrequestfromqueue
WebIDL::ExceptionOr<void> readable_byte_stream_controller_fill_read_request_from_queue(ReadableByteStreamController& controller, NonnullRefPtr<ReadRequest> read_request) WebIDL::ExceptionOr<void> readable_byte_stream_controller_fill_read_request_from_queue(ReadableByteStreamController& controller, JS::NonnullGCPtr<ReadRequest> read_request)
{ {
auto& vm = controller.vm(); auto& vm = controller.vm();
auto& realm = controller.realm(); auto& realm = controller.realm();

View file

@ -37,7 +37,7 @@ WebIDL::ExceptionOr<double> extract_high_water_mark(QueuingStrategy const&, doub
void readable_stream_close(ReadableStream&); void readable_stream_close(ReadableStream&);
void readable_stream_error(ReadableStream&, JS::Value error); void readable_stream_error(ReadableStream&, JS::Value error);
void readable_stream_add_read_request(ReadableStream&, ReadRequest const&); void readable_stream_add_read_request(ReadableStream&, ReadRequest&);
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> readable_stream_cancel(ReadableStream&, JS::Value reason); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> readable_stream_cancel(ReadableStream&, JS::Value reason);
void readable_stream_fulfill_read_request(ReadableStream&, JS::Value chunk, bool done); void readable_stream_fulfill_read_request(ReadableStream&, JS::Value chunk, bool done);
size_t readable_stream_get_num_read_into_requests(ReadableStream const&); size_t readable_stream_get_num_read_into_requests(ReadableStream const&);
@ -84,7 +84,7 @@ void readable_byte_stream_controller_clear_algorithms(ReadableByteStreamControll
void readable_byte_stream_controller_clear_pending_pull_intos(ReadableByteStreamController&); void readable_byte_stream_controller_clear_pending_pull_intos(ReadableByteStreamController&);
WebIDL::ExceptionOr<void> readable_byte_stream_controller_close(ReadableByteStreamController&); WebIDL::ExceptionOr<void> readable_byte_stream_controller_close(ReadableByteStreamController&);
void readable_byte_stream_controller_error(ReadableByteStreamController&, JS::Value error); void readable_byte_stream_controller_error(ReadableByteStreamController&, JS::Value error);
WebIDL::ExceptionOr<void> readable_byte_stream_controller_fill_read_request_from_queue(ReadableByteStreamController&, NonnullRefPtr<ReadRequest>); WebIDL::ExceptionOr<void> readable_byte_stream_controller_fill_read_request_from_queue(ReadableByteStreamController&, JS::NonnullGCPtr<ReadRequest>);
Optional<double> readable_byte_stream_controller_get_desired_size(ReadableByteStreamController const&); Optional<double> readable_byte_stream_controller_get_desired_size(ReadableByteStreamController const&);
WebIDL::ExceptionOr<void> readable_byte_stream_controller_handle_queue_drain(ReadableByteStreamController&); WebIDL::ExceptionOr<void> readable_byte_stream_controller_handle_queue_drain(ReadableByteStreamController&);
void readable_byte_stream_controller_invalidate_byob_request(ReadableByteStreamController&); void readable_byte_stream_controller_invalidate_byob_request(ReadableByteStreamController&);

View file

@ -69,7 +69,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> ReadableByteStreamControl
} }
// https://streams.spec.whatwg.org/#rbs-controller-private-pull // https://streams.spec.whatwg.org/#rbs-controller-private-pull
WebIDL::ExceptionOr<void> ReadableByteStreamController::pull_steps(NonnullRefPtr<ReadRequest> read_request) WebIDL::ExceptionOr<void> ReadableByteStreamController::pull_steps(JS::NonnullGCPtr<ReadRequest> read_request)
{ {
auto& vm = this->vm(); auto& vm = this->vm();
auto& realm = this->realm(); auto& realm = this->realm();
@ -86,7 +86,6 @@ WebIDL::ExceptionOr<void> ReadableByteStreamController::pull_steps(NonnullRefPtr
// 2. Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest). // 2. Perform ! ReadableByteStreamControllerFillReadRequestFromQueue(this, readRequest).
TRY(readable_byte_stream_controller_fill_read_request_from_queue(*this, read_request)); TRY(readable_byte_stream_controller_fill_read_request_from_queue(*this, read_request));
// 3. Return. // 3. Return.
return {}; return {};
} }

View file

@ -119,7 +119,7 @@ public:
void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; } void set_stream(JS::GCPtr<ReadableStream> stream) { m_stream = stream; }
WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> cancel_steps(JS::Value reason); WebIDL::ExceptionOr<JS::NonnullGCPtr<WebIDL::Promise>> cancel_steps(JS::Value reason);
WebIDL::ExceptionOr<void> pull_steps(NonnullRefPtr<ReadRequest>); WebIDL::ExceptionOr<void> pull_steps(JS::NonnullGCPtr<ReadRequest>);
WebIDL::ExceptionOr<void> release_steps(); WebIDL::ExceptionOr<void> release_steps();
private: private:

View file

@ -23,6 +23,13 @@
namespace Web::Streams { namespace Web::Streams {
void ReadLoopReadRequest::visit_edges(Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_realm);
visitor.visit(m_reader);
}
// https://streams.spec.whatwg.org/#default-reader-constructor // https://streams.spec.whatwg.org/#default-reader-constructor
WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStreamDefaultReader>> ReadableStreamDefaultReader::construct_impl(JS::Realm& realm, JS::NonnullGCPtr<ReadableStream> stream) WebIDL::ExceptionOr<JS::NonnullGCPtr<ReadableStreamDefaultReader>> ReadableStreamDefaultReader::construct_impl(JS::Realm& realm, JS::NonnullGCPtr<ReadableStream> stream)
{ {
@ -50,6 +57,8 @@ void ReadableStreamDefaultReader::visit_edges(Cell::Visitor& visitor)
{ {
Base::visit_edges(visitor); Base::visit_edges(visitor);
ReadableStreamGenericReaderMixin::visit_edges(visitor); ReadableStreamGenericReaderMixin::visit_edges(visitor);
for (auto& request : m_read_requests)
visitor.visit(request);
} }
// https://streams.spec.whatwg.org/#read-loop // https://streams.spec.whatwg.org/#read-loop
@ -108,7 +117,9 @@ void ReadLoopReadRequest::on_error(JS::Value error)
m_failure_steps(error); m_failure_steps(error);
} }
class DefaultReaderReadRequest : public ReadRequest { class DefaultReaderReadRequest final : public ReadRequest {
JS_CELL(DefaultReaderReadRequest, Cell);
public: public:
DefaultReaderReadRequest(JS::Realm& realm, WebIDL::Promise& promise) DefaultReaderReadRequest(JS::Realm& realm, WebIDL::Promise& promise)
: m_realm(realm) : m_realm(realm)
@ -132,6 +143,13 @@ public:
} }
private: private:
virtual void visit_edges(Visitor& visitor) override
{
Base::visit_edges(visitor);
visitor.visit(m_realm);
visitor.visit(m_promise);
}
JS::Realm& m_realm; JS::Realm& m_realm;
WebIDL::Promise& m_promise; WebIDL::Promise& m_promise;
}; };
@ -158,7 +176,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<JS::Promise>> ReadableStreamDefaultReader::
// Resolve promise with «[ "value" → undefined, "done" → true ]». // Resolve promise with «[ "value" → undefined, "done" → true ]».
// error steps, given e // error steps, given e
// Reject promise with e. // Reject promise with e.
auto read_request = adopt_ref(*new DefaultReaderReadRequest(realm, promise_capability)); auto read_request = heap().allocate_without_realm<DefaultReaderReadRequest>(realm, promise_capability);
// 4. Perform ! ReadableStreamDefaultReaderRead(this, readRequest). // 4. Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
TRY(readable_stream_default_reader_read(*this, read_request)); TRY(readable_stream_default_reader_read(*this, read_request));
@ -175,7 +193,7 @@ WebIDL::ExceptionOr<void> ReadableStreamDefaultReader::read_all_bytes(ReadLoopRe
// 1. Let readRequest be a new read request with the following items: // 1. Let readRequest be a new read request with the following items:
// NOTE: items and steps in ReadLoopReadRequest. // NOTE: items and steps in ReadLoopReadRequest.
auto read_request = adopt_ref(*new ReadLoopReadRequest(vm, realm, *this, move(success_steps), move(failure_steps))); auto read_request = heap().allocate_without_realm<ReadLoopReadRequest>(vm, realm, *this, move(success_steps), move(failure_steps));
// 2. Perform ! ReadableStreamDefaultReaderRead(this, readRequest). // 2. Perform ! ReadableStreamDefaultReaderRead(this, readRequest).
TRY(readable_stream_default_reader_read(*this, read_request)); TRY(readable_stream_default_reader_read(*this, read_request));

View file

@ -20,7 +20,9 @@ struct ReadableStreamReadResult {
bool done; bool done;
}; };
class ReadRequest : public RefCounted<ReadRequest> { class ReadRequest : public JS::Cell {
JS_CELL(ReadRequest, JS::Cell);
public: public:
virtual ~ReadRequest() = default; virtual ~ReadRequest() = default;
@ -29,7 +31,9 @@ public:
virtual void on_error(JS::Value error) = 0; virtual void on_error(JS::Value error) = 0;
}; };
class ReadLoopReadRequest : public ReadRequest { class ReadLoopReadRequest final : public ReadRequest {
JS_CELL(ReadLoopReadRequest, JS::Cell);
public: public:
// successSteps, which is an algorithm accepting a byte sequence // successSteps, which is an algorithm accepting a byte sequence
using SuccessSteps = JS::SafeFunction<void(ByteBuffer)>; using SuccessSteps = JS::SafeFunction<void(ByteBuffer)>;
@ -46,6 +50,8 @@ public:
virtual void on_error(JS::Value error) override; virtual void on_error(JS::Value error) override;
private: private:
virtual void visit_edges(Visitor&) override;
JS::VM& m_vm; JS::VM& m_vm;
JS::Realm& m_realm; JS::Realm& m_realm;
ReadableStreamDefaultReader& m_reader; ReadableStreamDefaultReader& m_reader;
@ -72,7 +78,7 @@ public:
WebIDL::ExceptionOr<void> release_lock(); WebIDL::ExceptionOr<void> release_lock();
SinglyLinkedList<NonnullRefPtr<ReadRequest>>& read_requests() { return m_read_requests; } SinglyLinkedList<JS::NonnullGCPtr<ReadRequest>>& read_requests() { return m_read_requests; }
private: private:
explicit ReadableStreamDefaultReader(JS::Realm&); explicit ReadableStreamDefaultReader(JS::Realm&);
@ -81,7 +87,7 @@ private:
virtual void visit_edges(Cell::Visitor&) override; virtual void visit_edges(Cell::Visitor&) override;
SinglyLinkedList<NonnullRefPtr<ReadRequest>> m_read_requests; SinglyLinkedList<JS::NonnullGCPtr<ReadRequest>> m_read_requests;
}; };
} }