| ... | @@ -409,6 +409,7 @@ pub const Manifest = struct { | ... | @@ -409,6 +409,7 @@ pub const Manifest = struct { |
| 409 | | 409 | |
| 410 | pub fn getFallible(offset: Offset, contents: []u8) error{InvalidFormat}!*File { | 410 | pub fn getFallible(offset: Offset, contents: []u8) error{InvalidFormat}!*File { |
| 411 | if (@backingInt(offset) + @sizeOf(File) >= contents.len) return error.InvalidFormat; | 411 | if (@backingInt(offset) + @sizeOf(File) >= contents.len) return error.InvalidFormat; |
| | 412 | if (!mem.isAligned(@backingInt(offset), @alignOf(File))) return error.InvalidFormat; |
| 412 | return get(offset, contents); | 413 | return get(offset, contents); |
| 413 | } | 414 | } |
| 414 | }; | 415 | }; |
| ... | @@ -458,6 +459,14 @@ pub const Manifest = struct { | ... | @@ -458,6 +459,14 @@ pub const Manifest = struct { |
| 458 | return true; | 459 | return true; |
| 459 | } | 460 | } |
| 460 | } | 461 | } |
| | 462 | |
| | 463 | /// `path_len` does not include the null byte. |
| | 464 | fn sizeOf(path_len: usize) usize { |
| | 465 | const end = @offsetOf(File, "path_start") + path_len; |
| | 466 | const needed_alignment = @alignOf(File) - (end % @alignOf(File)); |
| | 467 | assert(needed_alignment >= 1); // Always need at least a null byte. |
| | 468 | return end + needed_alignment; |
| | 469 | } |
| 461 | }; | 470 | }; |
| 462 | | 471 | |
| 463 | pub const Diagnostic = union(enum) { | 472 | pub const Diagnostic = union(enum) { |
| ... | @@ -809,7 +818,7 @@ pub const Manifest = struct { | ... | @@ -809,7 +818,7 @@ pub const Manifest = struct { |
| 809 | }; | 818 | }; |
| 810 | const contents = m.contents.items; | 819 | const contents = m.contents.items; |
| 811 | | 820 | |
| 812 | var off: u32 = 0; | 821 | var off: usize = 0; |
| 813 | var c: Check = .{}; | 822 | var c: Check = .{}; |
| 814 | | 823 | |
| 815 | // This group we always want to compute the hash digests, even on a | 824 | // This group we always want to compute the hash digests, even on a |
| ... | @@ -821,7 +830,7 @@ pub const Manifest = struct { | ... | @@ -821,7 +830,7 @@ pub const Manifest = struct { |
| 821 | // otherwise it's invalid format. | 830 | // otherwise it's invalid format. |
| 822 | for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| { | 831 | for (m.input_paths.items, m.files.keys()[0..m.input_paths.items.len]) |*input_path, input_file_off| { |
| 823 | if (off + 1 >= contents.len) return error.InvalidFormat; | 832 | if (off + 1 >= contents.len) return error.InvalidFormat; |
| 824 | const file_off: File.Offset = @fromBackingInt(off); | 833 | const file_off: File.Offset = @fromBackingInt(@intCast(off)); |
| 825 | const file = try file_off.getFallible(contents); | 834 | const file = try file_off.getFallible(contents); |
| 826 | if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat; | 835 | if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat; |
| 827 | const path = try filePathFallible(contents, file_off); | 836 | const path = try filePathFallible(contents, file_off); |
| ... | @@ -830,7 +839,7 @@ pub const Manifest = struct { | ... | @@ -830,7 +839,7 @@ pub const Manifest = struct { |
| 830 | | 839 | |
| 831 | input_group.async(io, checkInputFile, .{ m, &c, file_off, path, input_path }); | 840 | input_group.async(io, checkInputFile, .{ m, &c, file_off, path, input_path }); |
| 832 | | 841 | |
| 833 | off = @intCast(@as(usize, off) + @sizeOf(File) + path.len + 1); | 842 | off += File.sizeOf(path.len); |
| 834 | } | 843 | } |
| 835 | | 844 | |
| 836 | // Guess number of files based on manifest contents len to reduce allocations. | 845 | // Guess number of files based on manifest contents len to reduce allocations. |
| ... | @@ -849,7 +858,7 @@ pub const Manifest = struct { | ... | @@ -849,7 +858,7 @@ pub const Manifest = struct { |
| 849 | defer post_select.cancelDiscard(); | 858 | defer post_select.cancelDiscard(); |
| 850 | | 859 | |
| 851 | while (off + 1 < contents.len) { | 860 | while (off + 1 < contents.len) { |
| 852 | const file_off: File.Offset = @fromBackingInt(off); | 861 | const file_off: File.Offset = @fromBackingInt(@intCast(off)); |
| 853 | const file = try file_off.getFallible(contents); | 862 | const file = try file_off.getFallible(contents); |
| 854 | if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat; | 863 | if (file.flags.prefix >= m.cache.prefixes_len) return error.InvalidFormat; |
| 855 | const path = try filePathFallible(contents, file_off); | 864 | const path = try filePathFallible(contents, file_off); |
| ... | @@ -860,7 +869,7 @@ pub const Manifest = struct { | ... | @@ -860,7 +869,7 @@ pub const Manifest = struct { |
| 860 | post_select.async(.checkFile, checkFile, .{ m, &c, file_off, path }); | 869 | post_select.async(.checkFile, checkFile, .{ m, &c, file_off, path }); |
| 861 | post_select_remaining += 1; | 870 | post_select_remaining += 1; |
| 862 | | 871 | |
| 863 | off = @intCast(@as(usize, off) + @sizeOf(File) + path.len + 1); | 872 | off += File.sizeOf(path.len); |
| 864 | } | 873 | } |
| 865 | | 874 | |
| 866 | // Final terminating zero byte to distinguish empty manifest file from | 875 | // Final terminating zero byte to distinguish empty manifest file from |