File 0496-kernel-test-Add-preliminary-test-case.patch of Package erlang
From 050c204ddcb031de574e2a8d3a2447306ad280f9 Mon Sep 17 00:00:00 2001
From: Micael Karlberg <bmk@erlang.org>
Date: Mon, 12 Sep 2022 22:15:27 +0200
Subject: [PATCH 2/4] [kernel|test] Add preliminary test case
OTP-18240
---
lib/kernel/test/socket_SUITE.erl | 160 ++++++++++++++++++++++++++++++-
1 file changed, 158 insertions(+), 2 deletions(-)
diff --git a/lib/kernel/test/socket_SUITE.erl b/lib/kernel/test/socket_SUITE.erl
index 054171e22e..15c9206d8e 100644
--- a/lib/kernel/test/socket_SUITE.erl
+++ b/lib/kernel/test/socket_SUITE.erl
@@ -673,7 +673,8 @@
%% Tickets
otp16359_maccept_tcp4/1,
otp16359_maccept_tcp6/1,
- otp16359_maccept_tcpL/1
+ otp16359_maccept_tcpL/1,
+ otp18240_accept_mon_leak_tcp4/1
]).
@@ -2033,7 +2034,8 @@ ttest_ssockt_csockt_cases() ->
tickets_cases() ->
[
- {group, otp16359}
+ {group, otp16359},
+ otp18240_accept_mon_leak_tcp4
].
otp16359_cases() ->
@@ -49635,6 +49635,149 @@ otp16359_maccept_tcp(InitState) ->
Tester]).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% This test case is to verify that we do not leak monitors.
+otp18240_accept_mon_leak_tcp4(Config) when is_list(Config) ->
+ ?TT(?SECS(10)),
+ tc_try(?FUNCTION_NAME,
+ fun() -> has_support_ipv4() end,
+ fun() ->
+ InitState = #{domain => inet,
+ protocol => tcp,
+ num_socks => 10},
+ ok = otp18240_accept_tcp(InitState)
+ end).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+otp18240_accept_tcp(#{domain := Domain,
+ protocol := Proto,
+ num_socks := NumSocks}) ->
+ Self = self(),
+ {Pid, Mon} = spawn_monitor(fun() ->
+ otp18240_acceptor(Self,
+ Domain, Proto,
+ NumSocks)
+ end),
+ otp18240_await_acceptor(Pid, Mon).
+
+otp18240_await_acceptor(Pid, Mon) ->
+ receive
+ {'DOWN', Mon, process, Pid, Info} ->
+ i("acceptor terminated: "
+ "~n ~p", [Info])
+ after 5000 ->
+ i("acceptor info"
+ "~n Refs: ~p"
+ "~n Info: ~p",
+ [monitored_by(Pid), erlang:process_info(Pid)]),
+ otp18240_await_acceptor(Pid, Mon)
+ end.
+
+otp18240_acceptor(Parent, Domain, Proto, NumSocks) ->
+ i("[acceptor] begin with: "
+ "~n Domain: ~p"
+ "~n Protocol: ~p", [Domain, Proto]),
+ MonitoredBy0 = monitored_by(),
+ {ok, LSock} = socket:open(Domain, stream, Proto,
+ #{use_registry => false}),
+ ok = socket:bind(LSock, #{family => inet, port => 0, addr => any}),
+ ok = socket:listen(LSock),
+ MonitoredBy1 = monitored_by(),
+ [LSockMon] = MonitoredBy1 -- MonitoredBy0,
+ i("[acceptor]: listen socket created"
+ "~n Montored By before listen socket: ~p"
+ "~n Montored By after listen socket: ~p"
+ "~n Listen Socket Monitor: ~p"
+ "~n Listen Socket info: ~p",
+ [MonitoredBy0, MonitoredBy1, LSockMon, socket:info(LSock)]),
+
+ {ok, #{port := Port}} = socket:sockname(LSock),
+
+ i("[acceptor] create ~w clients (connectors)", [NumSocks]),
+ _Clients = [spawn_link(fun() ->
+ otp18240_client(CID,
+ Domain, Proto,
+ Port)
+ end) || CID <- lists:seq(1, NumSocks)],
+
+ i("[acceptor] accept ~w connections", [NumSocks]),
+ ServSocks = [otp18240_do_accept(AID, LSock) ||
+ AID <- lists:seq(1, NumSocks)],
+
+ i("[acceptor] close accepted connections when: "
+ "~n Listen Socket info: ~p", [socket:info(LSock)]),
+ _ = [otp18240_do_close(S) || S <- ServSocks],
+
+ %% at this point in time there should be no monitors from NIFs,
+ %% because we're not accepting anything
+ i("[acceptor] check monitor status"),
+ MonitoredBy2 = monitored_by(),
+ MonitoredBy3 = MonitoredBy2 -- [Parent, LSockMon],
+ i("[acceptor] monitor status: "
+ "~n UnRefs: ~p"
+ "~n MonitoredBy2: ~p"
+ "~n MonitoredBy3: ~p",
+ [[Parent, LSockMon], MonitoredBy2, MonitoredBy3]),
+ if
+ ([] =:= MonitoredBy3) ->
+ i("[acceptor] done"),
+ socket:close(LSock),
+ exit(ok);
+ true ->
+ socket:close(LSock),
+ i("[acceptor] Unexpected monitors: "
+ "~n ~p", [MonitoredBy2]),
+ exit({unexpected_monitors, MonitoredBy2})
+ end.
+
+
+otp18240_client(ID, Domain, Proto, PortNo) ->
+ i("[connector ~w] try create connector socket", [ID]),
+ {ok, Sock} = socket:open(Domain, stream, Proto, #{use_registry => false}),
+ ok = socket:bind(Sock, #{family => Domain, port => 0, addr => any}),
+ %% ok = socket:setopt(Sock, otp, debug, true),
+ i("[connector ~w] try connect", [ID]),
+ ok = socket:connect(Sock, #{family => Domain, addr => any, port => PortNo}),
+ i("[connector ~w] connected - now try recv", [ID]),
+ case socket:recv(Sock) of
+ {ok, Data} ->
+ i("[connector ~w] received unexpected data: "
+ "~n ~p", [ID, Data]),
+ (catch socket:close(Sock)),
+ exit('unexpected data');
+ {error, closed} ->
+ i("[connector ~w] expected socket close", [ID]);
+ {error, Reason} ->
+ i("[connector ~w] unexpected error: "
+ "~n ~p", [ID, Reason]),
+ (catch socket:close(Sock))
+ end,
+ i("[connector ~w] done", [ID]),
+ ok.
+
+
+otp18240_do_accept(ID, LSock) ->
+ i("[acceptor ~w] try accept", [ID]),
+ {ok, Sock} = socket:accept(LSock),
+ i("[acceptor ~w] accepted: ~p", [ID, Sock]),
+ {ID, Sock}.
+
+
+otp18240_do_close({ID, Sock}) ->
+ i("[acceptor ~w] try close ~p", [ID, Sock]),
+ case socket:close(Sock) of
+ ok ->
+ i("[acceptor ~w] socket closed", [ID]),
+ ok;
+ {error, Reason} ->
+ i("[acceptor ~w] failed close socket: "
+ "~n ~p", [ID, Reason]),
+ error
+ end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -47852,6 +48000,14 @@ which_local_addr(Domain) ->
?LIB:which_local_addr(Domain).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+monitored_by() ->
+ monitored_by(self()).
+monitored_by(Pid) ->
+ {monitored_by, Refs} = erlang:process_info(Pid, monitored_by),
+ Refs.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
--
2.35.3