From 6037af712e6fb2760cb89ce67834973e9b0bdaa3 Mon Sep 17 00:00:00 2001 From: robobun Date: Tue, 14 Apr 2026 03:13:06 +0000 Subject: [PATCH 1/2] Fix integer overflow when reading a sliced non-regular file Blob MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bun.file("/dev/null").slice(1).arrayBuffer() would panic in debug builds. Slicing a file Blob with unknown size yields a Blob with size close to Blob.max_size. For non-regular files with stat.size == 0, ReadFile used this value directly as the initial buffer capacity, and `size + 16` overflowed u52. Cap the initial buffer size for non-regular files to 4k (same as the unsliced case — the read loop grows the buffer via its 64KB stack buffer as needed), and use saturating add for defense in depth. --- src/bun.js/webcore/blob/read_file.zig | 12 +++--------- test/js/bun/util/bun-file-read.test.ts | 27 ++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/bun.js/webcore/blob/read_file.zig b/src/bun.js/webcore/blob/read_file.zig index 55ac7d5d40b..0da3918d8e3 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) { diff --git a/test/js/bun/util/bun-file-read.test.ts b/test/js/bun/util/bun-file-read.test.ts index fd8bca82ac3..d06b91fce33 100644 --- a/test/js/bun/util/bun-file-read.test.ts +++ b/test/js/bun/util/bun-file-read.test.ts @@ -1,5 +1,6 @@ import { expect, it } from "bun:test"; import { tmpdir } from "node:os"; +import { bunEnv, bunExe, isPosix } from "harness"; it("offset should work in Bun.file() #4963", async () => { const filename = tmpdir() + "/bun.test.offset.txt"; @@ -9,3 +10,29 @@ it("offset should work in Bun.file() #4963", async () => { const contents = await slice.text(); expect(contents).toBe("ntents"); }); + +it.skipIf(!isPosix)("reading a sliced non-regular file Blob does not overflow the initial buffer size", async () => { + // .slice(1) on a file Blob whose size is unknown (max_size) yields a Blob with + // size = max_size - 1. For a non-regular file (char device), this was used as + // the initial buffer capacity and `size + 16` overflowed u52. + await using proc = Bun.spawn({ + cmd: [ + bunExe(), + "-e", + ` + const a = await Bun.file("/dev/null").slice(1).arrayBuffer(); + if (a.byteLength !== 0) throw new Error("expected 0, got " + a.byteLength); + const b = await Bun.file("/dev/zero").slice(0, 100).arrayBuffer(); + if (b.byteLength !== 100) throw new Error("expected 100, got " + b.byteLength); + console.log("ok"); + `, + ], + env: bunEnv, + stdout: "pipe", + stderr: "pipe", + }); + + const [stdout, , exitCode] = await Promise.all([proc.stdout.text(), proc.stderr.text(), proc.exited]); + + expect({ stdout: stdout.trim(), exitCode }).toEqual({ stdout: "ok", exitCode: 0 }); +}); From 116b50da1fa8cb2bd98b7c9836e10fbb73d0a138 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Tue, 14 Apr 2026 03:15:17 +0000 Subject: [PATCH 2/2] [autofix.ci] apply automated fixes --- test/js/bun/util/bun-file-read.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/js/bun/util/bun-file-read.test.ts b/test/js/bun/util/bun-file-read.test.ts index d06b91fce33..001b6d8f311 100644 --- a/test/js/bun/util/bun-file-read.test.ts +++ b/test/js/bun/util/bun-file-read.test.ts @@ -1,6 +1,6 @@ import { expect, it } from "bun:test"; -import { tmpdir } from "node:os"; import { bunEnv, bunExe, isPosix } from "harness"; +import { tmpdir } from "node:os"; it("offset should work in Bun.file() #4963", async () => { const filename = tmpdir() + "/bun.test.offset.txt";