diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index a142b9919fb16e..aaf5d5a50a6513 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -3529,7 +3529,7 @@ pub const FileReader = struct { this.file_type = .nonblocking_pipe; } - this.nonblocking = is_nonblocking_tty or (this.pollable and !(file.is_atty orelse false)); + this.nonblocking = is_nonblocking_tty or bun.isNonBlocking(fd.int()); if (this.nonblocking and this.file_type == .pipe) { this.file_type = .nonblocking_pipe; diff --git a/src/bun.zig b/src/bun.zig index 536512da2a8e36..60a8ccfb7fc652 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -515,6 +515,10 @@ pub fn ensureNonBlocking(fd: anytype) void { _ = std.os.fcntl(fd, std.os.F.SETFL, current | std.os.O.NONBLOCK) catch 0; } +pub fn isNonBlocking(fd: anytype) bool { + return (std.os.fcntl(fd, std.os.F.GETFL, 0) catch 0 & std.os.O.NONBLOCK) == std.os.O.NONBLOCK; +} + const global_scope_log = sys.syslog; pub fn isReadable(fd: FileDescriptor) PollFlag { if (comptime Environment.isWindows) { diff --git a/test/regression/issue/10080.test.ts b/test/regression/issue/10080.test.ts new file mode 100644 index 00000000000000..7f92b68308d235 --- /dev/null +++ b/test/regression/issue/10080.test.ts @@ -0,0 +1,33 @@ +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 blocking stdio is treated as such 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, +);