Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assertion failure in ext/web/06_streams.js when stream[_state] === 'closed' #22621

Open
cscheid opened this issue Feb 28, 2024 · 1 comment
Open

Comments

@cscheid
Copy link

cscheid commented Feb 28, 2024

Version: Deno 1.41.0

Repro:

deno_repro.ts

async function processOutput(iterator: AsyncIterable<Uint8Array>): Promise<string> {
  const decoder = new TextDecoder();
  let outputText = "";
  for await (const chunk of iterator) {
    const text = decoder.decode(chunk);
    outputText += text;
  }
  return outputText;
}

async function* iteratorFromStream(stream: ReadableStream<Uint8Array>) {
  const reader = stream.getReader();
  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) return;
      yield value;
    }
  } finally {
    reader.releaseLock();
  }
}

const command = new Deno.Command("ls", {stdout: "piped", stderr: "piped"});
const process = command.spawn();

const promises: Promise<unknown>[] = [
  processOutput(iteratorFromStream(process.stdout)),
  processOutput(iteratorFromStream(process.stderr)),
];

await Promise.all(promises);

// assertion fails here
const status = await process.output();

Now run:

$ deno run --allow-all deno_repro.ts
error: Uncaught (in promise) AssertionError: Assertion failed.
const status = await process.output();
               ^
    at assert (ext:deno_web/00_infra.js:374:11)
    at readableStreamError (ext:deno_web/06_streams.js:2533:3)
    at readableStreamCollectIntoUint8Array (ext:deno_web/06_streams.js:1085:7)
    at eventLoopTick (ext:core/01_core.js:166:7)
    at async Promise.all (index 1)
    at async ChildProcess.output (ext:runtime/40_process.js:322:49)
    at async file:///Users/cscheid/Desktop/daily-log/2024/02/28/deno_repro.ts:35:16

Adding some debug print statements around (ext:deno_web/06_streams.js:2533:3) shows that at the point that readableStreamError(stream, err) is called, this stream actually is closed, failing the assertion assert(stream[_state] === "readable"); in line 2533.

The error object err is as follows, although I don't understand why we end with a bad resource ID:

BadResource: Bad resource ID
    at readableStreamCollectIntoUint8Array (ext:deno_web/06_streams.js:1069:23)
    at collectOutput (ext:runtime/40_process.js:221:10)
    at ChildProcess.output (ext:runtime/40_process.js:324:7)
    at file:///Users/cscheid/Desktop/daily-log/2024/02/28/deno_repro.ts:35:30
    at eventLoopTick (ext:core/01_core.js:166:7) {
  name: "BadResource"
}

The ls process does appear to run, and the stdout and stderr strings look correct.

@cscheid
Copy link
Author

cscheid commented Feb 28, 2024

The problem seems to happen when op_read_all is called with a resourceBacking.rid === 4. In the repro above, that path is called twice, once with resourceBacking.rid === 3 and once with resourceBacking.rid === 4. The latter is presumably a bad resource ID, which causes op_read_all to throw in a manner that's unexpected by the exception handler.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant