diff --git a/src/string_immutable.zig b/src/string_immutable.zig index c46e95875b..89715d846e 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -2570,8 +2570,7 @@ pub fn escapeHTMLForLatin1Input(allocator: std.mem.Allocator, latin1: []const u8 buf = try std.ArrayList(u8).initCapacity(allocator, latin1.len + 6); const copy_len = @intFromPtr(remaining.ptr) - @intFromPtr(latin1.ptr); - @memcpy(buf.items[0..copy_len], latin1[0..copy_len]); - buf.items.len = copy_len; + buf.appendSliceAssumeCapacity(latin1[0..copy_len]); any_needs_escape = true; inline for (0..ascii_vector_size) |i| { switch (vec[i]) { diff --git a/test/js/bun/util/escapeHTML.test.js b/test/js/bun/util/escapeHTML.test.js index 12d185f1fb..78d5b96656 100644 --- a/test/js/bun/util/escapeHTML.test.js +++ b/test/js/bun/util/escapeHTML.test.js @@ -102,4 +102,28 @@ describe("escapeHTML", () => { escapeHTML(String.fromCodePoint(0xd800) + "\xff".repeat(i)); } }); + + it("fuzz latin1", () => { + for (let i = 0; i < 256; i++) { + const initial = Buffer.alloc(i + 1, "a"); + for (let j = 0; j < i; j++) { + const clone = Buffer.from(initial); + clone[j] = ">".charCodeAt(0); + Bun.escapeHTML(clone.toString()); + } + } + }); + + it("fuzz utf16", () => { + for (let i = 0; i < 256; i++) { + const initial = new Uint16Array(i); + initial.fill("a".charCodeAt(0)); + + for (let j = 0; j < i; j++) { + const clone = Buffer.from(initial); + clone[j] = ">".charCodeAt(0); + Bun.escapeHTML(clone.toString("utf16le")); + } + } + }); });