authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 16:05:26-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-09-16 16:05:26-07:00
log56571a70d99a896777146e9588d9f6a04124c9a5
tree381c40048eeca54512266ef5fd1a4ec6c4643323
parent5549d9bbe3d091751394b78c205e357891013cdb

std.Build.Cache: fix flagsAndPath implementation

it was scanning for sentinel starting from flags rather than flags + 1, which could lead to the scenario where the path is empty because flags is zero

2 files changed, 7 insertions(+), 9 deletions(-)

lib/std/Build/Cache.zig+6-8
...@@ -499,9 +499,10 @@ pub const Manifest = struct {...@@ -499,9 +499,10 @@ pub const Manifest = struct {
499 pub fn flagsAndPath(off: File.Offset, contents: []const u8) [:0]const u8 {499 pub fn flagsAndPath(off: File.Offset, contents: []const u8) [:0]const u8 {
500 const flags_off = @offsetOf(File, "flags");500 const flags_off = @offsetOf(File, "flags");
501 comptime assert(@offsetOf(File, "path_start") - flags_off == 1);501 comptime assert(@offsetOf(File, "path_start") - flags_off == 1);
502 const hash_start = @backingInt(off) + flags_off;502 const start = @backingInt(off) + flags_off;
503 const hash_end = mem.findScalarPos(u8, contents, hash_start, 0).?;503 // Scan for the sentinel starting from the path_start offset because flags might be zero.
504 return contents[hash_start..hash_end :0];504 const end = mem.findScalarPos(u8, contents, start + 1, 0).?;
505 return contents[start..end :0];
505 }506 }
506507
507 pub fn pathFallible(off: File.Offset, contents: []const u8) error{InvalidFormat}![:0]const u8 {508 pub fn pathFallible(off: File.Offset, contents: []const u8) error{InvalidFormat}![:0]const u8 {
...@@ -898,7 +899,8 @@ pub const Manifest = struct {...@@ -898,7 +899,8 @@ pub const Manifest = struct {
898 // This is *not* hashing the contents of the input files. It is the899 // This is *not* hashing the contents of the input files. It is the
899 // flags (including prefix) and path only.900 // flags (including prefix) and path only.
900 for (man.files.keys()[0..man.input_paths.items.len]) |file_off| {901 for (man.files.keys()[0..man.input_paths.items.len]) |file_off| {
901 man.hashFlagsAndPath(file_off, &man.hash.hasher);902 const flags_and_path = file_off.flagsAndPath(man.contents.items);
903 man.hash.hasher.update(mem.absorbSentinel(flags_and_path));
902 }904 }
903905
904 var input_digest: BinDigest = undefined;906 var input_digest: BinDigest = undefined;
...@@ -2288,10 +2290,6 @@ pub const Manifest = struct {...@@ -2288,10 +2290,6 @@ pub const Manifest = struct {
2288 hasher.update(contents.items[contents_start..][0..contents_len]);2290 hasher.update(contents.items[contents_start..][0..contents_len]);
2289 hasher.final(bin_digest);2291 hasher.final(bin_digest);
2290 }2292 }
2291
2292 fn hashFlagsAndPath(m: *const Manifest, off: File.Offset, hasher: *Hasher) void {
2293 hasher.update(off.flagsAndPath(m.contents.items));
2294 }
2295};2293};
22962294
2297/// Create/Write a file, close it, then grab its stat.mtime timestamp.2295/// Create/Write a file, close it, then grab its stat.mtime timestamp.
src/Compilation.zig+1-1
...@@ -5530,7 +5530,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr...@@ -5530,7 +5530,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: std.Pr
5530 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)});5530 return comp.failCObj(c_object, "checking cache failed: {f}", .{diagnostic.fmt(&man)});
5531 },5531 },
5532 };5532 };
5533 log.debug("C object cache {f}", .{status.fmt(&man)});5533 log.debug("C object {q} cache {f}", .{ c_object.src.src_path, status.fmt(&man) });
5534 if (status == .hit) break :d man.hitDigestHex();5534 if (status == .hit) break :d man.hitDigestHex();
5535 }5535 }
5536 var argv: std.array_list.Managed([]const u8) = .init(gpa);5536 var argv: std.array_list.Managed([]const u8) = .init(gpa);