Skip to content

Commit a0c5f3d

Browse files
robobunClaude Botclaude
authored
fix(mmap): use coerceToInt64 for offset/size to prevent assertion failure (#25101)
## Summary - Fix assertion failure in `Bun.mmap` when `offset` or `size` options are non-numeric values - Add validation to reject negative `offset`/`size` with clear error messages Minimal reproduction: `Bun.mmap("", { offset: null });` ## Root Cause `Bun.mmap` was calling `toInt64()` directly on the `offset` and `size` options without validating they are numbers first. `toInt64()` has an assertion that the value must be a number or BigInt, which fails when non-numeric values like `null` or functions are passed. ## Test plan - [x] Added tests for negative offset/size rejection - [x] Added tests for non-number inputs (null, undefined) - [x] `bun bd test test/js/bun/util/mmap.test.js` passes Closes ENG-22413 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Bot <[email protected]> Co-authored-by: Claude <[email protected]>
1 parent 5965ff1 commit a0c5f3d

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

src/bun.js/api/BunObject.zig

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,11 +1212,19 @@ pub fn mmapFile(globalThis: *jsc.JSGlobalObject, callframe: *jsc.CallFrame) bun.
12121212
}
12131213

12141214
if (try opts.get(globalThis, "size")) |value| {
1215-
map_size = @as(usize, @intCast(value.toInt64()));
1215+
const size_value = try value.coerceToInt64(globalThis);
1216+
if (size_value < 0) {
1217+
return globalThis.throwInvalidArguments("size must be a non-negative integer", .{});
1218+
}
1219+
map_size = @intCast(size_value);
12161220
}
12171221

12181222
if (try opts.get(globalThis, "offset")) |value| {
1219-
offset = @as(usize, @intCast(value.toInt64()));
1223+
const offset_value = try value.coerceToInt64(globalThis);
1224+
if (offset_value < 0) {
1225+
return globalThis.throwInvalidArguments("offset must be a non-negative integer", .{});
1226+
}
1227+
offset = @intCast(offset_value);
12201228
offset = std.mem.alignBackwardAnyAlign(usize, offset, std.heap.pageSize());
12211229
}
12221230
}

test/js/bun/util/mmap.test.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,32 @@ describe.skipIf(isWindows)("Bun.mmap", async () => {
6868
expect(map[0]).toBe(old);
6969
await gcTick();
7070
});
71+
72+
it("mmap rejects negative offset", () => {
73+
expect(() => Bun.mmap(path, { offset: -1 })).toThrow("offset must be a non-negative integer");
74+
});
75+
76+
it("mmap rejects negative size", () => {
77+
expect(() => Bun.mmap(path, { size: -1 })).toThrow("size must be a non-negative integer");
78+
});
79+
80+
it("mmap handles non-number offset/size without crashing", () => {
81+
// These should not crash - non-number values coerce to 0 per JavaScript semantics
82+
// Previously these caused assertion failures (issue ENG-22413)
83+
84+
// null coerces to 0, which is valid for offset
85+
expect(() => {
86+
Bun.mmap(path, { offset: null });
87+
}).not.toThrow();
88+
89+
// size: null coerces to 0, which is invalid (EINVAL), but shouldn't crash
90+
expect(() => {
91+
Bun.mmap(path, { size: null });
92+
}).toThrow("EINVAL");
93+
94+
// undefined is ignored (property not set)
95+
expect(() => {
96+
Bun.mmap(path, { offset: undefined });
97+
}).not.toThrow();
98+
});
7199
});

0 commit comments

Comments
 (0)