[whatwg/streams] Abort followed by write on WritableStream may invoke a null strategy algorithm (Issue #1331)

### What is the issue with the Streams Standard?

Consider the following test (simplification of https://github.com/web-platform-tests/wpt/blob/8686b7a6d288d3b2c22b5ddb5a21773619b22b85/streams/writable-streams/aborting.any.js#L57)

```html
<script>

async function test() {
  const ws = new WritableStream();

  setTimeout(() => {
      const writer = ws.getWriter();
      const abortPromise = writer.abort("some error");
      writer.write(1);
  }, 0)
}

test();
</script>
```

The stack of calls from  [abort(reason)](https://streams.spec.whatwg.org/#default-writer-abort) are:

1.  [WritableStreamDefaultWriterAbort](https://streams.spec.whatwg.org/#writable-stream-default-writer-abort)
2.  [WritableStreamAbort](https://streams.spec.whatwg.org/#writable-stream-abort)
3. [WritableStreamStartErroring](https://streams.spec.whatwg.org/#writable-stream-start-erroring)
4. [WritableStreamFinishErroring](https://streams.spec.whatwg.org/#writable-stream-finish-erroring)

Step 12 of this WritableStreamFinishErroring will then perform:

> 12. Let promise be ! stream.[[[controller]]](https://streams.spec.whatwg.org/#writablestream-controller).[[[AbortSteps]]](https://streams.spec.whatwg.org/#abstract-opdef-writablestreamcontroller-abortsteps)(abortRequest’s [reason](https://streams.spec.whatwg.org/#pending-abort-request-reason)).

Where [\[AbortSteps\](reason)](https://streams.spec.whatwg.org/#ws-default-controller-private-abort) will clear the write algorithms:

> 2. Perform ! [WritableStreamDefaultControllerClearAlgorithms](https://streams.spec.whatwg.org/#writable-stream-default-controller-clear-algorithms)([this](https://webidl.spec.whatwg.org/#this)).

Which includes the `strategySizeAlgorithm`:

> 4. Set controller.[[[strategySizeAlgorithm]]](https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-strategysizealgorithm) to undefined.

Once abort has finished, [writer.write(chunk)](https://streams.spec.whatwg.org/#default-writer-write) is invoked.

In [WritableStreamDefaultWriterWrite](https://streams.spec.whatwg.org/#writable-stream-default-writer-write) step 4 is to:

> 4. Let chunkSize be ! [WritableStreamDefaultControllerGetChunkSize](https://streams.spec.whatwg.org/#writable-stream-default-controller-get-chunk-size)(controller, chunk).

Which will invoke the strategySizeAlgorithm:

> 1. Let returnValue be the result of performing controller.[[[strategySizeAlgorithm]]](https://streams.spec.whatwg.org/#writablestreamdefaultcontroller-strategysizealgorithm), passing in chunk, and interpreting the result as a [completion record](https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html#sec-completion-record-specification-type).

However, this has been nulled out by the call to WritableStreamDefaultControllerClearAlgorithms earlier, as part of the `abort`.

The stream is in an errored state, and _should_ through an abort, but this is only performed on step 9 of WritableStreamDefaultWriterWrite.

Speculatively, I think step 4. of `WritableStreamDefaultWriterWrite` could be moved to just after step 9 where the erroring status is checked, but I am not sure if that has unintended side effects.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/streams/issues/1331
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/streams/issues/1331@github.com>

Received on Saturday, 9 November 2024 11:11:15 UTC