mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
## Summary Fixed an off-by-one error in buffer allocation for several path module functions when handling paths longer than `PATH_SIZE` (typically 4096 bytes on most platforms). ## Changes - `normalizeJS_T`: Added +1 to buffer allocation for null terminator - `relativeJS_T`: Added +1 to buffer allocation for null terminator - `toNamespacedPathJS_T`: Added +9 bytes (8 for possible UNC prefix + 1 for null terminator) ## Test plan - Added tests for `path.normalize()` with paths up to 100,000 characters - Added tests for `path.relative()` with very long paths - All existing path tests continue to pass The issue occurred because when a path is exactly equal to or longer than `PATH_SIZE`, the buffer was allocated with size equal to the path length, but then a null terminator was written at `buf[bufSize]`, which was out of bounds. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Bot <claude-bot@bun.sh> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Jarred Sumner <jarred@jarredsumner.com>
66 lines
4.1 KiB
JavaScript
66 lines
4.1 KiB
JavaScript
import { describe, test } from "bun:test";
|
|
import assert from "node:assert";
|
|
import path from "node:path";
|
|
|
|
describe("path.normalize", () => {
|
|
test("win32", () => {
|
|
assert.strictEqual(path.win32.normalize("./fixtures///b/../b/c.js"), "fixtures\\b\\c.js");
|
|
assert.strictEqual(path.win32.normalize("/foo/../../../bar"), "\\bar");
|
|
assert.strictEqual(path.win32.normalize("a//b//../b"), "a\\b");
|
|
assert.strictEqual(path.win32.normalize("a//b//./c"), "a\\b\\c");
|
|
assert.strictEqual(path.win32.normalize("a//b//."), "a\\b");
|
|
assert.strictEqual(path.win32.normalize("//server/share/dir/file.ext"), "\\\\server\\share\\dir\\file.ext");
|
|
assert.strictEqual(path.win32.normalize("/a/b/c/../../../x/y/z"), "\\x\\y\\z");
|
|
assert.strictEqual(path.win32.normalize("C:"), "C:.");
|
|
assert.strictEqual(path.win32.normalize("C:..\\abc"), "C:..\\abc");
|
|
assert.strictEqual(path.win32.normalize("C:..\\..\\abc\\..\\def"), "C:..\\..\\def");
|
|
assert.strictEqual(path.win32.normalize("C:\\."), "C:\\");
|
|
assert.strictEqual(path.win32.normalize("file:stream"), "file:stream");
|
|
assert.strictEqual(path.win32.normalize("bar\\foo..\\..\\"), "bar\\");
|
|
assert.strictEqual(path.win32.normalize("bar\\foo..\\.."), "bar");
|
|
assert.strictEqual(path.win32.normalize("bar\\foo..\\..\\baz"), "bar\\baz");
|
|
assert.strictEqual(path.win32.normalize("bar\\foo..\\"), "bar\\foo..\\");
|
|
assert.strictEqual(path.win32.normalize("bar\\foo.."), "bar\\foo..");
|
|
assert.strictEqual(path.win32.normalize("..\\foo..\\..\\..\\bar"), "..\\..\\bar");
|
|
assert.strictEqual(path.win32.normalize("..\\...\\..\\.\\...\\..\\..\\bar"), "..\\..\\bar");
|
|
assert.strictEqual(path.win32.normalize("../../../foo/../../../bar"), "..\\..\\..\\..\\..\\bar");
|
|
assert.strictEqual(path.win32.normalize("../../../foo/../../../bar/../../"), "..\\..\\..\\..\\..\\..\\");
|
|
assert.strictEqual(path.win32.normalize("../foobar/barfoo/foo/../../../bar/../../"), "..\\..\\");
|
|
assert.strictEqual(path.win32.normalize("../.../../foobar/../../../bar/../../baz"), "..\\..\\..\\..\\baz");
|
|
assert.strictEqual(path.win32.normalize("foo/bar\\baz"), "foo\\bar\\baz");
|
|
});
|
|
|
|
test("posix", () => {
|
|
assert.strictEqual(path.posix.normalize("./fixtures///b/../b/c.js"), "fixtures/b/c.js");
|
|
assert.strictEqual(path.posix.normalize("/foo/../../../bar"), "/bar");
|
|
assert.strictEqual(path.posix.normalize("a//b//../b"), "a/b");
|
|
assert.strictEqual(path.posix.normalize("a//b//./c"), "a/b/c");
|
|
assert.strictEqual(path.posix.normalize("a//b//."), "a/b");
|
|
assert.strictEqual(path.posix.normalize("/a/b/c/../../../x/y/z"), "/x/y/z");
|
|
assert.strictEqual(path.posix.normalize("///..//./foo/.//bar"), "/foo/bar");
|
|
assert.strictEqual(path.posix.normalize("bar/foo../../"), "bar/");
|
|
assert.strictEqual(path.posix.normalize("bar/foo../.."), "bar");
|
|
assert.strictEqual(path.posix.normalize("bar/foo../../baz"), "bar/baz");
|
|
assert.strictEqual(path.posix.normalize("bar/foo../"), "bar/foo../");
|
|
assert.strictEqual(path.posix.normalize("bar/foo.."), "bar/foo..");
|
|
assert.strictEqual(path.posix.normalize("../foo../../../bar"), "../../bar");
|
|
assert.strictEqual(path.posix.normalize("../.../.././.../../../bar"), "../../bar");
|
|
assert.strictEqual(path.posix.normalize("../../../foo/../../../bar"), "../../../../../bar");
|
|
assert.strictEqual(path.posix.normalize("../../../foo/../../../bar/../../"), "../../../../../../");
|
|
assert.strictEqual(path.posix.normalize("../foobar/barfoo/foo/../../../bar/../../"), "../../");
|
|
assert.strictEqual(path.posix.normalize("../.../../foobar/../../../bar/../../baz"), "../../../../baz");
|
|
assert.strictEqual(path.posix.normalize("foo/bar\\baz"), "foo/bar\\baz");
|
|
});
|
|
|
|
test("very long paths", () => {
|
|
// Regression test: buffer overflow with paths longer than PATH_SIZE
|
|
// This used to panic with "index out of bounds" because the buffer
|
|
// didn't account for the null terminator
|
|
for (const len of [4096, 10000, 50000, 98340, 100000]) {
|
|
const longPath = "a".repeat(len);
|
|
assert.strictEqual(path.normalize(longPath), longPath);
|
|
assert.strictEqual(path.normalize(longPath).length, len);
|
|
}
|
|
});
|
|
});
|