authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-09 14:30:09-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-07-09 15:51:28-04:00
log30713514345f4416f7e68342be5555734e55410e
treeac1daa130d44409a30e05914229ae06b3596d14b
parenta03711b1e3921b2e088e4ee05277497e6143355c

MappedFile: rework add node fixes

This code was attempting to work around an assertion which trips when an invalid offset is chosen for a new node, but it duplicates logic from later in the function, so instead start with an initial offset and alignment that are always valid and use the already existing helper function to meet the requested alignment, similar to how the requested size is met.

3 files changed, 71 insertions(+), 67 deletions(-)

src/link/Coff.zig+2-2
...@@ -3602,13 +3602,13 @@ fn objectSectionMapIndex(...@@ -3602,13 +3602,13 @@ fn objectSectionMapIndex(
3602 const parent_alignment = parent_ni.alignment(&coff.mf);3602 const parent_alignment = parent_ni.alignment(&coff.mf);
3603 if (alignment.compare(.gt, parent_alignment)) {3603 if (alignment.compare(.gt, parent_alignment)) {
3604 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });3604 log.debug("realignParent({s}, {d}) {d}->{d}", .{ name.toSlice(coff), parent_ni, parent_alignment, alignment });
3605 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true });3605 try parent_ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3606 }3606 }
36073607
3608 const old_alignment = sym.ni.alignment(&coff.mf);3608 const old_alignment = sym.ni.alignment(&coff.mf);
3609 if (alignment.compare(.gt, old_alignment)) {3609 if (alignment.compare(.gt, old_alignment)) {
3610 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });3610 log.debug("realignObject({s}) {d}->{d}", .{ name.toSlice(coff), old_alignment, alignment });
3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .set_alignment = true });3611 try sym.ni.realign(&coff.mf, gpa, alignment, .{ .try_backwards = true });
3612 }3612 }
36133613
3614 try coff.verifyParentSectionAttributes(3614 try coff.verifyParentSectionAttributes(
src/link/Elf2.zig+3-3
...@@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct {...@@ -4659,7 +4659,7 @@ fn mapInputSection(elf: *Elf, opts: struct {
4659 const new_alignment: std.mem.Alignment = .fromByteUnits(4659 const new_alignment: std.mem.Alignment = .fromByteUnits(
4660 std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)),4660 std.math.ceilPowerOfTwoAssert(usize, @intCast(opts.addralign)),
4661 );4661 );
4662 try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{ .set_alignment = true });4662 try existing_shndx.get(elf).ni.realign(&elf.mf, gpa, new_alignment, .{});
4663 }4663 }
4664 // ...and update the shdr as needed.4664 // ...and update the shdr as needed.
4665 switch (elf.shdrPtr(existing_shndx)) {4665 switch (elf.shdrPtr(existing_shndx)) {
...@@ -4822,7 +4822,7 @@ fn uavMapIndex(...@@ -4822,7 +4822,7 @@ fn uavMapIndex(
4822 } else {4822 } else {
4823 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;4823 const node = uav_gop.value_ptr.lsi.index().ptr(elf).node;
4824 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {4824 if (resolved_align.toStdMem().order(node.alignment(&elf.mf)).compare(.gt)) {
4825 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{ .set_alignment = true });4825 try node.realign(&elf.mf, gpa, resolved_align.toStdMem(), .{});
4826 }4826 }
4827 }4827 }
4828 return umi;4828 return umi;
...@@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars...@@ -5551,7 +5551,7 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars
5551 // We have a copy relocation for this global, but the amount of space we5551 // We have a copy relocation for this global, but the amount of space we
5552 // reserved for it could be too small or underaligned!5552 // reserved for it could be too small or underaligned!
5553 try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size);5553 try copied_global.node.resize(&elf.mf, gpa, gop.value_ptr.size);
5554 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{ .set_alignment = true });5554 try copied_global.node.realign(&elf.mf, gpa, gop.value_ptr.alignment, .{});
5555 const global_ptr = elf.globalByName(name).?;5555 const global_ptr = elf.globalByName(name).?;
5556 switch (elf.symPtr(global_ptr.symtab_index)) {5556 switch (elf.symPtr(global_ptr.symtab_index)) {
5557 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),5557 inline else => |sym_ptr| elf.targetStore(&sym_ptr.size, @intCast(gop.value_ptr.size)),
src/link/MappedFile.zig+66-62
...@@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I...@@ -95,14 +95,11 @@ pub fn init(file: Io.File, gpa: std.mem.Allocator, io: Io) (Allocator.Error || I
95 .fallocate_punch_hole_unsupported = false,95 .fallocate_punch_hole_unsupported = false,
96 };96 };
97 try mf.nodes.ensureUnusedCapacity(gpa, 1);97 try mf.nodes.ensureUnusedCapacity(gpa, 1);
98 const root_ni = mf.addNode(gpa, .{ .add_node = .{98 const root_ni = try mf.addNode(gpa, .{ .add_node = .{
99 .size = size,99 .size = size,
100 .alignment = mf.flags.block_size,100 .alignment = mf.flags.block_size,
101 .fixed = true,101 .fixed = true,
102 } }) catch |err| switch (err) {102 } });
103 error.MappedFileIo => return mf.io_err.?,
104 else => |e| return e,
105 };
106 assert(root_ni == Node.Index.root);103 assert(root_ni == Node.Index.root);
107 try mf.ensureTotalCapacityInner(@intCast(size));104 try mf.ensureTotalCapacityInner(@intCast(size));
108 return mf;105 return mf;
...@@ -355,9 +352,7 @@ pub const Node = extern struct {...@@ -355,9 +352,7 @@ pub const Node = extern struct {
355352
356 pub const RealignNodeOptions = struct {353 pub const RealignNodeOptions = struct {
357 /// Shift the node backwards if possible354 /// Shift the node backwards if possible
358 try_backwards: bool = true,355 try_backwards: bool = false,
359 /// If `set, persists `new_alignment` as the node's alignment for future operations.
360 set_alignment: bool = true,
361 };356 };
362357
363 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.358 /// Moves and expands a node such that its offset and size are aligned to `new_alignment`.
...@@ -378,11 +373,7 @@ pub const Node = extern struct {...@@ -378,11 +373,7 @@ pub const Node = extern struct {
378 return error.MappedFileIo;373 return error.MappedFileIo;
379 },374 },
380 };375 };
381 var writers_it = mf.writers.first;376 mf.updateWriters();
382 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
383 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
384 w.interface.buffer = w.ni.slice(mf);
385 }
386 }377 }
387378
388 /// Shrink a node to `size`, exactly.379 /// Shrink a node to `size`, exactly.
...@@ -398,11 +389,7 @@ pub const Node = extern struct {...@@ -398,11 +389,7 @@ pub const Node = extern struct {
398 shift_next: bool,389 shift_next: bool,
399 ) Error!void {390 ) Error!void {
400 try mf.shrinkNode(gpa, ni, size, shift_next);391 try mf.shrinkNode(gpa, ni, size, shift_next);
401 var writers_it = mf.writers.first;392 mf.updateWriters();
402 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
403 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
404 w.interface.buffer = w.ni.slice(mf);
405 }
406 }393 }
407394
408 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {395 pub fn writer(ni: Node.Index, mf: *MappedFile, gpa: std.mem.Allocator, w: *Writer) void {
...@@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -562,34 +549,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
562 next: Node.Index = .none,549 next: Node.Index = .none,
563 offset: u64 = 0,550 offset: u64 = 0,
564 add_node: AddNodeOptions,551 add_node: AddNodeOptions,
565}) Error!Node.Index {552}) (Allocator.Error || Io.Cancelable || IoError)!Node.Index {
566 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);553 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);
567 mf.nodes_lock.assertUnlocked();554 mf.nodes_lock.assertUnlocked();
568 const offset = opts.add_node.alignment.forward(@intCast(opts.offset));
569 if (opts.parent != .none) {
570 const new_end = offset + opts.add_node.size;
571 switch (opts.next) {
572 .none => {
573 _, const parent_size = opts.parent.location(mf).resolve(mf);
574 if (new_end > parent_size)
575 try opts.parent.resize(mf, gpa, new_end +| new_end / growth_factor);
576 },
577 else => |next_ni| {
578 const next_offset, _ = next_ni.location(mf).resolve(mf);
579 if (new_end > next_offset)
580 try next_ni.realign(mf, gpa, opts.add_node.alignment, .{
581 .try_backwards = false,
582 .set_alignment = false,
583 });
584 },
585 }
586 }
587 const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: {555 const location_tag: Node.Location.Tag, const location_payload: Node.Location.Payload = location: {
588 if (std.math.cast(u32, offset)) |small_offset| break :location .{ .small, .{556 if (std.math.cast(u32, opts.offset)) |small_offset| break :location .{ .small, .{
589 .small = .{ .offset = small_offset, .size = 0 },557 .small = .{ .offset = small_offset, .size = 0 },
590 } };558 } };
591 try mf.large.ensureUnusedCapacity(gpa, 2);559 try mf.large.ensureUnusedCapacity(gpa, 2);
592 defer mf.large.appendSliceAssumeCapacity(&.{ offset, 0 });560 defer mf.large.appendSliceAssumeCapacity(&.{ opts.offset, 0 });
593 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };561 break :location .{ .large, .{ .large = .{ .index = mf.large.items.len } } };
594 };562 };
595 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {563 const free_ni: Node.Index, const free_node = free: switch (mf.free_ni) {
...@@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -616,7 +584,7 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
616 .last = .none,584 .last = .none,
617 .flags = .{585 .flags = .{
618 .location_tag = location_tag,586 .location_tag = location_tag,
619 .alignment = opts.add_node.alignment,587 .alignment = .@"1",
620 .fixed = opts.add_node.fixed,588 .fixed = opts.add_node.fixed,
621 .moved = true,589 .moved = true,
622 .resized = true,590 .resized = true,
...@@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {...@@ -627,13 +595,15 @@ fn addNode(mf: *MappedFile, gpa: std.mem.Allocator, opts: struct {
627 };595 };
628596
629 {597 {
630 try free_ni.resize(mf, gpa, opts.add_node.size);598 try mf.realignNode(gpa, free_ni, opts.add_node.alignment, .{});
599 try mf.resizeNode(gpa, free_ni, opts.add_node.size);
631 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);600 if (opts.add_node.moved or opts.add_node.resized) try mf.updates.ensureUnusedCapacity(gpa, 1);
632 free_node.flags.moved = false;601 free_node.flags.moved = false;
633 free_node.flags.resized = false;602 free_node.flags.resized = false;
634 }603 }
635 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);604 if (opts.add_node.moved) free_ni.movedAssumeCapacity(mf);
636 if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf);605 if (opts.add_node.resized) free_ni.resizedAssumeCapacity(mf);
606 mf.updateWriters();
637 return free_ni;607 return free_ni;
638}608}
639609
...@@ -658,7 +628,15 @@ pub fn addOnlyChildNode(...@@ -658,7 +628,15 @@ pub fn addOnlyChildNode(
658 return mf.addNode(gpa, .{628 return mf.addNode(gpa, .{
659 .parent = parent_ni,629 .parent = parent_ni,
660 .add_node = opts,630 .add_node = opts,
661 });631 }) catch |err| switch (err) {
632 error.OutOfMemory,
633 error.Canceled,
634 => |e| return e,
635 else => |e| {
636 mf.io_err = e;
637 return error.MappedFileIo;
638 },
639 };
662}640}
663641
664pub fn addFirstChildNode(642pub fn addFirstChildNode(
...@@ -673,7 +651,15 @@ pub fn addFirstChildNode(...@@ -673,7 +651,15 @@ pub fn addFirstChildNode(
673 .parent = parent_ni,651 .parent = parent_ni,
674 .next = parent.first,652 .next = parent.first,
675 .add_node = opts,653 .add_node = opts,
676 });654 }) catch |err| switch (err) {
655 error.OutOfMemory,
656 error.Canceled,
657 => |e| return e,
658 else => |e| {
659 mf.io_err = e;
660 return error.MappedFileIo;
661 },
662 };
677}663}
678664
679pub fn addLastChildNode(665pub fn addLastChildNode(
...@@ -695,7 +681,15 @@ pub fn addLastChildNode(...@@ -695,7 +681,15 @@ pub fn addLastChildNode(
695 },681 },
696 },682 },
697 .add_node = opts,683 .add_node = opts,
698 });684 }) catch |err| switch (err) {
685 error.OutOfMemory,
686 error.Canceled,
687 => |e| return e,
688 else => |e| {
689 mf.io_err = e;
690 return error.MappedFileIo;
691 },
692 };
699}693}
700694
701pub fn addNodeAfter(695pub fn addNodeAfter(
...@@ -714,7 +708,15 @@ pub fn addNodeAfter(...@@ -714,7 +708,15 @@ pub fn addNodeAfter(
714 .next = prev.next,708 .next = prev.next,
715 .offset = prev_offset + prev_size,709 .offset = prev_offset + prev_size,
716 .add_node = opts,710 .add_node = opts,
717 });711 }) catch |err| switch (err) {
712 error.OutOfMemory,
713 error.Canceled,
714 => |e| return e,
715 else => |e| {
716 mf.io_err = e;
717 return error.MappedFileIo;
718 },
719 };
718}720}
719721
720fn shrinkNode(722fn shrinkNode(
...@@ -1043,26 +1045,20 @@ fn realignNode(...@@ -1043,26 +1045,20 @@ fn realignNode(
1043 new_alignment: std.mem.Alignment,1045 new_alignment: std.mem.Alignment,
1044 opts: Node.Index.RealignNodeOptions,1046 opts: Node.Index.RealignNodeOptions,
1045) (Allocator.Error || Io.Cancelable || IoError)!void {1047) (Allocator.Error || Io.Cancelable || IoError)!void {
1046 assert(ni != Node.Index.root); // currently unsupported
1047 mf.nodes_lock.assertUnlocked();1048 mf.nodes_lock.assertUnlocked();
10481049
1049 const node = ni.get(mf);1050 const node = ni.get(mf);
1050 const old_offset, const size = node.location().resolve(mf);1051 {
10511052 const prev_alignment = node.flags.alignment;
1052 assert(new_alignment.compare(.gt, node.flags.alignment));1053 node.flags.alignment = new_alignment;
10531054 if (new_alignment.compare(.lte, prev_alignment)) return;
1054 const prev_alignment = node.flags.alignment;
1055 node.flags.alignment = new_alignment;
1056 defer {
1057 // alignment needs to be temporarily set for the resizes below
1058 if (!opts.set_alignment) node.flags.alignment = prev_alignment;
1059 }1055 }
10601056
1061 const new_size = node.flags.alignment.forward(@intCast(size));1057 const old_offset, const size = node.location().resolve(mf);
1062 if (new_alignment.check(@intCast(old_offset))) {1058 if (ni == Node.Index.root) return mf.resizeNode(gpa, ni, size);
1063 if (new_size > size) try mf.resizeNode(gpa, ni, new_size);1059
1064 return;1060 const new_size = new_alignment.forward(@intCast(size));
1065 }1061 if (new_alignment.check(@intCast(old_offset))) return mf.resizeNode(gpa, ni, new_size);
10661062
1067 _, const parent_size = node.parent.location(mf).resolve(mf);1063 _, const parent_size = node.parent.location(mf).resolve(mf);
1068 const trailing_end = trailing_end: switch (node.next) {1064 const trailing_end = trailing_end: switch (node.next) {
...@@ -1122,7 +1118,7 @@ fn realignNode(...@@ -1122,7 +1118,7 @@ fn realignNode(
11221118
1123 ni.setLocationAssumeCapacity(mf, forward_offset, new_size);1119 ni.setLocationAssumeCapacity(mf, forward_offset, new_size);
1124 } else {1120 } else {
1125 const temp_size = node.flags.alignment.forward(@intCast(new_size + 1));1121 const temp_size = new_alignment.forward(@intCast(new_size + 1));
1126 try mf.resizeNode(gpa, ni, temp_size);1122 try mf.resizeNode(gpa, ni, temp_size);
1127 const new_offset, _ = ni.location(mf).resolve(mf);1123 const new_offset, _ = ni.location(mf).resolve(mf);
11281124
...@@ -1148,6 +1144,14 @@ fn realignNode(...@@ -1148,6 +1144,14 @@ fn realignNode(
1148 }1144 }
1149}1145}
11501146
1147fn updateWriters(mf: *MappedFile) void {
1148 var writers_it = mf.writers.first;
1149 while (writers_it) |writer_node| : (writers_it = writer_node.next) {
1150 const w: *Node.Writer = @fieldParentPtr("writer_node", writer_node);
1151 w.interface.buffer = w.ni.slice(mf);
1152 }
1153}
1154
1151fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void {1155fn moveRange(mf: *MappedFile, old_file_offset: u64, new_file_offset: u64, size: u64) (Io.Cancelable || IoError)!void {
1152 // make a copy of this node at the new location1156 // make a copy of this node at the new location
1153 try mf.copyRange(old_file_offset, new_file_offset, size);1157 try mf.copyRange(old_file_offset, new_file_offset, size);