authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-06-11 15:15:21-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-06-11 15:24:57-07:00
log4b776ae44139fb1a3601949b60ff580f3f16e73f
tree12ec0ac64d1b2372536cd960229b35ecb78fcbdc
parentd9bd34fd0533295044ffb4160da41f7873aff905

std.Progress: fix race assertion failure

A node may be freed during the execution of this loop, causing there to be a parent reference to a nonexistent node. Without this assignment, this would lead to the map entry containing stale data. By assigning none, the child node with the bad parent pointer will be harmlessly omitted from the tree. Closes #20262

1 files changed, 14 insertions(+), 5 deletions(-)

lib/std/Progress.zig+14-5
......@@ -734,7 +734,7 @@ const Serialized = struct {
734734 const Buffer = struct {
735735 parents: [node_storage_buffer_len]Node.Parent,
736736 storage: [node_storage_buffer_len]Node.Storage,
737 map: [node_storage_buffer_len]Node.Index,
737 map: [node_storage_buffer_len]Node.OptionalIndex,
738738
739739 parents_copy: [node_storage_buffer_len]Node.Parent,
740740 storage_copy: [node_storage_buffer_len]Node.Storage,
......@@ -753,9 +753,11 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {
753753 // Iterate all of the nodes and construct a serializable copy of the state that can be examined
754754 // without atomics.
755755 const end_index = @atomicLoad(u32, &global_progress.node_end_index, .monotonic);
756 const node_parents = global_progress.node_parents[0..end_index];
757 const node_storage = global_progress.node_storage[0..end_index];
758 for (node_parents, node_storage, 0..) |*parent_ptr, *storage_ptr, i| {
756 for (
757 global_progress.node_parents[0..end_index],
758 global_progress.node_storage[0..end_index],
759 serialized_buffer.map[0..end_index],
760 ) |*parent_ptr, *storage_ptr, *map| {
759761 var begin_parent = @atomicLoad(Node.Parent, parent_ptr, .acquire);
760762 while (begin_parent != .unused) {
761763 const dest_storage = &serialized_buffer.storage[serialized_len];
......@@ -766,12 +768,19 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {
766768 if (begin_parent == end_parent) {
767769 any_ipc = any_ipc or (dest_storage.getIpcFd() != null);
768770 serialized_buffer.parents[serialized_len] = begin_parent;
769 serialized_buffer.map[i] = @enumFromInt(serialized_len);
771 map.* = @enumFromInt(serialized_len);
770772 serialized_len += 1;
771773 break;
772774 }
773775
774776 begin_parent = end_parent;
777 } else {
778 // A node may be freed during the execution of this loop, causing
779 // there to be a parent reference to a nonexistent node. Without
780 // this assignment, this would lead to the map entry containing
781 // stale data. By assigning none, the child node with the bad
782 // parent pointer will be harmlessly omitted from the tree.
783 map.* = .none;
775784 }
776785 }
777786