authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-07 18:15:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 13:12:47-07:00
log5b57dca62d8094d58a21e5458b5095febce47dc5
treed1bbccbd776a509f301d233a426d215f5decc275
parent2c605872fc4fb5f4df99647ad7f4fbe7f65612a5

std.build.Cache: fix regressions from the branch


1 files changed, 53 insertions(+), 24 deletions(-)

lib/std/Build/Cache.zig+53-24
...@@ -67,7 +67,8 @@ fn appendPrefixedPath(cache: *const Cache, contents: *std.ArrayList(u8), prefixe...@@ -67,7 +67,8 @@ fn appendPrefixedPath(cache: *const Cache, contents: *std.ArrayList(u8), prefixe
67 const end = contents.items.len + prefixed_path.sub_path.len;67 const end = contents.items.len + prefixed_path.sub_path.len;
68 const needed_alignment = @alignOf(Manifest.File) - (end % @alignOf(Manifest.File));68 const needed_alignment = @alignOf(Manifest.File) - (end % @alignOf(Manifest.File));
69 assert(needed_alignment >= 1); // Always need at least a null byte.69 assert(needed_alignment >= 1); // Always need at least a null byte.
70 try contents.ensureTotalCapacity(cache.gpa, end + needed_alignment);70 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all times.
71 try contents.ensureTotalCapacity(cache.gpa, end + needed_alignment + 1);
71 contents.appendSliceAssumeCapacity(prefixed_path.sub_path);72 contents.appendSliceAssumeCapacity(prefixed_path.sub_path);
72 contents.appendNTimesAssumeCapacity(0, needed_alignment);73 contents.appendNTimesAssumeCapacity(0, needed_alignment);
73 return prefixed_path.prefix;74 return prefixed_path.prefix;
...@@ -97,7 +98,10 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa...@@ -97,7 +98,10 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa
9798
98 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));99 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));
99 assert(needed_alignment >= 1); // Always need at least a null byte.100 assert(needed_alignment >= 1); // Always need at least a null byte.
100 try contents.appendNTimes(gpa, 0, needed_alignment);101 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all
102 // times.
103 try contents.ensureUnusedCapacity(gpa, needed_alignment + 1);
104 contents.appendNTimesAssumeCapacity(0, needed_alignment);
101105
102 return @intCast(i);106 return @intCast(i);
103 }107 }
...@@ -107,7 +111,9 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa...@@ -107,7 +111,9 @@ fn resolveAppendPath(cache: *const Cache, contents: *std.ArrayList(u8), path: Pa
107111
108 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));112 const needed_alignment = @alignOf(Manifest.File) - (contents.items.len % @alignOf(Manifest.File));
109 assert(needed_alignment >= 1); // Always need at least a null byte.113 assert(needed_alignment >= 1); // Always need at least a null byte.
110 try contents.appendNTimes(gpa, 0, needed_alignment);114 // Extra +1 here is due to the requirement to keep at least 1 unused capacity in `Manifest.contents` at all times.
115 try contents.ensureUnusedCapacity(gpa, needed_alignment + 1);
116 contents.appendNTimesAssumeCapacity(0, needed_alignment);
111117
112 return 0;118 return 0;
113}119}
...@@ -127,10 +133,10 @@ pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);...@@ -127,10 +133,10 @@ pub const Hasher = crypto.auth.siphash.SipHash128(1, 3);
127/// Refresh this with new random bytes when the manifest133/// Refresh this with new random bytes when the manifest
128/// format is modified in a non-backwards-compatible way.134/// format is modified in a non-backwards-compatible way.
129pub const hasher_init: Hasher = Hasher.init(&.{135pub const hasher_init: Hasher = Hasher.init(&.{
130 0x33, 0x52, 0xa2, 0x84,136 0x02, 0xe9, 0xfa, 0xfe,
131 0xcf, 0x17, 0x56, 0x57,137 0xe0, 0x95, 0x81, 0x55,
132 0x01, 0xbb, 0xcd, 0xe4,138 0xf5, 0x5a, 0x15, 0xcb,
133 0x77, 0xd6, 0xf0, 0x60,139 0x4a, 0xf4, 0x00, 0x09,
134});140});
135141
136pub const HashHelper = struct {142pub const HashHelper = struct {
...@@ -487,7 +493,8 @@ pub const Manifest = struct {...@@ -487,7 +493,8 @@ pub const Manifest = struct {
487 pub const Diagnostic = union(enum) {493 pub const Diagnostic = union(enum) {
488 none,494 none,
489 manifest_create: Io.File.OpenError,495 manifest_create: Io.File.OpenError,
490 manifest_read: Io.File.Reader.Error,496 manifest_stat: Io.File.StatError,
497 manifest_read: Io.File.ReadPositionalError,
491 manifest_lock: Io.File.LockError,498 manifest_lock: Io.File.LockError,
492 file_open: FileOp,499 file_open: FileOp,
493 file_stat: FileOp,500 file_stat: FileOp,
...@@ -644,7 +651,7 @@ pub const Manifest = struct {...@@ -644,7 +651,7 @@ pub const Manifest = struct {
644 return @fromBackingInt(@intCast(gop.index));651 return @fromBackingInt(@intCast(gop.index));
645 }652 }
646653
647 pub fn addInputFileOptional(m: *Manifest, opt_path: ?Path, options: AddInputPathOptions) Allocator.Error!void {654 pub fn addInputPathOptional(m: *Manifest, opt_path: ?Path, options: AddInputPathOptions) Allocator.Error!void {
648 m.hash.add(opt_path != null);655 m.hash.add(opt_path != null);
649 _ = try addInputPath(m, opt_path orelse return, options);656 _ = try addInputPath(m, opt_path orelse return, options);
650 }657 }
...@@ -824,24 +831,43 @@ pub const Manifest = struct {...@@ -824,24 +831,43 @@ pub const Manifest = struct {
824 fn checkLocked(m: *Manifest) Check.Error!Check.Status {831 fn checkLocked(m: *Manifest) Check.Error!Check.Status {
825 const gpa = m.cache.gpa;832 const gpa = m.cache.gpa;
826 const io = m.cache.io;833 const io = m.cache.io;
834 const manifest_file = m.manifest_file.?;
827835
828 var manifest_reader = m.manifest_file.?.reader(io, &.{}); // Reads positionally from zero.836 const manifest_size = if (manifest_file.stat(io)) |stat| stat.size else |err| switch (err) {
829 m.contents.clearRetainingCapacity();837 error.Canceled => |e| return e,
830 manifest_reader.interface.appendRemainingUnlimited(gpa, &m.contents) catch |err| switch (err) {838 else => |e| {
831 error.OutOfMemory => |e| return e,839 m.diagnostic = .{ .manifest_stat = e };
832 error.ReadFailed => {
833 m.diagnostic = .{ .manifest_read = manifest_reader.err.? };
834 return error.CacheCheckFailed;840 return error.CacheCheckFailed;
835 },841 },
836 };842 };
843
844 // We always want to compute the input file hash digests, even on a cache miss, because they will be
845 // used in the manifest digest.
846
847 if (manifest_size == 0 or manifest_size < m.contents.items.len) {
848 // Don't clobber our input files by overwriting contents since it's a cache miss.
849 try m.contents.ensureUnusedCapacity(gpa, 1);
850 return .miss;
851 }
852
853 // Already supposedly includes the extra null byte that we have to maintain.
854 try m.contents.resize(gpa, manifest_size);
855
856 {
857 const n = manifest_file.readPositionalAll(io, m.contents.items, 0) catch |err| switch (err) {
858 error.Canceled => |e| return e,
859 else => |e| {
860 m.diagnostic = .{ .manifest_read = e };
861 return error.CacheCheckFailed;
862 },
863 };
864 m.contents.shrinkRetainingCapacity(n);
865 }
837 const contents = m.contents.items;866 const contents = m.contents.items;
838867
839 var off: usize = 0;868 var off: usize = 0;
840 var c: Check = .{};869 var c: Check = .{};
841870
842 // We always want to compute the input file hash digests, even on a cache miss, because they will be
843 // used in the manifest digest.
844
845 // First the input files section, which must match our input files, otherwise it's invalid format.871 // First the input files section, which must match our input files, otherwise it's invalid format.
846 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| {872 for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| {
847 if (off + 1 >= contents.len) return error.InvalidFormat;873 if (off + 1 >= contents.len) return error.InvalidFormat;
...@@ -1466,7 +1492,7 @@ pub const Manifest = struct {...@@ -1466,7 +1492,7 @@ pub const Manifest = struct {
1466 const prev_contents_len = other.contents.items.len;1492 const prev_contents_len = other.contents.items.len;
1467 try other.contents.appendSlice(gpa, copy_bytes);1493 try other.contents.appendSlice(gpa, copy_bytes);
14681494
1469 const gop = other.files.getOrPutAssumeCapacity(@fromBackingInt(prev_contents_len), .{1495 const gop = other.files.getOrPutAssumeCapacityContext(@fromBackingInt(prev_contents_len), .{
1470 .manifest = other,1496 .manifest = other,
1471 });1497 });
14721498
...@@ -1514,7 +1540,7 @@ pub const Manifest = struct {...@@ -1514,7 +1540,7 @@ pub const Manifest = struct {
1514 var entries_list: std.ArrayList(u32) = .empty;1540 var entries_list: std.ArrayList(u32) = .empty;
1515 defer entries_list.deinit(gpa);1541 defer entries_list.deinit(gpa);
15161542
1517 while (true) {1543 while (reader.state != .finished) {
1518 const entries = entry_buffer[0..try reader.read(io, &entry_buffer)];1544 const entries = entry_buffer[0..try reader.read(io, &entry_buffer)];
1519 for (try entries_list.addManyAsSlice(gpa, entries.len), entries) |*off, entry| {1545 for (try entries_list.addManyAsSlice(gpa, entries.len), entries) |*off, entry| {
1520 off.* = @intCast(contents.items.len);1546 off.* = @intCast(contents.items.len);
...@@ -1528,12 +1554,15 @@ pub const Manifest = struct {...@@ -1528,12 +1554,15 @@ pub const Manifest = struct {
1528 }1554 }
15291555
1530 const Sort = struct {1556 const Sort = struct {
1531 contents: []const u8,1557 contents: [*:0]const u8,
1532 pub fn lessThan(this: @This(), lhs: u32, rhs: u32) bool {1558 pub fn lessThan(this: @This(), lhs: u32, rhs: u32) bool {
1533 return mem.lessThanZ(u8, this.contents[lhs + 1 ..], this.contents[rhs + 1 ..]); // +1 for kind byte1559 // This comparison includes the kind byte.
1560 return mem.lessThanZ(u8, this.contents + lhs, this.contents + rhs);
1534 }1561 }
1535 };1562 };
1536 mem.sortUnstable(u32, entries_list.items, @as(Sort, .{ .contents = contents.items }), Sort.lessThan);1563 mem.sortUnstable(u32, entries_list.items, @as(Sort, .{
1564 .contents = @ptrCast(contents.items.ptr),
1565 }), Sort.lessThan);
15371566
1538 // Duplicate the contents such that we may refer to it while creating a1567 // Duplicate the contents such that we may refer to it while creating a
1539 // sorted copy in the original position (at contents_start). We will then1568 // sorted copy in the original position (at contents_start). We will then
...@@ -1546,7 +1575,7 @@ pub const Manifest = struct {...@@ -1546,7 +1575,7 @@ pub const Manifest = struct {
1546 const offset = wrong_offset + contents_len;1575 const offset = wrong_offset + contents_len;
1547 // Includes the kind prefix which we also want to copy.1576 // Includes the kind prefix which we also want to copy.
1548 const entry: [*:0]const u8 = @ptrCast(contents.items[offset..]);1577 const entry: [*:0]const u8 = @ptrCast(contents.items[offset..]);
1549 new_offset += mem.copySentinel(u8, 0, contents.items[new_offset..], entry);1578 new_offset += mem.copySentinelInclusive(u8, 0, contents.items[new_offset..], entry);
1550 }1579 }
1551 assert(new_offset == contents_start + contents_len);1580 assert(new_offset == contents_start + contents_len);
1552 contents.shrinkRetainingCapacity(contents_start + contents_len);1581 contents.shrinkRetainingCapacity(contents_start + contents_len);