diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 0ef0e1c315b3b6..37af891db3258c 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -3518,6 +3518,11 @@ pub const FileReader = struct { if (this.nonblocking and this.file_type == .pipe) { this.file_type = .nonblocking_pipe; } + + // ensure non blocking otherwise hangs will occur + if (this.nonblocking) { + bun.ensureNonBlocking(fd.int()); + } } this.fd = fd; diff --git a/test/regression/issue/10080.test.ts b/test/regression/issue/10080.test.ts new file mode 100644 index 00000000000000..6613f2ecca7403 --- /dev/null +++ b/test/regression/issue/10080.test.ts @@ -0,0 +1,29 @@ +import { test, expect } from "bun:test"; +import { bunEnv, bunExe, isPosix } from "harness"; +import { tmpdir } from "os"; +import { join } from "path"; + +test.if(isPosix)("10080 - ensure nonblocking file descriptor is nonblocking in FileReader", async () => { + const expected = "foobar\n"; + const filename = join(tmpdir(), "bun.test.stream." + Date.now() + ".js"); + const contents = "for await (const line of console) {console.log(`foo${line}`)}" + await Bun.write(filename, contents); + const shellCommand = `exec &> >(${bunExe()} ${filename}); echo "bar"; while read -r line; do echo $line; done`; + + const proc = Bun.spawn(["bash", "-c", shellCommand], { + stdin: "inherit", + stdout: "pipe", + stderr: "inherit", + env: bunEnv, + }); + const { value }= await proc.stdout.getReader().read(); + const output = new TextDecoder().decode(value); + if (output !== expected) { + expect(output).toEqual(expected); + throw new Error("Output didn't match!\n"); + } + + proc.kill(9); + await proc.exited; + expect(proc.killed).toBeTrue(); +}, 1000);