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 {...@@ -734,7 +734,7 @@ const Serialized = struct {
734 const Buffer = struct {734 const Buffer = struct {
735 parents: [node_storage_buffer_len]Node.Parent,735 parents: [node_storage_buffer_len]Node.Parent,
736 storage: [node_storage_buffer_len]Node.Storage,736 storage: [node_storage_buffer_len]Node.Storage,
737 map: [node_storage_buffer_len]Node.Index,737 map: [node_storage_buffer_len]Node.OptionalIndex,
738738
739 parents_copy: [node_storage_buffer_len]Node.Parent,739 parents_copy: [node_storage_buffer_len]Node.Parent,
740 storage_copy: [node_storage_buffer_len]Node.Storage,740 storage_copy: [node_storage_buffer_len]Node.Storage,
...@@ -753,9 +753,11 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {...@@ -753,9 +753,11 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {
753 // Iterate all of the nodes and construct a serializable copy of the state that can be examined753 // Iterate all of the nodes and construct a serializable copy of the state that can be examined
754 // without atomics.754 // without atomics.
755 const end_index = @atomicLoad(u32, &global_progress.node_end_index, .monotonic);755 const end_index = @atomicLoad(u32, &global_progress.node_end_index, .monotonic);
756 const node_parents = global_progress.node_parents[0..end_index];756 for (
757 const node_storage = global_progress.node_storage[0..end_index];757 global_progress.node_parents[0..end_index],
758 for (node_parents, node_storage, 0..) |*parent_ptr, *storage_ptr, i| {758 global_progress.node_storage[0..end_index],
759 serialized_buffer.map[0..end_index],
760 ) |*parent_ptr, *storage_ptr, *map| {
759 var begin_parent = @atomicLoad(Node.Parent, parent_ptr, .acquire);761 var begin_parent = @atomicLoad(Node.Parent, parent_ptr, .acquire);
760 while (begin_parent != .unused) {762 while (begin_parent != .unused) {
761 const dest_storage = &serialized_buffer.storage[serialized_len];763 const dest_storage = &serialized_buffer.storage[serialized_len];
...@@ -766,12 +768,19 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {...@@ -766,12 +768,19 @@ fn serialize(serialized_buffer: *Serialized.Buffer) Serialized {
766 if (begin_parent == end_parent) {768 if (begin_parent == end_parent) {
767 any_ipc = any_ipc or (dest_storage.getIpcFd() != null);769 any_ipc = any_ipc or (dest_storage.getIpcFd() != null);
768 serialized_buffer.parents[serialized_len] = begin_parent;770 serialized_buffer.parents[serialized_len] = begin_parent;
769 serialized_buffer.map[i] = @enumFromInt(serialized_len);771 map.* = @enumFromInt(serialized_len);
770 serialized_len += 1;772 serialized_len += 1;
771 break;773 break;
772 }774 }
773775
774 begin_parent = end_parent;776 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;
775 }784 }
776 }785 }
777786