File 9331-Rewrite-legacy-catch.patch of Package erlang
From 6b838ff6a6ddcdbfeefa1cd6e17c6cd48bb8c822 Mon Sep 17 00:00:00 2001
From: Raimo Niskanen <raimo@erlang.org>
Date: Thu, 19 Feb 2026 16:36:30 +0100
Subject: [PATCH 1/4] Rewrite legacy `catch`
Rewrite to use `try`...`catch`...`end`.
For unexpected internal exceptions maybe details
in error logging have changed.
The misfeature of explicitly loading module code
for callback modules has been removed to not surprise
embedded mode installations.
A really old and undocumented variant of the open/prepare
callback call without the leading `Peer` argument
has been removed.
---
lib/tftp/src/tftp.hrl | 4 +-
lib/tftp/src/tftp_app.erl | 4 +-
lib/tftp/src/tftp_binary.erl | 36 +++---
lib/tftp/src/tftp_engine.erl | 212 ++++++++++++++++++-----------------
lib/tftp/src/tftp_lib.erl | 30 ++---
5 files changed, 146 insertions(+), 140 deletions(-)
diff --git a/lib/tftp/src/tftp.hrl b/lib/tftp/src/tftp.hrl
index 3c132cc432..9c9adfae35 100644
--- a/lib/tftp/src/tftp.hrl
+++ b/lib/tftp/src/tftp.hrl
@@ -50,6 +50,8 @@
-record(tftp_msg_error, {code, text, details}).
-record(tftp_msg_oack, {options}).
+-record(tftp_decode_error, {reply}).
+
-record(config, {parent_pid = self(),
udp_socket,
udp_options = [binary, {reuseaddr, true}, {active, once}],
diff --git a/lib/tftp/src/tftp_app.erl b/lib/tftp/src/tftp_app.erl
index f1d7190732..c072908d50 100644
--- a/lib/tftp/src/tftp_app.erl
+++ b/lib/tftp/src/tftp_app.erl
@@ -51,9 +51,9 @@ stop(_State) ->
%%====================================================================
get_configuration() ->
- case (catch application:get_env(tftp, services)) of
+ case application:get_env(tftp, services) of
{ok, Services} ->
Services;
- _ ->
+ undefined ->
[]
end.
diff --git a/lib/tftp/src/tftp_binary.erl b/lib/tftp/src/tftp_binary.erl
index 5362331a47..796b0bfcf3 100644
--- a/lib/tftp/src/tftp_binary.erl
+++ b/lib/tftp/src/tftp_binary.erl
@@ -50,8 +50,8 @@
prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initial) ->
%% Client side
IsNativeAscii = is_native_ascii(Initial),
- case catch handle_options(Access, Filename, Mode, SuggestedOptions, IsNativeAscii) of
- {ok, IsNetworkAscii, AcceptedOptions} when Access =:= read, is_binary(Filename) ->
+ try handle_options(Access, Filename, Mode, SuggestedOptions, IsNativeAscii) of
+ {IsNetworkAscii, AcceptedOptions} when Access =:= read, is_binary(Filename) ->
State = #read_state{options = AcceptedOptions,
blksize = lookup_blksize(AcceptedOptions),
bin = Filename,
@@ -59,16 +59,16 @@ prepare(_Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(I
count = byte_size(Filename),
is_native_ascii = IsNativeAscii},
{ok, AcceptedOptions, State};
- {ok, IsNetworkAscii, AcceptedOptions} when Access =:= write, Filename =:= binary ->
+ {IsNetworkAscii, AcceptedOptions} when Access =:= write, Filename =:= binary ->
State = #write_state{options = AcceptedOptions,
blksize = lookup_blksize(AcceptedOptions),
list = [],
is_network_ascii = IsNetworkAscii,
is_native_ascii = IsNativeAscii},
{ok, AcceptedOptions, State};
- {ok, _, _} ->
- {error, {undef, "Illegal callback usage. Mode and filename is incompatible."}};
- {error, {Code, Text}} ->
+ {_, _} ->
+ {error, {undef, "Illegal callback usage. Mode and filename is incompatible."}}
+ catch throw : {Code, Text} ->
{error, {Code, Text}}
end;
prepare(_Peer, _Access, _Bin, _Mode, _SuggestedOptions, _Initial) ->
@@ -88,22 +88,22 @@ open(Peer, Access, Filename, Mode, SuggestedOptions, Initial) when is_list(Initi
end;
open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, read_state) ->
%% Both sides
- case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#read_state.is_native_ascii) of
- {ok, IsNetworkAscii, Options}
+ try handle_options(Access, Filename, Mode, NegotiatedOptions, State#read_state.is_native_ascii) of
+ {IsNetworkAscii, Options}
when Options =:= NegotiatedOptions,
IsNetworkAscii =:= State#read_state.is_network_ascii ->
- {ok, NegotiatedOptions, State};
- {error, {Code, Text}} ->
+ {ok, NegotiatedOptions, State}
+ catch throw : {Code, Text} ->
{error, {Code, Text}}
end;
open(_Peer, Access, Filename, Mode, NegotiatedOptions, State) when is_record(State, write_state) ->
%% Both sides
- case catch handle_options(Access, Filename, Mode, NegotiatedOptions, State#write_state.is_native_ascii) of
- {ok, IsNetworkAscii, Options}
+ try handle_options(Access, Filename, Mode, NegotiatedOptions, State#write_state.is_native_ascii) of
+ {IsNetworkAscii, Options}
when Options =:= NegotiatedOptions,
IsNetworkAscii =:= State#write_state.is_network_ascii ->
- {ok, NegotiatedOptions, State};
- {error, {Code, Text}} ->
+ {ok, NegotiatedOptions, State}
+ catch throw : {Code, Text} ->
{error, {Code, Text}}
end;
open(Peer, Access, Filename, Mode, NegotiatedOptions, State) ->
@@ -171,7 +171,7 @@ abort(Code, Text, State) ->
handle_options(Access, Bin, Mode, Options, IsNativeAscii) ->
IsNetworkAscii = handle_mode(Mode, IsNativeAscii),
Options2 = do_handle_options(Access, Bin, Options),
- {ok, IsNetworkAscii, Options2}.
+ {IsNetworkAscii, Options2}.
handle_mode("netascii", true) -> true;
handle_mode("octet", _IsNativeAscii) -> false;
@@ -202,15 +202,15 @@ do_handle_options(_Access, _Bin, []) ->
handle_integer(Access, Bin, Key, Val, Options, Min, Max) ->
- case catch list_to_integer(Val) of
- {'EXIT', _} ->
- do_handle_options(Access, Bin, Options);
+ try list_to_integer(Val) of
Int when Int >= Min, Int =< Max ->
[{Key, Val} | do_handle_options(Access, Bin, Options)];
Int when Int >= Min, Max =:= infinity ->
[{Key, Val} | do_handle_options(Access, Bin, Options)];
_Int ->
throw({error, {badopt, "Illegal " ++ Key ++ " value " ++ Val}})
+ catch error : _ ->
+ do_handle_options(Access, Bin, Options)
end.
lookup_blksize(Options) ->
diff --git a/lib/tftp/src/tftp_engine.erl b/lib/tftp/src/tftp_engine.erl
index c62bf992c1..e69478032e 100644
--- a/lib/tftp/src/tftp_engine.erl
+++ b/lib/tftp/src/tftp_engine.erl
@@ -153,7 +153,7 @@ daemon_init(Config) when is_record(Config, config),
is_pid(Config#config.parent_pid) ->
process_flag(trap_exit, true),
{Port, UdpOptions} = prepare_daemon_udp(Config),
- case catch gen_udp:open(Port, UdpOptions) of
+ try gen_udp:open(Port, UdpOptions) of
{ok, Socket} ->
{ok, ActualPort} = inet:port(Socket),
proc_lib:init_ack({ok, self()}),
@@ -170,8 +170,8 @@ daemon_init(Config) when is_record(Config, config),
{error, Reason} ->
Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
- exit({gen_udp_open, UdpOptions, Reason});
- Reason ->
+ exit({gen_udp_open, UdpOptions, Reason})
+ catch error : Reason ->
Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [UdpOptions, Reason])),
print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
exit({gen_udp_open, UdpOptions, Reason})
@@ -187,10 +187,10 @@ prepare_daemon_udp(#config{udp_port = Port, udp_options = UdpOptions} = Config)
InitArg = list_to_atom("tftpd_" ++ integer_to_list(Port)),
case init:get_argument(InitArg) of
{ok, [[FdStr]] = Badarg} when is_list(FdStr) ->
- case catch list_to_integer(FdStr) of
- Fd when is_integer(Fd) ->
- {0, [{fd, Fd} | lists:keydelete(ip, 1, UdpOptions)]};
- {'EXIT', _} ->
+ try list_to_integer(FdStr) of
+ Fd ->
+ {0, [{fd, Fd} | lists:keydelete(ip, 1, UdpOptions)]}
+ catch error : _ ->
Text = lists:flatten(io_lib:format("Illegal prebound fd ~p: ~p", [InitArg, Badarg])),
print_debug_info(Config, daemon, open, ?ERROR(open, undef, Text, "")),
exit({badarg, {prebound_fd, InitArg, Badarg}})
@@ -229,24 +229,24 @@ daemon_loop(#daemon_state{config = DaemonConfig,
_ = reply({ok, Info}, Ref, FromPid),
?MODULE:daemon_loop(State);
{{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
- case catch tftp_lib:parse_config(Options, DaemonConfig) of
- {'EXIT', Reason} ->
- _ = reply({error, Reason}, Ref, FromPid),
- ?MODULE:daemon_loop(State);
+ try tftp_lib:parse_config(Options, DaemonConfig) of
DaemonConfig2 when is_record(DaemonConfig2, config) ->
_ = reply(ok, Ref, FromPid),
?MODULE:daemon_loop(State#daemon_state{config = DaemonConfig2})
+ catch error : Reason ->
+ _ = reply({error, Reason}, Ref, FromPid),
+ ?MODULE:daemon_loop(State)
end;
{udp, Socket, RemoteHost, RemotePort, Bin} when is_binary(Bin) ->
_ = inet:setopts(Socket, [{active, once}]),
ServerConfig = DaemonConfig#config{parent_pid = self(),
udp_host = RemoteHost,
udp_port = RemotePort},
- Msg = (catch tftp_lib:decode_msg(Bin)),
- print_debug_info(ServerConfig, daemon, recv, Msg),
- case Msg of
- Req when is_record(Req, tftp_msg_req),
- N =< DaemonConfig#config.max_conn ->
+ DecodedMsg = tftp_lib:decode_msg(Bin),
+ print_debug_info(ServerConfig, daemon, recv, DecodedMsg),
+ case DecodedMsg of
+ #tftp_msg_req{} = Req when
+ N =< DaemonConfig#config.max_conn ->
Peer = peer_info(ServerConfig),
PeerReq = {Peer, Req},
PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
@@ -263,17 +263,17 @@ daemon_loop(#daemon_state{config = DaemonConfig,
[Pid, PeerInfo, Req#tftp_msg_req.filename]),
?MODULE:daemon_loop(State)
end;
- Req when is_record(Req, tftp_msg_req) ->
+ #tftp_msg_req{}->
Reply = #tftp_msg_error{code = enospc, text = "Too many connections"},
Peer = peer_info(ServerConfig),
PeerInfo = lists:flatten(io_lib:format("~p", [Peer])),
- warning_msg(DaemonConfig,
+ warning_msg(DaemonConfig,
"Daemon has too many connections (~p)."
"\n\tRejecting request from ~s\n",
[N, PeerInfo]),
send_msg(ServerConfig, daemon, Reply),
?MODULE:daemon_loop(State);
- {'EXIT', Reply} when is_record(Reply, tftp_msg_error) ->
+ #tftp_decode_error{reply = Reply} ->
send_msg(ServerConfig, daemon, Reply),
?MODULE:daemon_loop(State);
Req ->
@@ -485,14 +485,13 @@ client_prepare(Config, Callback, Req) when is_record(Req, tftp_msg_req) ->
client_open(Config, Callback, Req, BlockNo, #transfer_res{status = Status, decoded_msg = DecodedMsg, prepared = Prepared}) ->
{LocalAccess, _} = local_file_access(Req),
- case Status of
- ok when is_record(Prepared, prepared) ->
+ case Prepared of
+ #prepared{} when Status =:= ok ->
case DecodedMsg of
- Msg when is_record(Msg, tftp_msg_oack) ->
- ServerOptions = Msg#tftp_msg_oack.options,
+ #tftp_msg_oack{options = ServerOptions} ->
OptText = "Protocol violation. Server is not allowed new options",
case post_verify_options(Config, Req, ServerOptions, OptText) of
- {ok, Config2, Req2} ->
+ {ok, Config2, Req2} ->
{Config3, Callback2, Req3} =
do_client_open(Config2, Callback, Req2),
case LocalAccess of
@@ -525,7 +524,8 @@ client_open(Config, Callback, Req, BlockNo, #transfer_res{status = Status, decod
#tftp_msg_error{code = Code, text = Text} ->
_ = callback({abort, {Code, Text}}, Config, Callback, Req),
terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
- {'EXIT', #tftp_msg_error{code = Code, text = Text}} ->
+ #tftp_decode_error{
+ reply = #tftp_msg_error{code = Code, text = Text}} ->
_ = callback({abort, {Code, Text}}, Config, Callback, Req),
terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename));
Msg when is_tuple(Msg) ->
@@ -537,8 +537,7 @@ client_open(Config, Callback, Req, BlockNo, #transfer_res{status = Status, decod
Text2 = lists:flatten([Text, ". ", io_lib:format("~p", [element(1, Msg)])]),
terminate(Config, Req, ?ERROR(client_open, Code, Text2, Req#tftp_msg_req.filename))
end;
- error when is_record(Prepared, tftp_msg_error) ->
- #tftp_msg_error{code = Code, text = Text} = Prepared,
+ #tftp_msg_error{code = Code, text = Text} when Status =:= error ->
_ = callback({abort, {Code, Text}}, Config, Callback, Req),
terminate(Config, Req, ?ERROR(client_open, Code, Text, Req#tftp_msg_req.filename))
end.
@@ -593,7 +592,9 @@ common_loop(Config, Callback, Req, #transfer_res{status = Status, decoded_msg =
#tftp_msg_error{code = Code, text = Text} ->
_ = callback({abort, {Code, Text}}, Config, Callback, Req),
terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
- {'EXIT', #tftp_msg_error{code = Code, text = Text} = Error} ->
+ #tftp_decode_error{
+ reply = Error =
+ #tftp_msg_error{code = Code, text = Text}} ->
_ = callback({abort, {Code, Text}}, Config, Callback, Req),
send_msg(Config, Req, Error),
terminate(Config, Req, ?ERROR(common_loop, Code, Text, Req#tftp_msg_req.filename));
@@ -789,20 +794,20 @@ open_free_port(Config, Who, Req) when is_record(Config, config), is_record(Req,
case Config#config.port_policy of
random ->
%% BUGBUG: Should be a random port
- case catch gen_udp:open(0, UdpOptions) of
+ try gen_udp:open(0, UdpOptions) of
{ok, Socket} ->
Config2 = Config#config{udp_socket = Socket},
print_debug_info(Config2, Who, open, Req),
{ok, Config2};
{error, Reason} ->
Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
- {'EXIT', _} = Reason ->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
+ catch error : Reason ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[0 | UdpOptions], {'EXIT', Reason}])),
?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
end;
{range, Port, Max} when Port =< Max ->
- case catch gen_udp:open(Port, UdpOptions) of
+ try gen_udp:open(Port, UdpOptions) of
{ok, Socket} ->
Config2 = Config#config{udp_socket = Socket},
print_debug_info(Config2, Who, open, Req),
@@ -813,9 +818,9 @@ open_free_port(Config, Who, Req) when is_record(Config, config), is_record(Req,
open_free_port(Config2, Who, Req);
{error, Reason} ->
Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
- ?ERROR(open, undef, Text, Req#tftp_msg_req.filename);
- {'EXIT', _} = Reason->
- Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], Reason])),
+ ?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
+ catch error : Reason ->
+ Text = lists:flatten(io_lib:format("UDP open ~p -> ~p", [[Port | UdpOptions], {'EXIT', Reason}])),
?ERROR(open, undef, Text, Req#tftp_msg_req.filename)
end;
{range, Port, _Max} ->
@@ -880,14 +885,15 @@ do_wait_for_msg_and_handle_timeout(Config, Callback, Req, Msg, IoList, LocalAcce
end.
send_msg(Config, Req, Msg) ->
- case catch tftp_lib:encode_msg(Msg) of
- {'EXIT', Reason} ->
- Code = undef,
- Text = "Internal error. Encode failed",
- Msg2 = #tftp_msg_error{code = Code, text = Text, details = Reason},
- send_msg(Config, Req, Msg2);
+ try tftp_lib:encode_msg(Msg) of
IoList ->
do_send_msg(Config, Req, Msg, IoList)
+ catch error : Reason : Stacktrace ->
+ Code = undef,
+ Text = "Internal error. Encode failed",
+ Details = {error, Reason, Stacktrace},
+ Msg2 = #tftp_msg_error{code = Code, text = Text, details = Details},
+ send_msg(Config, Req, Msg2)
end.
do_send_msg(#config{udp_socket = Socket, udp_host = RemoteHost, udp_port = RemotePort} = Config, Req, Msg, IoList) ->
@@ -910,15 +916,16 @@ do_send_msg(#config{udp_socket = Socket, udp_host = RemoteHost, udp_port = Remot
%% DumpPath ->
%% trace_udp_send(Req, Msg, IoList, DumpPath)
%% end,
- try
- ok = gen_udp:send(Socket, RemoteHost, RemotePort, IoList)
- catch
- error:{badmatch,{error,einval=Reason}}:StackTrace ->
- error_msg(Config,
- "Stacktrace; ~p\n gen_udp:send(~p, ~p, ~p, ~p) -> ~p\n",
- [StackTrace, Socket, RemoteHost, RemotePort, IoList, {error, Reason}]);
- error:{badmatch,{error,Reason}} ->
- {error, Reason}
+ case gen_udp:send(Socket, RemoteHost, RemotePort, IoList) of
+ ok -> ok;
+ {error, einval} = Error ->
+ StackTrace = try throw(ok) catch throw : ok : ST -> ST end,
+ error_msg(
+ Config,
+ "Stacktrace; ~p\n gen_udp:send(~p, ~p, ~p, ~p) -> ~p\n",
+ [StackTrace, Socket, RemoteHost, RemotePort, IoList, Error]);
+ {error, _} = Error ->
+ Error
end.
%% trace_udp_send(#tftp_msg_req{filename = [$/ | RelFile]} = Req, Msg, IoList, DumpPath) ->
@@ -947,14 +954,14 @@ wait_for_msg(Config, Callback, Req) ->
_ = inet:setopts(Socket, [{active, once}]),
Config2 = Config#config{udp_host = RemoteHost,
udp_port = RemotePort},
- DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
+ DecodedMsg = tftp_lib:decode_msg(Bin),
print_debug_info(Config2, Req, recv, DecodedMsg),
{Config2, DecodedMsg};
{udp, Socket, Host, Port, Bin} when is_binary(Bin),
Config#config.udp_host =:= Host,
Config#config.udp_port =:= Port ->
_ = inet:setopts(Socket, [{active, once}]),
- DecodedMsg = (catch tftp_lib:decode_msg(Bin)),
+ DecodedMsg = tftp_lib:decode_msg(Bin),
print_debug_info(Config, Req, recv, DecodedMsg),
{Config, DecodedMsg};
{info, Ref, FromPid} when is_pid(FromPid) ->
@@ -967,13 +974,14 @@ wait_for_msg(Config, Callback, Req) ->
_ = reply({ok, Info}, Ref, FromPid),
wait_for_msg(Config, Callback, Req);
{{change_config, Options}, Ref, FromPid} when is_pid(FromPid) ->
- case catch tftp_lib:parse_config(Options, Config) of
- {'EXIT', Reason} ->
- _ = reply({error, Reason}, Ref, FromPid),
- wait_for_msg(Config, Callback, Req);
+ try tftp_lib:parse_config(Options, Config) of
Config2 when is_record(Config2, config) ->
_ = reply(ok, Ref, FromPid),
wait_for_msg(Config2, Callback, Req)
+ catch exit : Reason ->
+ _ = reply({error, Reason}, Ref, FromPid),
+ wait_for_msg(Config, Callback, Req)
+
end;
{system, From, Msg} ->
Misc = #sys_misc{module = ?MODULE, function = wait_for_msg, arguments = [Config, Callback, Req]},
@@ -1026,7 +1034,7 @@ do_callback(read = Fun, Config, Callback, Req)
is_record(Req, tftp_msg_req) ->
Args = [Callback#callback.state],
NextBlockNo = Callback#callback.block_no + 1,
- case catch safe_apply(Callback#callback.module, Fun, Args) of
+ case callback_apply(Callback#callback.module, Fun, Args) of
{more, Bin, NewState} when is_binary(Bin) ->
Count = Callback#callback.count + byte_size(Bin),
Callback2 = Callback#callback{state = NewState,
@@ -1060,7 +1068,7 @@ do_callback({write = Fun, Bin}, Config, Callback, Req)
is_binary(Bin) ->
Args = [Bin, Callback#callback.state],
NextBlockNo = Callback#callback.block_no + 1,
- case catch safe_apply(Callback#callback.module, Fun, Args) of
+ case callback_apply(Callback#callback.module, Fun, Args) of
{more, NewState} ->
Count = Callback#callback.count + byte_size(Bin),
Callback2 = Callback#callback{state = NewState,
@@ -1096,19 +1104,13 @@ do_callback({open, Type}, Config, Callback, Req)
server_open -> {open, 0}
end,
Mod = Callback#callback.module,
- Args = [Access,
+ Args = [peer_info(Config),
+ Access,
Filename,
Req#tftp_msg_req.mode,
Req#tftp_msg_req.options,
Callback#callback.state],
- PeerInfo = peer_info(Config),
- _ = fast_ensure_loaded(Mod),
- Args2 =
- case erlang:function_exported(Mod, Fun, length(Args)) of
- true -> Args;
- false -> [PeerInfo | Args]
- end,
- case catch safe_apply(Mod, Fun, Args2) of
+ case callback_apply(Mod, Fun, Args) of
{ok, AcceptedOptions, NewState} ->
Callback2 = Callback#callback{state = NewState,
block_no = BlockNo,
@@ -1132,11 +1134,18 @@ do_callback({abort = Fun, #tftp_msg_error{code = Code, text = Text} = Error}, Co
is_record(Callback, callback),
is_record(Req, tftp_msg_req) ->
Args = [Code, Text, Callback#callback.state],
- catch safe_apply(Callback#callback.module, Fun, Args),
+ _ = callback_apply(Callback#callback.module, Fun, Args),
{undefined, Error};
do_callback({abort, Error}, _Config, undefined, _Req) when is_record(Error, tftp_msg_error) ->
{undefined, Error}.
+callback_apply(Mod, Fun, Args) ->
+ try apply(Mod, Fun, Args) of Result -> Result
+ catch throw : Result -> Result;
+ exit : Reason -> {'EXIT', Reason};
+ error : Reason : Stacktrace -> {'EXIT', {Reason, Stacktrace}}
+ end.
+
peer_info(#config{udp_host = Host, udp_port = Port}) ->
if
tuple_size(Host) =:= 4 ->
@@ -1158,15 +1167,17 @@ match_callback(Filename, Callbacks) ->
end.
do_match_callback(Filename, [C | Tail]) when is_record(C, callback) ->
- case catch re:run(Filename, C#callback.internal, [{capture, none}]) of
+ try re:run(Filename, C#callback.internal, [{capture, none}]) of
match ->
{ok, C};
nomatch ->
- do_match_callback(Filename, Tail);
- Details ->
+ do_match_callback(Filename, Tail)
+ catch error : Reason : Stacktrace ->
+ Details = {error, Reason, Stacktrace},
Code = baduser,
Text = "Internal error. File handler not found",
- {error, #tftp_msg_error{code = Code, text = Text, details = Details}}
+ {error,
+ #tftp_msg_error{code = Code, text = Text, details = Details}}
end;
do_match_callback(Filename, []) ->
Code = baduser,
@@ -1229,7 +1240,7 @@ local_file_access(#tftp_msg_req{access = Access,
pre_verify_options(Config, Req) ->
Options = Req#tftp_msg_req.options,
- case catch verify_reject(Config, Req, Options) of
+ case verify_reject(Config, Req, Options) of
ok ->
case verify_integer("tsize", 0, Config#config.max_tsize, Options) of
true ->
@@ -1267,9 +1278,16 @@ verify_reject(Config, Req, Options) ->
true ->
{error, {eacces, atom_to_list(Access) ++ " mode not allowed"}};
false ->
- [throw({error, {badopt, Key ++ " not allowed"}}) ||
- {Key, _} <- Options, lists:member(Key, Rejected)],
- ok
+ verify_reject(Options, Rejected)
+ end.
+
+verify_reject([], _Rejected) -> ok;
+verify_reject([{Key, _} | Options], Rejected) ->
+ case lists:member(Key, Rejected) of
+ true ->
+ {error, {badopt, Key ++ " not allowed"}};
+ false ->
+ verify_reject(Options, Rejected)
end.
lookup_timeout(Options) ->
@@ -1291,9 +1309,7 @@ lookup_mode(Options) ->
verify_integer(Key, Min, Max, Options) ->
case lists:keysearch(Key, 1, Options) of
{value, {_, Val}} when is_list(Val) ->
- case catch list_to_integer(Val) of
- {'EXIT', _} ->
- false;
+ try list_to_integer(Val) of
Int when Int >= Min, is_integer(Min),
Max =:= infinity ->
true;
@@ -1302,38 +1318,27 @@ verify_integer(Key, Min, Max, Options) ->
true;
_ ->
false
+ catch error : _ ->
+ false
end;
false ->
true
end.
error_msg(#config{logger = Logger, debug_level = _Level}, F, A) ->
- safe_apply(Logger, error_msg, [F, A]).
+ apply(Logger, error_msg, [F, A]).
warning_msg(#config{logger = Logger, debug_level = Level}, F, A) ->
case Level of
none -> ok;
error -> ok;
- _ -> safe_apply(Logger, warning_msg, [F, A])
+ _ -> apply(Logger, warning_msg, [F, A])
end.
info_msg(#config{logger = Logger}, F, A) ->
- safe_apply(Logger, info_msg, [F, A]).
+ apply(Logger, info_msg, [F, A]).
-safe_apply(Mod, Fun, Args) ->
- _ = fast_ensure_loaded(Mod),
- apply(Mod, Fun, Args).
-fast_ensure_loaded(Mod) ->
- case erlang:function_exported(Mod, module_info, 0) of
- true ->
- ok;
- false ->
- Res = code:load_file(Mod),
- %% io:format("tftp: code:load_file(~p) -> ~p\n", [Mod, Res]), %% XXX
- Res
- end.
-
print_debug_info(#config{debug_level = Level} = Config, Who, Where, Data) ->
if
Level =:= none ->
@@ -1370,11 +1375,10 @@ do_print_debug_info(Config, Who, Where, #tftp_msg_req{local_filename = Filename}
do_print_debug_info(Config, Who, Where, Msg2);
do_print_debug_info(Config, Who, Where, Data) ->
Local =
- case catch inet:port(Config#config.udp_socket) of
- {'EXIT', _Reason} ->
- 0;
- {ok, Port} ->
- Port
+ try inet:port(Config#config.udp_socket) of
+ {ok, Port} -> Port;
+ {error, _ } -> 0
+ catch error : _ -> 0
end,
%% Remote = Config#config.udp_port,
PeerInfo = lists:flatten(io_lib:format("~p", [peer_info(Config)])),
diff --git a/lib/tftp/src/tftp_lib.erl b/lib/tftp/src/tftp_lib.erl
index fb8f0ce921..9398a0de39 100644
--- a/lib/tftp/src/tftp_lib.erl
+++ b/lib/tftp/src/tftp_lib.erl
@@ -305,6 +305,12 @@ code_character(N) ->
%%-------------------------------------------------------------------
decode_msg(Bin) when is_binary(Bin) ->
+ try do_decode_msg(Bin)
+ catch throw : Text ->
+ #tftp_decode_error{reply = #tftp_msg_error{code = undef, text = Text}}
+ end.
+
+do_decode_msg(Bin) ->
case Bin of
<<?TFTP_OPCODE_RRQ:16/integer, Tail/binary>> ->
case decode_strings(Tail, [keep_case, lower_case]) of
@@ -315,11 +321,9 @@ decode_msg(Bin) when is_binary(Bin) ->
mode = to_lower(Mode),
options = Options};
[_Filename | _Strings] ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing mode"});
+ throw("Missing mode");
_ ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing filename"})
+ throw("Missing filename")
end;
<<?TFTP_OPCODE_WRQ:16/integer, Tail/binary>> ->
case decode_strings(Tail, [keep_case, lower_case]) of
@@ -330,11 +334,9 @@ decode_msg(Bin) when is_binary(Bin) ->
mode = to_lower(Mode),
options = Options};
[_Filename | _Strings] ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing mode"});
+ throw("Missing mode");
_ ->
- exit(#tftp_msg_error{code = undef,
- text = "Missing filename"})
+ throw("Missing filename")
end;
<<?TFTP_OPCODE_DATA:16/integer, SeqNo:16/integer, Data/binary>> ->
#tftp_msg_data{block_no = SeqNo, data = Data};
@@ -347,16 +349,14 @@ decode_msg(Bin) when is_binary(Bin) ->
#tftp_msg_error{code = ErrorCode2,
text = ErrorText};
_ ->
- exit(#tftp_msg_error{code = undef,
- text = "Trailing garbage"})
+ throw("Trailing garbage")
end;
<<?TFTP_OPCODE_OACK:16/integer, Tail/binary>> ->
Strings = decode_strings(Tail, [lower_case]),
Options = decode_options(Strings),
#tftp_msg_oack{options = Options};
_ ->
- exit(#tftp_msg_error{code = undef,
- text = "Invalid syntax"})
+ throw("Invalid syntax")
end.
decode_strings(Bin, Cases) when is_binary(Bin), is_list(Cases) ->
@@ -384,7 +384,7 @@ decode_string(<<Char:8/integer, Tail/binary>>, Case, String) ->
decode_string(Tail, Case, [Char2 | String])
end;
decode_string(<<>>, _Case, _String) ->
- exit(#tftp_msg_error{code = undef, text = "Trailing null missing"}).
+ throw("Trailing null missing").
decode_options([Key, Value | Strings]) ->
[{to_lower(Key), Value} | decode_options(Strings)];
@@ -403,7 +403,7 @@ decode_error_code(Int) ->
?TFTP_ERROR_BADUSER -> baduser;
?TFTP_ERROR_BADOPT -> badopt;
Int when is_integer(Int), Int >= 0, Int =< 65535 -> Int;
- _ -> exit(#tftp_msg_error{code = undef, text = "Error code outside range."})
+ _ -> throw("Error code outside range.")
end.
%%-------------------------------------------------------------------
--
2.51.0