Files
bun.sh/test/js/bun/resolve/toml/toml.test.js
robobun 1344151576 fix(json): prevent stack overflow in JSONC parser on deeply nested input (#26174)
## Summary
- Add stack overflow protection to JSON/JSONC parser to prevent
segmentation faults
- Parser now throws `RangeError: Maximum call stack size exceeded`
instead of crashing
- Fixes DoS vulnerability when parsing deeply nested JSON structures
(~150k+ depth)

## Test plan
- [x] Added regression tests for deeply nested arrays and objects (25k
depth)
- [x] Verified system Bun v1.3.6 crashes with segfault at 150k depth
- [x] Verified fix throws proper error instead of crashing
- [x] All existing JSONC tests pass

🤖 Generated with [Claude Code](https://claude.ai/code)

---------

Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 16:23:01 -08:00

112 lines
2.9 KiB
JavaScript

import { expect, it } from "bun:test";
import emptyToml from "./toml-empty.toml";
import tomlFromCustomTypeAttribute from "./toml-fixture.toml.txt" with { type: "toml" };
function checkToml(toml) {
expect(toml.framework).toBe("next");
expect(toml.bundle.packages["@emotion/react"]).toBe(true);
expect(toml.array[0].entry_one).toBe("one");
expect(toml.array[0].entry_two).toBe("two");
expect(toml.array[1].entry_one).toBe("three");
expect(toml.array[1].entry_two).toBe(undefined);
expect(toml.array[1].nested[0].entry_one).toBe("four");
expect(toml.dev.one.two.three).toBe(4);
expect(toml.dev.foo).toBe(123);
expect(toml.inline.array[0]).toBe(1234);
expect(toml.inline.array[1]).toBe(4);
expect(toml.dev["foo.bar"]).toBe("baz");
expect(toml.install.scopes["@mybigcompany"].url).toBe("https://registry.mybigcompany.com");
expect(toml.install.scopes["@mybigcompany2"].url).toBe("https://registry.mybigcompany.com");
expect(toml.install.scopes["@mybigcompany3"].three).toBe(4);
expect(toml.install.cache.dir).toBe("C:\\Windows\\System32");
expect(toml.install.cache.dir2).toBe("C:\\Windows\\System32\\🏳️‍🌈");
}
it("via dynamic import", async () => {
const toml = (await import("./toml-fixture.toml")).default;
checkToml(toml);
});
it("via import type toml", async () => {
checkToml(tomlFromCustomTypeAttribute);
});
it("via dynamic import with type attribute", async () => {
delete require.cache[require.resolve("./toml-fixture.toml.txt")];
const toml = (await import("./toml-fixture.toml.txt", { with: { type: "toml" } })).default;
checkToml(toml);
});
it("empty via import statement", () => {
expect(emptyToml).toEqual({});
});
it("inline table followed by table array", () => {
const tomlContent = `
[global]
inline_table = { q1 = 1 }
[[items]]
q1 = 1
q2 = 2
[[items]]
q1 = 3
q2 = 4
`;
// Test via Bun's internal TOML parser
const Bun = globalThis.Bun;
const parsed = Bun.TOML.parse(tomlContent);
expect(parsed.global).toEqual({
inline_table: { q1: 1 },
});
expect(parsed.items).toEqual([
{ q1: 1, q2: 2 },
{ q1: 3, q2: 4 },
]);
});
it("array followed by table array", () => {
const tomlContent = `
[global]
array = [1, 2, 3]
[[items]]
q1 = 1
`;
const Bun = globalThis.Bun;
const parsed = Bun.TOML.parse(tomlContent);
expect(parsed.global).toEqual({
array: [1, 2, 3],
});
expect(parsed.items).toEqual([{ q1: 1 }]);
});
it("nested inline tables", () => {
const tomlContent = `
[global]
nested = { outer = { inner = 1 } }
[[items]]
q1 = 1
`;
const Bun = globalThis.Bun;
const parsed = Bun.TOML.parse(tomlContent);
expect(parsed.global).toEqual({
nested: { outer: { inner: 1 } },
});
expect(parsed.items).toEqual([{ q1: 1 }]);
});
it("Bun.TOML.parse throws on deeply nested inline tables instead of crashing", () => {
const depth = 25_000;
const deepToml = "a = " + "{ b = ".repeat(depth) + "1" + " }".repeat(depth);
expect(() => Bun.TOML.parse(deepToml)).toThrow(RangeError);
});