File 0687-Use-alias-to-prevent-internal-message-leak-after-tim.patch of Package erlang

From 8a350bd4199437aee0e066dcd3f76132ead0ba13 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micha=C5=82=20W=C4=85sowski?= <michal@erlang.org>
Date: Thu, 20 Nov 2025 15:42:56 +0100
Subject: [PATCH] Use alias to prevent internal message leak after timeout

---
 lib/mnesia/src/mnesia.hrl            | 11 ++++++++++
 lib/mnesia/src/mnesia_controller.erl | 27 ++++++++++++++---------
 lib/mnesia/src/mnesia_locker.erl     | 22 +++++++++++++++----
 lib/mnesia/src/mnesia_tm.erl         | 32 +++++++++++++++++++++-------
 4 files changed, 70 insertions(+), 22 deletions(-)

diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index 3fcedbfd09..44c89dd313 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -53,6 +53,17 @@
         (try ?ets_lookup_element(mnesia_gvar, Var, 2)
          catch error:_:_Stacktrace -> {'EXIT', _Stacktrace} end)).
 
+-define(unalias_and_flush_msg(Alias, Msg),
+        unalias(Alias),
+        ?flush_msg(Msg)
+       ).
+
+-define(flush_msg(Msg),
+        receive Msg -> ok
+        after 0 -> ok
+        end
+       ).
+
 %% It's important that counter is first, since we compare tid's
 
 -record(tid,
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 0a1e540a8a..ac73a5ded2 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -99,7 +99,7 @@
 	 dump_and_reply/2,
 	 load_and_reply/2,
 	 send_and_reply/2,
-	 wait_for_tables_init/2,
+	 wait_for_tables_init/3,
 	 connect_nodes2/3
 	]).
 
@@ -232,13 +232,16 @@ wait_for_tables(Tabs, Timeout) ->
 do_wait_for_tables(Tabs, 0) ->
     reply_wait(Tabs);
 do_wait_for_tables(Tabs, Timeout) ->
-    Pid = spawn_link(?MODULE, wait_for_tables_init, [self(), Tabs]),
+    Alias = alias([reply]),
+    Pid = spawn_link(?MODULE, wait_for_tables_init, [self(), Alias, Tabs]),
     receive
-	{?SERVER_NAME, Pid, Res} ->
+	{?SERVER_NAME, Alias, Res} ->
 	    Res;
 	{'EXIT', Pid, _} ->
+	    unalias(Alias),
 	    reply_wait(Tabs)
     after Timeout ->
+	    ?unalias_and_flush_msg(Alias, {?SERVER_NAME, Alias, _}),
 	    unlink(Pid),
 	    exit(Pid, timeout),
 	    reply_wait(Tabs)
@@ -256,10 +259,10 @@ reply_wait(Tabs) ->
     catch exit:_ -> {error, {node_not_running, node()}}
     end.
 
-wait_for_tables_init(From, Tabs) ->
+wait_for_tables_init(From, Alias, Tabs) ->
     process_flag(trap_exit, true),
     Res = wait_for_init(From, Tabs, whereis(?SERVER_NAME)),
-    From ! {?SERVER_NAME, self(), Res},
+    Alias ! {?SERVER_NAME, Alias, Res},
     unlink(From),
     exit(normal).
 
@@ -1306,7 +1309,7 @@ handle_info(Msg = {'EXIT', Pid, R}, State) when R /= wait_for_tables_timeout ->
     end;
 
 handle_info({From, get_state}, State) ->
-    From ! {?SERVER_NAME, State},
+    From ! {?SERVER_NAME, From, State},
     noreply(State);
 
 %% No real need for buffering
@@ -1860,12 +1863,14 @@ get_info(Timeout) ->
 	undefined ->
 	    {timeout, Timeout};
 	Pid ->
-	    Pid ! {self(), get_state},
+	    Alias = alias([reply]),
+	    Pid ! {Alias, get_state},
 	    receive
-		{?SERVER_NAME, State = #state{loader_queue=LQ,late_loader_queue=LLQ}} ->
+		{?SERVER_NAME, Alias, State = #state{loader_queue=LQ,late_loader_queue=LLQ}} ->
 		    {info,State#state{loader_queue=gb_trees:to_list(LQ),
 				      late_loader_queue=gb_trees:to_list(LLQ)}}
 	    after Timeout ->
+		    ?unalias_and_flush_msg(Alias, {?SERVER_NAME, Alias, _}),
 		    {timeout, Timeout}
 	    end
     end.
@@ -1875,11 +1880,13 @@ get_workers(Timeout) ->
 	undefined ->
 	    {timeout, Timeout};
 	Pid ->
-	    Pid ! {self(), get_state},
+	    Alias = alias([reply]),
+	    Pid ! {Alias, get_state},
 	    receive
-		{?SERVER_NAME, State = #state{}} ->
+		{?SERVER_NAME, Alias, State = #state{}} ->
 		    {workers, get_loaders(State), get_senders(State), State#state.dumper_pid}
 	    after Timeout ->
+		    ?unalias_and_flush_msg(Alias, {?SERVER_NAME, Alias, _}),
 		    {timeout, Timeout}
 	    end
     end.
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index aa7f94ee9f..44516596b5 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -1126,8 +1126,15 @@ rec_requests([], _Oid, _Store) ->
     ok.
 
 get_held_locks() ->
-    ?MODULE ! {get_table, self(), mnesia_held_locks},
-    Locks = receive {mnesia_held_locks, Ls} -> Ls after 5000 -> [] end,
+    Alias = alias([reply]),
+    ?MODULE ! {get_table, Alias, mnesia_held_locks},
+    Locks = receive
+                {mnesia_held_locks, Ls} ->
+                    Ls
+            after 5000 ->
+                    ?unalias_and_flush_msg(Alias, {mnesia_held_locks, _}),
+                    []
+            end,
     rewrite_locks(Locks, []).
 
 %% Mnesia internal usage only
@@ -1148,8 +1155,15 @@ rewrite_locks([], Acc) ->
     lists:reverse(Acc).
 
 get_lock_queue() ->
-    ?MODULE ! {get_table, self(), mnesia_lock_queue},
-    Q = receive {mnesia_lock_queue, Locks} -> Locks after 5000 -> [] end,
+    Alias = alias([reply]),
+    ?MODULE ! {get_table, Alias, mnesia_lock_queue},
+    Q = receive
+            {mnesia_lock_queue, Locks} ->
+                Locks
+        after 5000 ->
+                ?unalias_and_flush_msg(Alias, {mnesia_lock_queue, _}),
+                []
+        end,
     [{Oid, Op, Pid, Tid, WFT} || {queue, Oid, Tid, Op, Pid, WFT} <- Q].
 
 do_stop() ->
diff --git a/lib/mnesia/src/mnesia_tm.erl b/lib/mnesia/src/mnesia_tm.erl
index 10def6d3d7..e6ec6ea09b 100644
--- a/lib/mnesia/src/mnesia_tm.erl
+++ b/lib/mnesia/src/mnesia_tm.erl
@@ -1108,8 +1108,12 @@ intercept_best_friend([{stop,Fun} | R],Ignore) ->
     ?CATCH(Fun()),
     intercept_best_friend(R,Ignore);
 intercept_best_friend([Pid | R],false) ->
-    Pid ! {activity_ended, undefined, self()},
+    Alias = alias([reply]),
+    Pid ! {activity_ended, undefined, Alias},
     wait_for_best_friend(Pid, 0),
+    unalias(Alias),
+    ?flush_msg({activity_ended, _, Pid}),
+    ?flush_msg({'EXIT', Pid, _}),
     intercept_best_friend(R,true);
 intercept_best_friend([_|R],true) ->
     intercept_best_friend(R,true).
@@ -2049,8 +2053,9 @@ sync_send_dirty(Tid, [Head | Tail], Tab, WaitFor) ->
 	    Res =  do_dirty(Tid, Head),
 	    {WF, Res};
 	true ->
-	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}},
-	    sync_send_dirty(Tid, Tail, Tab, [Node | WaitFor])
+	    Alias = alias([reply]),
+	    {?MODULE, Node} ! {Alias, {sync_dirty, Tid, Head, Tab}},
+	    sync_send_dirty(Tid, Tail, Tab, [{Node, Alias} | WaitFor])
     end;
 sync_send_dirty(_Tid, [], _Tab, WaitFor) ->
     {WaitFor, {'EXIT', {aborted, {node_not_running, WaitFor}}}}.
@@ -2068,9 +2073,10 @@ async_send_dirty(Tid, [Head | Tail], Tab, ReadNode, WaitFor, Res) ->
 	    NewRes =  do_dirty(Tid, Head),
 	    async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, NewRes);
 	ReadNode == Node ->
-	    {?MODULE, Node} ! {self(), {sync_dirty, Tid, Head, Tab}},
+	    Alias = alias([reply]),
+	    {?MODULE, Node} ! {Alias, {sync_dirty, Tid, Head, Tab}},
 	    NewRes = {'EXIT', {aborted, {node_not_running, Node}}},
-	    async_send_dirty(Tid, Tail, Tab, ReadNode, [Node | WaitFor], NewRes);
+	    async_send_dirty(Tid, Tail, Tab, ReadNode, [{Node, Alias} | WaitFor], NewRes);
 	true ->
 	    {?MODULE, Node} ! {self(), {async_dirty, Tid, Head, Tab}},
 	    async_send_dirty(Tid, Tail, Tab, ReadNode, WaitFor, Res)
@@ -2078,8 +2084,16 @@ async_send_dirty(Tid, [Head | Tail], Tab, ReadNode, WaitFor, Res) ->
 async_send_dirty(_Tid, [], _Tab, _ReadNode, WaitFor, Res) ->
     {WaitFor, Res}.
 
-rec_dirty([Node | Tail], Res) when Node /= node() ->
-    NewRes = get_dirty_reply(Node, Res),
+rec_dirty([{Node, Alias} | Tail], Res) when Node /= node() ->
+    NewRes =
+        try
+            get_dirty_reply(Node, Res)
+        after
+            unalias(Alias),
+            ?flush_msg({?MODULE, Node, {'EXIT', _}}),
+            ?flush_msg({?MODULE, Node, {dirty_res, _}}),
+            ?flush_msg({mnesia_down, Node})
+        end,
     rec_dirty(Tail, NewRes);
 rec_dirty([], Res) ->
     Res.
@@ -2203,11 +2217,13 @@ get_info(Timeout) ->
 	undefined ->
 	    {timeout, Timeout};
 	Pid ->
-	    Pid ! {self(), info},
+	    Alias = alias([reply]),
+	    Pid ! {Alias, info},
 	    receive
 		{?MODULE, _, {info, Part, Coord}} ->
 		    {info, Part, Coord}
 	    after Timeout ->
+		    ?unalias_and_flush_msg(Alias, {?MODULE, _, {info, _, _}}),
 		    {timeout, Timeout}
 	    end
     end.
-- 
2.51.0

openSUSE Build Service is sponsored by