From bbd13ab961ab49e01d5699eec195929cae7bf25a Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Mon, 17 Feb 2025 17:23:07 -0800 Subject: [PATCH] rescanMac: Avoid overallocating/overreading by millions of bytes readAtLeast is greedy and will read the entire length of the buffer if it can. However, reading past the end of the cert in this case is useless, so reading the full length of the buffer just puts an increasingly large (due to the growth algorithm of ArrayList) collection of wasted bytes after each cert in cb.bytes. In practical terms, this ends up saving potentially millions of bytes of wasted reads/allocations. In my testing, after reading the keychain files on my machine, cb.bytes ends up with these capacities: - Before: cb.bytes.capacity = 32720747 - After: cb.bytes.capacity = 251937 That's a decrease of 99.2% Additionally, swaps to readNoEof since it should be an error to hit EOF without reading the full cert size. --- lib/std/crypto/Certificate/Bundle/macos.zig | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/std/crypto/Certificate/Bundle/macos.zig b/lib/std/crypto/Certificate/Bundle/macos.zig index e8e296a034..a1ecf95605 100644 --- a/lib/std/crypto/Certificate/Bundle/macos.zig +++ b/lib/std/crypto/Certificate/Bundle/macos.zig @@ -71,11 +71,9 @@ pub fn rescanMac(cb: *Bundle, gpa: Allocator) RescanMacError!void { if (cert_header.cert_size == 0) continue; - try cb.bytes.ensureUnusedCapacity(gpa, cert_header.cert_size); - const cert_start = @as(u32, @intCast(cb.bytes.items.len)); - const dest_buf = cb.bytes.allocatedSlice()[cert_start..]; - cb.bytes.items.len += try reader.readAtLeast(dest_buf, cert_header.cert_size); + const dest_buf = try cb.bytes.addManyAsSlice(gpa, cert_header.cert_size); + try reader.readNoEof(dest_buf); try cb.parseCert(gpa, cert_start, now_sec); }