diff --git a/src/bun.js/webcore/blob/read_file.zig b/src/bun.js/webcore/blob/read_file.zig index 55ac7d5d40b..c2b6e1bfe00 100644 --- a/src/bun.js/webcore/blob/read_file.zig +++ b/src/bun.js/webcore/blob/read_file.zig @@ -347,10 +347,7 @@ pub const ReadFile = struct { // read up to 4k at a time if // they didn't explicitly set a size and we're reading from something that's not a regular file } else if (stat.size == 0 and this.could_block) { - this.size = if (this.max_length == Blob.max_size) - 4096 - else - this.max_length; + this.size = @min(this.max_length, 4096); } if (this.offset > 0) { @@ -384,7 +381,7 @@ pub const ReadFile = struct { // add an extra 16 bytes to the buffer to avoid having to resize it for trailing extra data if (!this.could_block or (this.size > 0 and this.size != Blob.max_size)) - this.buffer = std.ArrayListUnmanaged(u8).initCapacity(bun.default_allocator, this.size + 16) catch |err| { + this.buffer = std.ArrayListUnmanaged(u8).initCapacity(bun.default_allocator, this.size +| 16) catch |err| { this.errno = err; this.onFinish(); return; @@ -669,10 +666,7 @@ pub const ReadFileUV = struct { } else if (stat.size == 0 and !this.is_regular_file) { // read up to 4k at a time if they didn't explicitly set a size and // we're reading from something that's not a regular file. - this.size = if (this.max_length == Blob.max_size) - 4096 - else - this.max_length; + this.size = @min(this.max_length, 4096); } if (this.offset > 0) { @@ -698,7 +692,7 @@ pub const ReadFileUV = struct { return; } // add an extra 16 bytes to the buffer to avoid having to resize it for trailing extra data - this.buffer.ensureTotalCapacityPrecise(this.byte_store.allocator, @min(this.size + 16, @as(usize, std.math.maxInt(bun.windows.ULONG)))) catch { + this.buffer.ensureTotalCapacityPrecise(this.byte_store.allocator, @min(this.size +| 16, @as(usize, std.math.maxInt(bun.windows.ULONG)))) catch { this.errno = error.OutOfMemory; this.system_error = bun.sys.Error.fromCode(bun.sys.E.NOMEM, .read).toSystemError(); this.onFinish(); diff --git a/test/js/bun/util/bun-stdin-slice.test.ts b/test/js/bun/util/bun-stdin-slice.test.ts new file mode 100644 index 00000000000..8fad44a3d09 --- /dev/null +++ b/test/js/bun/util/bun-stdin-slice.test.ts @@ -0,0 +1,42 @@ +import { expect, test } from "bun:test"; +import { bunEnv, bunExe, isWindows } from "harness"; + +// Reading a sliced non-regular file blob (like stdin from a pipe) with a size +// close to Blob.max_size used to overflow when computing the initial read +// buffer capacity. The overflow was only reachable on POSIX; on Windows the +// ReadFileUV path already bailed on size > ULONG_MAX before the addition. +test.skipIf(isWindows)("Bun.stdin.slice(1).text() does not crash when stdin is a pipe", async () => { + await using proc = Bun.spawn({ + cmd: [bunExe(), "-e", `process.stdout.write(await Bun.stdin.slice(1).text());`], + env: bunEnv, + stdin: "pipe", + stdout: "pipe", + stderr: "pipe", + }); + + proc.stdin.write("hello world"); + await proc.stdin.end(); + + const [stdout, exitCode] = await Promise.all([proc.stdout.text(), proc.exited]); + + expect(stdout).toBe("hello world"); + expect(exitCode).toBe(0); +}); + +test.skipIf(isWindows)("Bun.stdin.slice(0, N).text() caps reads at N bytes", async () => { + await using proc = Bun.spawn({ + cmd: [bunExe(), "-e", `process.stdout.write(await Bun.stdin.slice(0, 3).text());`], + env: bunEnv, + stdin: "pipe", + stdout: "pipe", + stderr: "pipe", + }); + + proc.stdin.write("0123456789"); + await proc.stdin.end(); + + const [stdout, exitCode] = await Promise.all([proc.stdout.text(), proc.exited]); + + expect(stdout).toBe("012"); + expect(exitCode).toBe(0); +});