File 0223-compiler-Fix-inplace-tuple-updates-for-an-edge-case.patch of Package erlang

From da168c7c3eb57c875d39026d4c32a0252004ed24 Mon Sep 17 00:00:00 2001
From: Isabell Huang <isabell@erlang.org>
Date: Wed, 3 Dec 2025 11:15:47 +0100
Subject: [PATCH] compiler: Fix inplace tuple updates for an edge case

Fix https://github.com/erlang/otp/issues/10367.
This reverts a30e40ee9ae41ec50128bb5e89f631cfb30dccda.
In certain edge cases, aggregates are incorrectly marked as unique
when their contained records are not unique. This leads to unsafe
destructive updates and strange runtime behaviours.

If there is a less conservative fix that is more specific for this
edge case, we can revisit.
---
 lib/compiler/src/beam_ssa_ss.erl              |  7 +----
 .../test/beam_ssa_check_SUITE_data/alias.erl  | 27 +++++++++----------
 .../tuple_inplace_checks.erl                  | 23 ++++++++++++++--
 3 files changed, 34 insertions(+), 23 deletions(-)

diff --git a/lib/compiler/src/beam_ssa_ss.erl b/lib/compiler/src/beam_ssa_ss.erl
index db3163e597..f0ef95da45 100644
--- a/lib/compiler/src/beam_ssa_ss.erl
+++ b/lib/compiler/src/beam_ssa_ss.erl
@@ -645,12 +645,7 @@ set_alias([], State) ->
     State.
 
 get_alias_edges(V, State) ->
-    OutEdges = [To
-                || {#b_var{},To,Kind} <- beam_digraph:out_edges(State, V),
-                   case Kind of
-                       {embed,_} -> false;
-                       _ -> true
-                   end],
+    OutEdges = [To || {#b_var{},To,_} <- beam_digraph:out_edges(State, V)],
     EmbedEdges = [Src
                   || {#b_var{}=Src,_,Lbl} <- beam_digraph:in_edges(State, V),
                      case Lbl of
diff --git a/lib/compiler/test/beam_ssa_check_SUITE_data/alias.erl b/lib/compiler/test/beam_ssa_check_SUITE_data/alias.erl
index 068426c4cb..2a2547c5f5 100644
--- a/lib/compiler/test/beam_ssa_check_SUITE_data/alias.erl
+++ b/lib/compiler/test/beam_ssa_check_SUITE_data/alias.erl
@@ -831,13 +831,12 @@ aliased_pair_tl_instr(Ls) ->
 aliasing_after_tuple_extract(N) ->
     aliasing_after_tuple_extract(N, {<<>>, dummy}).
 
-%% Check that the Acc tuple is unique on entry, but that the elements
-%% are aliased.
+%% Check that both the tuple (Acc) and the extracted element (X) are
+%% aliased.
 aliasing_after_tuple_extract(0, Acc) ->
 %ssa% (_,Acc) when post_ssa_opt ->
-%ssa% X = get_tuple_element(Acc, 0) {unique => [Acc]},
-%ssa% Bin = bs_create_bin(_,_,X,...) {aliased => [X]},
-%ssa% Tuple = put_tuple(Bin, Acc) {aliased => [Bin], unique => [Acc]}.
+%ssa% X = get_tuple_element(Acc, 0) {aliased => [Acc]},
+%ssa% _ = bs_create_bin(_,_,X,...) {aliased => [X]}.
     Acc;
 aliasing_after_tuple_extract(N, Acc) ->
     {X,_} = Acc,
@@ -853,9 +852,8 @@ alias_after_pair_hd(0, Acc) ->
     Acc;
 alias_after_pair_hd(N, Acc) ->
 %ssa% (_,Acc) when post_ssa_opt ->
-%ssa% X = get_hd(Acc) {unique => [Acc]},
-%ssa% Bin = bs_create_bin(_,_,X,...) {aliased => [X]},
-%ssa% Tuple = put_list(Bin, Acc) {aliased => [Bin], unique => [Acc]}.
+%ssa% X = get_hd(Acc) {aliased => [Acc]},
+%ssa% _ = bs_create_bin(_,_,X,...) {aliased => [X]}.
     [X|_] = Acc,
     alias_after_pair_hd(N - 1, [<<X/bitstring, 1>>|Acc]).
 
@@ -868,9 +866,8 @@ alias_after_pair_tl(0, Acc) ->
     Acc;
 alias_after_pair_tl(N, Acc) ->
 %ssa% (_,Acc) when post_ssa_opt ->
-%ssa% X = get_tl(Acc) {unique => [Acc]},
-%ssa% Bin = bs_create_bin(_,_,X,...) {aliased => [X]},
-%ssa% Tuple = put_list(Acc, Bin) {aliased => [Bin], unique => [Acc]}.
+%ssa% X = get_tl(Acc) {aliased => [Acc]},
+%ssa% _ = bs_create_bin(_,_,X,...) {aliased => [X]}.
     [_|X] = Acc,
     alias_after_pair_tl(N - 1, [Acc|<<X/bitstring, 1>>]).
 
@@ -1204,8 +1201,8 @@ nested_tuple_inner() ->
 
 nested_tuple() ->
 %ssa% () when post_ssa_opt ->
-%ssa% U = bs_create_bin(append, _, T, ...) { unique => [T] },
-%ssa% R = put_tuple(U, A) { aliased => [A], unique => [U] },
+%ssa% U = bs_create_bin(append, _, T, ...) { aliased => [T] },
+%ssa% R = put_tuple(U, A) { aliased => [U, A] },
 %ssa% ret(R).
     {{{{Z,X}}}} = nested_tuple_inner(),
     {<<Z/binary, 1:8>>,X}.
@@ -1228,8 +1225,8 @@ nested_mixed_inner() ->
 
 nested_mixed() ->
 %ssa% () when post_ssa_opt ->
-%ssa% U = bs_create_bin(append, _, T, ...) { unique => [T] },
-%ssa% R = put_tuple(U, A) { aliased => [A], unique => [U] },
+%ssa% U = bs_create_bin(append, _, T, ...) { aliased => [T] },
+%ssa% R = put_tuple(U, A) { aliased => [U, A] },
 %ssa% ret(R).
     [{[{Z,X}]}] = nested_mixed_inner(),
     {<<Z/binary, 1:8>>,X}.
diff --git a/lib/compiler/test/beam_ssa_check_SUITE_data/tuple_inplace_checks.erl b/lib/compiler/test/beam_ssa_check_SUITE_data/tuple_inplace_checks.erl
index 74af653f5b..f5cb7b1268 100644
--- a/lib/compiler/test/beam_ssa_check_SUITE_data/tuple_inplace_checks.erl
+++ b/lib/compiler/test/beam_ssa_check_SUITE_data/tuple_inplace_checks.erl
@@ -25,7 +25,8 @@
 -export([do0a/0, do0b/2, different_sizes/2, ambiguous_inits/1,
          update_record0/0, fc/0, track_update_record/1,
          gh8124_a/0, gh8124_b/0, tuple_set_a/1, tuple_set_b/0,
-         failure_to_patch_list/0, erierl1208/0, gh_9903/0]).
+         failure_to_patch_list/0, erierl1208/0, gh_9903/0,
+         gh10367/0]).
 -record(r, {a=0,b=0,c=0,tot=0}).
 -record(r1, {a}).
 -record(r2, {b}).
@@ -279,7 +280,7 @@ tuple_set_a(Something) ->
 
 tuple_set_b() ->
 %ssa% () when post_ssa_opt ->
-%ssa% _ = update_record(inplace, 2, _, ...).
+%ssa% _ = update_record(copy, 2, _, ...).
     case tuple_set_a(ex:f()) of
 	{ok, A} ->
 	    case e:f() of
@@ -315,3 +316,21 @@ ftpl(Ts0) ->
 %ssa% _ = update_record(inplace, 5, X,...).
     A = erlang:timestamp(),
     Ts0#r{a=A}.
+
+gh10367_gen() ->
+    [#r4{a = a}, #r4{a = b, b = dict:new()}].
+
+gh10367_update([_, #r4{a = b} = P2]) ->
+%ssa% (X) when post_ssa_opt ->
+%ssa% _ = update_record(copy, 3, _, ...).
+    P2#r4{a = a};
+gh10367_update([_, #r4{a = a} = P2]) ->
+    P2#r4{a = b}.
+
+gh10367() ->
+%ssa% () when post_ssa_opt ->
+%ssa% _ = update_record(reuse, 3, _, ...).
+    [P1, P2] = gh10367_gen(),
+    Expected = P2#r4{a = a},
+    timer:sleep(0),
+    Expected = gh10367_update([P1, P2]).
-- 
2.51.0

openSUSE Build Service is sponsored by