File 4041-Remove-catch-in-supervisor.patch of Package erlang
From 14cd0741973a8a853fb7e16f1af22ec2fe7ffcc2 Mon Sep 17 00:00:00 2001
From: Maria Scott <maria-12648430@hnc-agency.org>
Date: Mon, 9 Mar 2026 13:24:52 +0100
Subject: [PATCH] Remove catch in supervisor
Co-authored-by: Jan Uhlig <juhlig@hnc-agency.org>
---
lib/stdlib/src/supervisor.erl | 77 +++++++++++++++++-----------
lib/stdlib/test/supervisor_SUITE.erl | 29 ++++++-----
2 files changed, 61 insertions(+), 45 deletions(-)
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 41e622be7c..c9ba52cfd7 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -292,8 +292,6 @@ but the map is preferred.
`m:gen_event`, `m:gen_statem`, `m:gen_server`, `m:sys`
""".
--compile(nowarn_deprecated_catch).
-
-behaviour(gen_server).
%% External exports
@@ -1034,19 +1032,31 @@ do_start_child(SupName, Child, Report) ->
end.
do_start_child_i(M, F, A) ->
- case catch apply(M, F, A) of
- {ok, Pid} when is_pid(Pid) ->
- {ok, Pid};
- {ok, Pid, Extra} when is_pid(Pid) ->
- {ok, Pid, Extra};
- ignore ->
- {ok, undefined};
- {error, Error} ->
- {error, Error};
- What ->
- {error, What}
+ try
+ apply(M, F, A)
+ of
+ Result ->
+ handle_do_start_child_i_result(Result)
+ catch
+ throw:Result ->
+ handle_do_start_child_i_result(Result);
+ exit:Reason ->
+ {error, {'EXIT', Reason}};
+ error:Reason:StackTrace ->
+ {error, {'EXIT', {Reason, StackTrace}}}
end.
+handle_do_start_child_i_result({ok, Pid} = Result) when is_pid(Pid) ->
+ Result;
+handle_do_start_child_i_result({ok, Pid, _Extra} = Result) when is_pid(Pid) ->
+ Result;
+handle_do_start_child_i_result(ignore) ->
+ {ok, undefined};
+handle_do_start_child_i_result({error, _Reason} = Error) ->
+ Error;
+handle_do_start_child_i_result(Other) ->
+ {error, Other}.
+
%%% ---------------------------------------------------
%%%
%%% Callback functions.
@@ -2022,7 +2032,7 @@ set_flags(Flags, State) ->
period = Period,
auto_shutdown = AutoShutdown}}
catch
- Thrown -> Thrown
+ throw:Thrown -> Thrown
end.
check_flags(SupFlags) when is_map(SupFlags) ->
@@ -2114,7 +2124,7 @@ check_startspec([ChildSpec|T], Ids, Db, AutoShutdown) ->
%% The error message duplicate_child_name is kept for
%% backwards compatibility, although
%% duplicate_child_id would be more correct.
- true -> {duplicate_child_name, Id};
+ true -> {duplicate_child_name, Id};
false -> check_startspec(T, [Id | Ids], Db#{Id=>Child},
AutoShutdown)
end;
@@ -2124,8 +2134,13 @@ check_startspec([], Ids, Db, _AutoShutdown) ->
{ok, {lists:reverse(Ids),Db}}.
check_childspec(ChildSpec, AutoShutdown) when is_map(ChildSpec) ->
- catch do_check_childspec(maps:merge(?default_child_spec,ChildSpec),
- AutoShutdown);
+ try
+ do_check_childspec(maps:merge(?default_child_spec,ChildSpec),
+ AutoShutdown)
+ catch
+ throw:Error ->
+ Error
+ end;
check_childspec({Id, Func, RestartType, Shutdown, ChildType, Mods},
AutoShutdown) ->
check_childspec(#{id => Id,
@@ -2149,26 +2164,26 @@ do_check_childspec(#{restart := RestartType,
#{start := F} -> F;
_ -> throw(missing_start)
end,
- validId(Id),
- validFunc(Func),
- validRestartType(RestartType),
+ true = validId(Id),
+ true = validFunc(Func),
+ true = validRestartType(RestartType),
Significant = case ChildSpec of
#{significant := Signf} -> Signf;
_ -> false
end,
- validSignificant(Significant, RestartType, AutoShutdown),
- validChildType(ChildType),
+ true = validSignificant(Significant, RestartType, AutoShutdown),
+ true = validChildType(ChildType),
Shutdown = case ChildSpec of
#{shutdown := S} -> S;
#{type := worker} -> 5000;
#{type := supervisor} -> infinity
end,
- validShutdown(Shutdown),
+ true = validShutdown(Shutdown),
Mods = case ChildSpec of
#{modules := Ms} -> Ms;
_ -> {M,_,_} = Func, [M]
end,
- validMods(Mods),
+ true = validMods(Mods),
{ok, #child{id = Id, mfargs = Func, restart_type = RestartType,
significant = Significant, shutdown = Shutdown,
child_type = ChildType, modules = Mods}}.
@@ -2207,13 +2222,13 @@ validShutdown(Shutdown) -> throw({invalid_shutdown, Shutdown}).
validMods(dynamic) -> true;
validMods(Mods) when is_list(Mods) ->
- lists:foreach(fun(Mod) ->
- if
- is_atom(Mod) -> ok;
- true -> throw({invalid_module, Mod})
- end
- end,
- Mods);
+ lists:all(fun
+ (Mod) when is_atom(Mod) ->
+ true;
+ (Mod) ->
+ throw({invalid_module, Mod})
+ end,
+ Mods);
validMods(Mods) -> throw({invalid_modules, Mods}).
child_to_spec(#child{id = Id,
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index afcee3c14d..e2a2f6405a 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -24,6 +24,7 @@
-module(supervisor_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include_lib("stdlib/include/assert.hrl").
%% Testserver specific export
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
@@ -832,8 +833,8 @@ child_adm(Config) when is_list(Config) ->
%% Termination
{error, not_found} = supervisor:terminate_child(sup_test, hej),
- {'EXIT',{noproc,{gen_server,call, _}}} =
- (catch supervisor:terminate_child(foo, child1)),
+ ok = ?assertExit({noproc, {gen_server, call, _}},
+ supervisor:terminate_child(foo, child1)),
ok = supervisor:terminate_child(sup_test, child1),
check_exit_reason(CPid, shutdown),
[{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
@@ -854,8 +855,8 @@ child_adm(Config) when is_list(Config) ->
%% Deletion
{error, running} = supervisor:delete_child(sup_test, child1),
{error, not_found} = supervisor:delete_child(sup_test, hej),
- {'EXIT',{noproc,{gen_server,call, _}}} =
- (catch supervisor:delete_child(foo, child1)),
+ ok = ?assertExit({noproc, {gen_server, call, _}},
+ supervisor:delete_child(foo, child1)),
ok = supervisor:terminate_child(sup_test, child1),
ok = supervisor:delete_child(sup_test, child1),
{error, not_found} = supervisor:restart_child(sup_test, child1),
@@ -863,8 +864,8 @@ child_adm(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test),
%% Start
- {'EXIT',{noproc,{gen_server,call, _}}} =
- (catch supervisor:start_child(foo, Child)),
+ ok = ?assertExit({noproc, {gen_server, call, _}},
+ supervisor:start_child(foo, Child)),
{ok, CPid3} = supervisor:start_child(sup_test, Child),
[{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
[1,1,0,1] = get_child_counts(sup_test),
@@ -874,10 +875,10 @@ child_adm(Config) when is_list(Config) ->
[{child1, CPid3, worker, []}] = supervisor:which_children(sup_test),
[1,1,0,1] = get_child_counts(sup_test),
- {'EXIT',{noproc,{gen_server,call,[foo,which_children,infinity]}}}
- = (catch supervisor:which_children(foo)),
- {'EXIT',{noproc,{gen_server,call,[foo,count_children,infinity]}}}
- = (catch supervisor:count_children(foo)),
+ ok = ?assertExit({noproc, {gen_server, call, [foo, which_children, infinity]}},
+ supervisor:which_children(foo)),
+ ok = ?assertExit({noproc, {gen_server, call, [foo, count_children, infinity]}},
+ supervisor:count_children(foo)),
ok.
%%-------------------------------------------------------------------------
%% The API functions terminate_child/2, delete_child/2 restart_child/2
@@ -898,8 +899,8 @@ child_adm_simple(Config) when is_list(Config) ->
[1,0,0,0] = get_child_counts(sup_test),
%% Start
- {'EXIT',{noproc,{gen_server,call, _}}} =
- (catch supervisor:start_child(foo, [])),
+ ok = ?assertExit({noproc, {gen_server, call, _}},
+ supervisor:start_child(foo, [])),
{ok, CPid1} = supervisor:start_child(sup_test, []),
[{undefined, CPid1, worker, []}] =
supervisor:which_children(sup_test),
@@ -1392,8 +1393,8 @@ temporary_bystander(_Config) ->
terminate(SupPid1, CPid1, child1, normal),
terminate(SupPid2, CPid3, child1, normal),
timer:sleep(350),
- catch link(SupPid1),
- catch link(SupPid2),
+ _ = try link(SupPid1) catch _:_ -> ok end,
+ _ = try link(SupPid2) catch _:_ -> ok end,
%% The supervisor would die attempting to restart child2
true = erlang:is_process_alive(SupPid1),
true = erlang:is_process_alive(SupPid2),
--
2.51.0