commit c9601664c6914a8bdbf778f494a0a4fe6d84fa53 (tree)
parent e2c587ae54cba1d2b13b5cbef8530e13fab04c7f
Author: kcbanner <kcbanner@gmail.com>
Date: Sat, 13 Jun 2026 23:40:30 -0400
Coff: fix use of stale header pointer (due to node resize) in addRelocAssumeCapacity
MappedFile: add check to prevent INVAL from fallocate() when realigning nodes that are not aligned to the block size
Diffstat:
2 files changed, 40 insertions(+), 29 deletions(-)
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
@@ -3730,33 +3730,37 @@ fn addRelocAssumeCapacity(
break :sti .none;
} else .none;
- const section = loc_sn.section(coff);
- const header = loc_sn.header(coff);
- const old_num_relocations = coff.targetLoad(&header.number_of_relocations);
- const new_num_relocations = old_num_relocations + 1;
- const new_size = new_num_relocations * std.coff.Relocation.sizeOf();
- if (section.relocation_table_ni == .none) {
- section.relocation_table_ni = try coff.mf.addLastChildNode(
- gpa,
- coff.sectionParent(),
- .{
- .size = new_size,
- .alignment = .@"2",
- .moved = true,
- .resized = true,
- },
- );
- coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });
- } else {
- try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
- }
+ const sri: Section.RelocationIndex = blk: {
+ const section = loc_sn.section(coff);
+ const header = loc_sn.header(coff);
+ const old_num_relocations = coff.targetLoad(&header.number_of_relocations);
+ const new_num_relocations = old_num_relocations + 1;
+ const new_size = new_num_relocations * std.coff.Relocation.sizeOf();
+
+ coff.targetStore(&header.number_of_relocations, new_num_relocations);
+ if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr|
+ coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
+
+ if (section.relocation_table_ni == .none) {
+ section.relocation_table_ni = try coff.mf.addLastChildNode(
+ gpa,
+ coff.sectionParent(),
+ .{
+ .size = new_size,
+ .alignment = .@"2",
+ .moved = true,
+ .resized = true,
+ },
+ );
+ coff.nodes.appendAssumeCapacity(.{ .relocation_table = loc_sn });
+ } else {
+ try section.relocation_table_ni.resize(&coff.mf, gpa, new_size);
+ }
- coff.targetStore(&header.number_of_relocations, new_num_relocations);
- if (coff.symbolTableSectionAuxEntryPtr(loc_sn.symbol(coff).sti(coff))) |aux_ptr|
- coff.targetStore(&aux_ptr.number_of_relocations, new_num_relocations);
+ // TODO: These need to allocate from a free list, once deleting relocs from the table is supported
+ break :blk .wrap(old_num_relocations);
+ };
- // TODO: These need to allocate from a free list, once deleting relocs is supported
- const sri: Section.RelocationIndex = .wrap(old_num_relocations);
const entry = sri.entry(coff, loc_sn).?;
if (sti.unwrap()) |index| coff.targetStore(&entry.symbol_table_index, index);
diff --git a/src/link/MappedFile.zig b/src/link/MappedFile.zig
@@ -799,6 +799,17 @@ fn resizeNode(
if (is_linux and !mf.flags.fallocate_insert_range_unsupported and
node.flags.alignment.order(mf.flags.block_size).compare(.gte))
insert_range: {
+ const range_file_offset = ni.fileLocation(mf, false).offset + old_size;
+ const range_size = node.flags.alignment.forward(
+ @intCast(requested_size +| requested_size / growth_factor),
+ ) - old_size;
+
+ // If this node is being realigned, its current state might not
+ // meet the requirements for fallocate
+ if (!mf.flags.block_size.check(@intCast(range_file_offset)) or
+ !mf.flags.block_size.check(@intCast(range_size)))
+ break :insert_range;
+
mf.memory_map.write(io) catch |err| switch (err) {
error.WouldBlock => return error.Unexpected, // file was not opened as non-blocking
error.NotOpenForWriting => return error.Unexpected, // we definitely opened the file for writing
@@ -808,10 +819,6 @@ fn resizeNode(
const last_offset, const last_size = parent.last.location(mf).resolve(mf);
const last_end = last_offset + last_size;
assert(last_end <= old_parent_size);
- const range_file_offset = ni.fileLocation(mf, false).offset + old_size;
- const range_size = node.flags.alignment.forward(
- @intCast(requested_size +| requested_size / growth_factor),
- ) - old_size;
_, const file_size = Node.Index.root.location(mf).resolve(mf);
while (true) switch (linux.errno(switch (std.math.order(range_file_offset, file_size)) {
.lt => linux.fallocate(