aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_jump.erl19
-rw-r--r--lib/compiler/test/Makefile1
-rw-r--r--lib/compiler/test/regressions_SUITE.erl98
-rw-r--r--lib/kernel/doc/src/inet.xml30
-rw-r--r--lib/kernel/src/gen_tcp.erl2
-rw-r--r--lib/kernel/src/inet.erl7
-rw-r--r--lib/kernel/src/inet_int.hrl1
-rw-r--r--lib/kernel/src/rpc.erl2
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl315
-rw-r--r--lib/kernel/test/inet_SUITE.erl55
-rw-r--r--lib/mnesia/src/mnesia_loader.erl3
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml7
-rw-r--r--lib/ssh/doc/src/ssh_connection.xml34
-rw-r--r--lib/ssl/test/ssl_ECC_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_alpn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_certificate_verify_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_cipher_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl4
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_npn_handshake_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_npn_hello_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl3
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl1
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl2
-rw-r--r--lib/stdlib/src/supervisor.erl27
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl29
30 files changed, 554 insertions, 114 deletions
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 80b2998ddc..5bfaa41b7d 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -490,16 +490,17 @@ is_label_used_in_1([], _, _) -> false.
is_label_used_in_block({set,_,_,Info}, Lbl) ->
case Info of
- {bif,_,{f,F}} -> F =:= Lbl;
- {alloc,_,{gc_bif,_,{f,F}}} -> F =:= Lbl;
+ {bif,_,{f,F}} -> F =:= Lbl;
+ {alloc,_,{gc_bif,_,{f,F}}} -> F =:= Lbl;
{alloc,_,{put_map,_,{f,F}}} -> F =:= Lbl;
- {'catch',{f,F}} -> F =:= Lbl;
- {alloc,_,_} -> false;
- {put_tuple,_} -> false;
- {get_tuple_element,_} -> false;
- {set_tuple_element,_} -> false;
- {line,_} -> false;
- _ when is_atom(Info) -> false
+ {get_map_elements,{f,F}} -> F =:= Lbl;
+ {'catch',{f,F}} -> F =:= Lbl;
+ {alloc,_,_} -> false;
+ {put_tuple,_} -> false;
+ {get_tuple_element,_} -> false;
+ {set_tuple_element,_} -> false;
+ {line,_} -> false;
+ _ when is_atom(Info) -> false
end.
%% remove_unused_labels(Instructions0) -> Instructions
diff --git a/lib/compiler/test/Makefile b/lib/compiler/test/Makefile
index 98125fc84e..6553d10077 100644
--- a/lib/compiler/test/Makefile
+++ b/lib/compiler/test/Makefile
@@ -33,6 +33,7 @@ MODULES= \
num_bif_SUITE \
receive_SUITE \
record_SUITE \
+ regressions_SUITE \
trycatch_SUITE \
warnings_SUITE \
z_SUITE \
diff --git a/lib/compiler/test/regressions_SUITE.erl b/lib/compiler/test/regressions_SUITE.erl
new file mode 100644
index 0000000000..51bcc5737f
--- /dev/null
+++ b/lib/compiler/test/regressions_SUITE.erl
@@ -0,0 +1,98 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2015. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% Test specific code snippets that has crashed the compiler in the past.
+-module(regressions_SUITE).
+-include_lib("test_server/include/test_server.hrl").
+
+-export([all/0, groups/0, init_per_testcase/2,end_per_testcase/2]).
+
+-export([maps/1]).
+
+groups() ->
+ [{p,test_lib:parallel(),
+ [maps]}].
+
+% Default timetrap timeout (set in init_per_testcase).
+-define(default_timeout, ?t:minutes(2)).
+
+init_per_testcase(_Case, Config) ->
+ ?line Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ ok.
+
+all() ->
+ test_lib:recompile(?MODULE),
+ [{group,p}].
+
+%%% test cases
+
+maps(Config) when is_list(Config) ->
+ Ts = [{beam_bool_get_elements,
+ <<"century(#{ron := operator}, _century) ->
+ if 0.0; _century, _century, _century -> _century end.
+ ">>}],
+ ok = run(Config, Ts),
+ ok.
+
+%% aux
+
+run(Config, Tests) ->
+ F = fun({N,P}) ->
+ io:format("Compiling test for: ~w~n", [N]),
+ case catch run_test(Config, P) of
+ {'EXIT', Reason} ->
+ ?t:format("~nTest ~p failed.~nReason: ~p~n", [N, Reason]),
+ fail();
+ _ -> ok
+ end
+ end,
+ lists:foreach(F, Tests).
+
+
+run_test(Conf, Test0) ->
+ Module = "regressions_"++test_lib:uniq(),
+ Filename = Module ++ ".erl",
+ DataDir = ?config(priv_dir, Conf),
+ Test = ["-module(", Module, "). ", Test0],
+ File = filename:join(DataDir, Filename),
+ Def = [binary,export_all,return],
+ Opts = [ Opt ++ Def ||
+ Opt <- [ [no_postopt],
+ [no_copt],
+ [no_postopt,no_copt],
+ [inline],
+ [inline,no_postopt],
+ []
+ ]],
+ ok = file:write_file(File, Test),
+ lists:foreach(fun(Opt) ->
+ io:format(" - compiling with ~p~n", [Opt]),
+ {ok,_M,_Bin,_} = compile:file(File,Opt)
+ end, Opts),
+ file:delete(File),
+ ok.
+
+fail() ->
+ io:format("failed~n"),
+ ?t:fail().
diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml
index 77a8caaaf6..4dd9e0e221 100644
--- a/lib/kernel/doc/src/inet.xml
+++ b/lib/kernel/doc/src/inet.xml
@@ -1037,6 +1037,36 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp
<marker id="option-sndbuf"></marker>
</item>
+ <tag><c>{show_econnreset, Boolean}</c>(TCP/IP sockets)</tag>
+ <item>
+ <p>When this option is set to <c>false</c>, as it is by
+ default, an RST that is received from the TCP peer is treated
+ as a normal close (as though a FIN was sent). A caller
+ to <seealso marker="gen_tcp#recv/2">gen_tcp:recv/2</seealso>
+ will get <c>{error, closed}</c>. In active
+ mode the controlling process will receive a
+ <c>{tcp_close, Socket}</c> message, indicating that the
+ peer has closed the connection.</p>
+ <p>Setting this option to <c>true</c> will allow you to
+ distinguish between a connection that was closed normally,
+ and one which was aborted (intentionally or unintentionally)
+ by the TCP peer. A call to
+ <seealso marker="gen_tcp#recv/2">gen_tcp:recv/2</seealso>
+ will return <c>{error, econnreset}</c>. In
+ active mode, the controlling process will receive a
+ <c>{tcp_error, Socket, econnreset}</c> message
+ before the usual <c>{tcp_closed, Socket}</c>, as is
+ the case for any other socket error. Calls to
+ <seealso marker="gen_tcp#send/2">gen_tcp:send/2</seealso>
+ will also return <c>{error, econnreset}</c> when it
+ is detected that a TCP peer has sent an RST.</p>
+ <p>A connected socket returned from
+ <seealso marker="gen_tcp#accept/1">gen_tcp:accept/1</seealso>
+ will inherit the <c>show_econnreset</c> setting from the
+ listening socket.</p>
+ <marker id="option-show_econnreset"></marker>
+ </item>
+
<tag><c>{sndbuf, Size}</c></tag>
<item>
<p>The minimum size of the send buffer to use for the socket.
diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl
index bc8ffbe5e3..86251fc8f1 100644
--- a/lib/kernel/src/gen_tcp.erl
+++ b/lib/kernel/src/gen_tcp.erl
@@ -58,6 +58,7 @@
{reuseaddr, boolean()} |
{send_timeout, non_neg_integer() | infinity} |
{send_timeout_close, boolean()} |
+ {show_econnreset, boolean()} |
{sndbuf, non_neg_integer()} |
{tos, non_neg_integer()} |
{ipv6_v6only, boolean()}.
@@ -89,6 +90,7 @@
reuseaddr |
send_timeout |
send_timeout_close |
+ show_econnreset |
sndbuf |
tos |
ipv6_v6only.
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index d668738109..1ae90aaf0c 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -654,7 +654,7 @@ options() ->
multicast_if, multicast_ttl, multicast_loop,
exit_on_close, high_watermark, low_watermark,
high_msgq_watermark, low_msgq_watermark,
- send_timeout, send_timeout_close
+ send_timeout, send_timeout_close, show_econnreset
].
%% Return a list of statistics options
@@ -672,7 +672,8 @@ connect_options() ->
[tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay,
header, active, packet, packet_size, buffer, mode, deliver,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
- low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw].
+ low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw,
+ show_econnreset].
connect_options(Opts, Family) ->
BaseOpts =
@@ -740,7 +741,7 @@ listen_options() ->
header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only,
exit_on_close, high_watermark, low_watermark, high_msgq_watermark,
low_msgq_watermark, send_timeout, send_timeout_close, delay_send,
- packet_size, raw].
+ packet_size, raw, show_econnreset].
listen_options(Opts, Family) ->
BaseOpts =
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 889b596a22..7bd973af99 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -147,6 +147,7 @@
-define(INET_LOPT_MSGQ_HIWTRMRK, 36).
-define(INET_LOPT_MSGQ_LOWTRMRK, 37).
-define(INET_LOPT_NETNS, 38).
+-define(INET_LOPT_TCP_SHOW_ECONNRESET, 39).
% Specific SCTP options: separate range:
-define(SCTP_OPT_RTOINFO, 100).
-define(SCTP_OPT_ASSOCINFO, 101).
diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl
index 2300b7e901..d8250418f9 100644
--- a/lib/kernel/src/rpc.erl
+++ b/lib/kernel/src/rpc.erl
@@ -22,7 +22,7 @@
%% facility
%% This code used to reside in net.erl, but has now been moved to
-%% a searate module.
+%% a separate module.
-define(NAME, rex).
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index 76a9708a58..44e7984401 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -31,6 +31,11 @@
init_per_testcase/2, end_per_testcase/2,
otp_3924/1, otp_3924_sender/4, closed_socket/1,
shutdown_active/1, shutdown_passive/1, shutdown_pending/1,
+ show_econnreset_active/1, show_econnreset_active_once/1,
+ show_econnreset_passive/1, econnreset_after_sync_send/1,
+ econnreset_after_async_send_active/1,
+ econnreset_after_async_send_active_once/1,
+ econnreset_after_async_send_passive/1, linger_zero/1,
default_options/1, http_bad_packet/1,
busy_send/1, busy_disconnect_passive/1, busy_disconnect_active/1,
fill_sendq/1, partial_recv_and_close/1,
@@ -94,6 +99,11 @@ all() ->
iter_max_socks, passive_sockets, active_n,
accept_closed_by_other_process, otp_3924, closed_socket,
shutdown_active, shutdown_passive, shutdown_pending,
+ show_econnreset_active, show_econnreset_active_once,
+ show_econnreset_passive, econnreset_after_sync_send,
+ econnreset_after_async_send_active,
+ econnreset_after_async_send_active_once,
+ econnreset_after_async_send_passive, linger_zero,
default_options, http_bad_packet, busy_send,
busy_disconnect_passive, busy_disconnect_active,
fill_sendq, partial_recv_and_close,
@@ -1079,6 +1089,311 @@ shutdown_pending(Config) when is_list(Config) ->
gen_tcp:close(S)
end.
+%%
+%% Test 'show_econnreset' option
+%%
+
+show_econnreset_active(Config) when is_list(Config) ->
+ %% First confirm everything works with option turned off.
+ {ok, L} = gen_tcp:listen(0, []),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = inet:setopts(Client, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(Client),
+ receive
+ {tcp_closed, S} ->
+ ok;
+ Other ->
+ ?t:fail({unexpected1, Other})
+ after 1000 ->
+ ?t:fail({timeout, {server, no_tcp_closed}})
+ end,
+
+ %% Now test with option switched on.
+ %% Note: We are also testing that the show_econnreset option is
+ %% inherited from the listening socket by the accepting socket.
+ {ok, L1} = gen_tcp:listen(0, [{show_econnreset, true}]),
+ {ok, Port1} = inet:port(L1),
+ {ok, Client1} = gen_tcp:connect(localhost, Port1, [{active, false}]),
+ {ok, S1} = gen_tcp:accept(L1),
+ ok = gen_tcp:close(L1),
+ ok = inet:setopts(Client1, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(Client1),
+ receive
+ {tcp_error, S1, econnreset} ->
+ receive
+ {tcp_closed, S1} ->
+ ok;
+ Other1 ->
+ ?t:fail({unexpected2, Other1})
+ after 1 ->
+ ?t:fail({timeout, {server, no_tcp_closed}})
+ end;
+ Other2 ->
+ ?t:fail({unexpected3, Other2})
+ after 1000 ->
+ ?t:fail({timeout, {server, no_tcp_error}})
+ end.
+
+show_econnreset_active_once(Config) when is_list(Config) ->
+ %% Now test using {active, once}
+ {ok, L} = gen_tcp:listen(0,
+ [{active, false},
+ {show_econnreset, true}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = inet:setopts(Client, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(Client),
+ ok = ?t:sleep(20),
+ ok = receive Msg -> {unexpected_msg, Msg} after 0 -> ok end,
+ ok = inet:setopts(S, [{active, once}]),
+ receive
+ {tcp_error, S, econnreset} ->
+ receive
+ {tcp_closed, S} ->
+ ok;
+ Other1 ->
+ ?t:fail({unexpected1, Other1})
+ after 1 ->
+ ?t:fail({timeout, {server, no_tcp_closed}})
+ end;
+ Other2 ->
+ ?t:fail({unexpected2, Other2})
+ after 1000 ->
+ ?t:fail({timeout, {server, no_tcp_error}})
+ end.
+
+show_econnreset_passive(Config) when is_list(Config) ->
+ %% First confirm everything works with option turned off.
+ {ok, L} = gen_tcp:listen(0, [{active, false}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = inet:setopts(S, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S),
+ ok = ?t:sleep(1),
+ {error, closed} = gen_tcp:recv(Client, 0),
+
+ %% Now test with option switched on.
+ {ok, L1} = gen_tcp:listen(0, [{active, false}]),
+ {ok, Port1} = inet:port(L1),
+ {ok, Client1} = gen_tcp:connect(localhost, Port1,
+ [{active, false},
+ {show_econnreset, true}]),
+ {ok, S1} = gen_tcp:accept(L1),
+ ok = gen_tcp:close(L1),
+ ok = inet:setopts(S1, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S1),
+ ok = ?t:sleep(1),
+ {error, econnreset} = gen_tcp:recv(Client1, 0).
+
+econnreset_after_sync_send(Config) when is_list(Config) ->
+ %% First confirm everything works with option turned off.
+ {ok, L} = gen_tcp:listen(0, [{active, false}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port, [{active, false}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = inet:setopts(S, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S),
+ ok = ?t:sleep(20),
+ {error, closed} = gen_tcp:send(Client, "Whatever"),
+
+ %% Now test with option switched on.
+ {ok, L1} = gen_tcp:listen(0, [{active, false}]),
+ {ok, Port1} = inet:port(L1),
+ {ok, Client1} = gen_tcp:connect(localhost, Port1,
+ [{active, false},
+ {show_econnreset, true}]),
+ {ok, S1} = gen_tcp:accept(L1),
+ ok = gen_tcp:close(L1),
+ ok = inet:setopts(S1, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S1),
+ ok = ?t:sleep(20),
+ {error, econnreset} = gen_tcp:send(Client1, "Whatever").
+
+econnreset_after_async_send_active(Config) when is_list(Config) ->
+ {OS, _} = os:type(),
+ Payload = lists:duplicate(1024 * 1024, $.),
+
+ %% First confirm everything works with option turned off.
+ {ok, L} = gen_tcp:listen(0, [{active, false}, {recbuf, 4096}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port, [{sndbuf, 4096}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = gen_tcp:send(Client, Payload),
+ case erlang:port_info(Client, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ?t:fail(T)
+ end,
+ ok = gen_tcp:send(S, "Whatever"),
+ ok = ?t:sleep(20),
+ ok = inet:setopts(S, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S),
+ ok = ?t:sleep(20),
+ receive
+ {tcp, Client, "Whatever"} ->
+ receive
+ {tcp_closed, Client} ->
+ ok;
+ Other1 ->
+ ?t:fail({unexpected1, Other1})
+ end;
+ Other2 ->
+ ?t:fail({unexpected2, Other2})
+ end,
+
+ %% Now test with option switched on.
+ {ok, L1} = gen_tcp:listen(0, [{active, false}, {recbuf, 4096}]),
+ {ok, Port1} = inet:port(L1),
+ {ok, Client1} = gen_tcp:connect(localhost, Port1,
+ [{sndbuf, 4096},
+ {show_econnreset, true}]),
+ {ok, S1} = gen_tcp:accept(L1),
+ ok = gen_tcp:close(L1),
+ ok = gen_tcp:send(Client1, Payload),
+ case erlang:port_info(Client1, queue_size) of
+ {queue_size, N1} when N1 > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T1 -> ?t:fail(T1)
+ end,
+ ok = gen_tcp:send(S1, "Whatever"),
+ ok = ?t:sleep(20),
+ ok = inet:setopts(S1, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S1),
+ ok = ?t:sleep(20),
+ receive
+ {tcp, Client1, "Whatever"} ->
+ receive
+ {tcp_error, Client1, econnreset} ->
+ receive
+ {tcp_closed, Client1} ->
+ ok;
+ Other3 ->
+ ?t:fail({unexpected3, Other3})
+ end;
+ Other4 ->
+ ?t:fail({unexpected4, Other4})
+ end;
+ Other5 ->
+ ?t:fail({unexpected5, Other5})
+ end.
+
+econnreset_after_async_send_active_once(Config) when is_list(Config) ->
+ {OS, _} = os:type(),
+ {ok, L} = gen_tcp:listen(0, [{active, false}, {recbuf, 4096}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port,
+ [{active, false},
+ {sndbuf, 4096},
+ {show_econnreset, true}]),
+ {ok,S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ Payload = lists:duplicate(1024 * 1024, $.),
+ ok = gen_tcp:send(Client, Payload),
+ case erlang:port_info(Client, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ?t:fail(T)
+ end,
+ ok = gen_tcp:send(S, "Whatever"),
+ ok = ?t:sleep(20),
+ ok = inet:setopts(S, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(S),
+ ok = ?t:sleep(20),
+ ok = receive Msg -> {unexpected_msg, Msg} after 0 -> ok end,
+ ok = inet:setopts(Client, [{active, once}]),
+ receive
+ {tcp_error, Client, econnreset} ->
+ receive
+ {tcp_closed, Client} ->
+ ok;
+ Other ->
+ ?t:fail({unexpected1, Other})
+ end;
+ Other ->
+ ?t:fail({unexpected2, Other})
+ end.
+
+econnreset_after_async_send_passive(Config) when is_list(Config) ->
+ {OS, _} = os:type(),
+ Payload = lists:duplicate(1024 * 1024, $.),
+
+ %% First confirm everything works with option turned off.
+ {ok, L} = gen_tcp:listen(0, [{active, false}, {recbuf, 4096}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port,
+ [{active, false},
+ {sndbuf, 4096}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ ok = inet:setopts(S, [{linger, {true, 0}}]),
+ ok = gen_tcp:send(S, "Whatever"),
+ ok = gen_tcp:send(Client, Payload),
+ case erlang:port_info(Client, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ?t:fail(T)
+ end,
+ ok = gen_tcp:close(S),
+ ok = ?t:sleep(20),
+ {error, closed} = gen_tcp:recv(Client, 0),
+
+ %% Now test with option switched on.
+ {ok, L1} = gen_tcp:listen(0, [{active, false}, {recbuf, 4096}]),
+ {ok, Port1} = inet:port(L1),
+ {ok, Client1} = gen_tcp:connect(localhost, Port1,
+ [{active, false},
+ {sndbuf, 4096},
+ {show_econnreset, true}]),
+ {ok, S1} = gen_tcp:accept(L1),
+ ok = gen_tcp:close(L1),
+ ok = inet:setopts(S1, [{linger, {true, 0}}]),
+ ok = gen_tcp:send(S1, "Whatever"),
+ ok = gen_tcp:send(Client1, Payload),
+ ok = gen_tcp:close(S1),
+ ok = ?t:sleep(20),
+ {error, econnreset} = gen_tcp:recv(Client1, 0).
+
+%%
+%% Test {linger {true, 0}} aborts a connection
+%%
+
+linger_zero(Config) when is_list(Config) ->
+ %% All the econnreset tests will prove that {linger, {true, 0}} aborts
+ %% a connection when the driver queue is empty. We will test here
+ %% that it also works when the driver queue is not empty.
+ {OS, _} = os:type(),
+ {ok, L} = gen_tcp:listen(0, [{active, false},
+ {recbuf, 4096},
+ {show_econnreset, true}]),
+ {ok, Port} = inet:port(L),
+ {ok, Client} = gen_tcp:connect(localhost, Port,
+ [{active, false},
+ {sndbuf, 4096}]),
+ {ok, S} = gen_tcp:accept(L),
+ ok = gen_tcp:close(L),
+ PayloadSize = 1024 * 1024,
+ Payload = lists:duplicate(PayloadSize, $.),
+ ok = gen_tcp:send(Client, Payload),
+ case erlang:port_info(Client, queue_size) of
+ {queue_size, N} when N > 0 -> ok;
+ {queue_size, 0} when OS =:= win32 -> ok;
+ {queue_size, 0} = T -> ?t:fail(T)
+ end,
+ ok = inet:setopts(Client, [{linger, {true, 0}}]),
+ ok = gen_tcp:close(Client),
+ ok = ?t:sleep(1),
+ undefined = erlang:port_info(Client, connected),
+ {error, econnreset} = gen_tcp:recv(S, PayloadSize).
+
%% Thanks to Luke Gorrie. Tests for a very specific problem with
%% corrupt data. The testcase will be killed by the timetrap timeout
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index c77de9316f..994c4b35f9 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -120,36 +120,37 @@ t_gethostbyaddr() ->
required(v4).
t_gethostbyaddr(doc) -> "Test the inet:gethostbyaddr/1 function.";
t_gethostbyaddr(Config) when is_list(Config) ->
- ?line {Name,FullName,IPStr,{A,B,C,D}=IP,Aliases,_,_} =
- ct:get_config(test_host_ipv4_only),
- ?line Rname = integer_to_list(D) ++ "." ++
- integer_to_list(C) ++ "." ++
- integer_to_list(B) ++ "." ++
- integer_to_list(A) ++ ".in-addr.arpa",
- ?line {ok,HEnt} = inet:gethostbyaddr(IPStr),
- ?line {ok,HEnt} = inet:gethostbyaddr(IP),
- ?line {error,Error} = inet:gethostbyaddr(Name),
- ?line ok = io:format("Failure reason: ~p: ~s",
- [error,inet:format_error(Error)]),
- ?line HEnt_ = HEnt#hostent{h_addrtype = inet,
- h_length = 4,
- h_addr_list = [IP]},
- ?line HEnt_ = HEnt,
+ {Name,FullName,IPStr,{A,B,C,D}=IP,Aliases,_,_} = ct:get_config(test_host_ipv4_only),
+ Rname = integer_to_list(D) ++ "." ++
+ integer_to_list(C) ++ "." ++
+ integer_to_list(B) ++ "." ++
+ integer_to_list(A) ++ ".in-addr.arpa",
+ {ok,HEnt} = inet:gethostbyaddr(IPStr),
+ {ok,HEnt} = inet:gethostbyaddr(IP),
+ {error,Error} = inet:gethostbyaddr(Name),
+ ok = io:format("Failure reason: ~p: ~s", [error,inet:format_error(Error)]),
+ HEnt_ = HEnt#hostent{h_addrtype = inet,
+ h_length = 4,
+ h_addr_list = [IP]},
+ HEnt_ = HEnt,
case {os:type(),os:version()} of
- {{unix,freebsd},{5,0,0}} ->
- %% The alias list seems to be buggy in FreeBSD 5.0.0.
- ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]}]),
- io:format("Buggy alias list: ~p", [HEnt#hostent.h_aliases]),
- ok;
- _ ->
- ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]},
- {HEnt#hostent.h_aliases,[[],Aliases,[Rname]]}])
+ {{unix,freebsd},{5,0,0}} ->
+ %% The alias list seems to be buggy in FreeBSD 5.0.0.
+ check_elems([{HEnt#hostent.h_name,[Name,FullName]}]),
+ io:format("Buggy alias list: ~p", [HEnt#hostent.h_aliases]),
+ ok;
+ _ ->
+ io:format("alias list: ~p", [HEnt#hostent.h_aliases]),
+ io:format("check alias list: ~p", [[Aliases,[Rname]]]),
+ io:format("name: ~p", [HEnt#hostent.h_name]),
+ io:format("check name: ~p", [[Name,FullName]]),
+ check_elems([{HEnt#hostent.h_name,[Name,FullName]},
+ {HEnt#hostent.h_aliases,[[],Aliases,[Rname]]}])
end,
- ?line {_DName, _DFullName, DIPStr, DIP, _, _, _} =
- ct:get_config(test_dummy_host),
- ?line {error,nxdomain} = inet:gethostbyaddr(DIPStr),
- ?line {error,nxdomain} = inet:gethostbyaddr(DIP),
+ {_DName, _DFullName, DIPStr, DIP, _, _, _} = ct:get_config(test_dummy_host),
+ {error,nxdomain} = inet:gethostbyaddr(DIPStr),
+ {error,nxdomain} = inet:gethostbyaddr(DIP),
ok.
t_gethostbyaddr_v6() -> required(v6).
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index 65ea743fd3..492a061f76 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -209,8 +209,7 @@ do_get_network_copy(Tab, Reason, Ns, Storage, Cs) ->
set({Tab, load_node}, Node),
set({Tab, load_reason}, Reason),
mnesia_controller:i_have_tab(Tab),
- dbg_out("Table ~p copied from ~p to ~p (~b entries)~n",
- [Tab, Node, node(), mnesia:table_info(Tab, size)]),
+ dbg_out("Table ~p copied from ~p to ~p~n", [Tab, Node, node()]),
{loaded, ok};
Err = {error, _} when element(1, Reason) == dumper ->
{not_loaded,Err};
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index d31ccd834d..94556b7b51 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -167,7 +167,8 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<item>If the <c>Item</c> is a <c>pid()</c>, the corresponding
process is traced. The process may be a remote process
(on another Erlang node). The node must be in the list of
- traced nodes (<seealso marker="#n">see</seealso><c>n/1</c> and <c>tracer/0/2/3</c>).</item>
+ traced nodes (see <seealso marker="#n"><c>n/1</c></seealso> and
+ <c>tracer/0/2/3</c>).</item>
<item>If the <c>Item</c> is the atom <c>all</c>, all processes in the
system as well as all processes created hereafter are
to be traced. This also affects all nodes added with the
@@ -648,7 +649,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
<p>If <c>Nodename</c> is the local node, the error reason
<c>cant_add_local_node</c> is returned.
</p>
- <p>If a trace port (<seealso marker="#trace_port">see</seealso><c>trace_port/2</c>) is
+ <p>If a trace port (see <seealso marker="#trace_port"><c>trace_port/2</c></seealso>) is
running on the local node, remote nodes can not be traced with
a tracer process. The error reason
<c>cant_trace_remote_pid_to_local_port</c> is returned. A
@@ -761,7 +762,7 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard)\
type which is independent of the tracer on the trace control
node.</p>
</note>
- <p>For details, <seealso marker="#tracer2">see</seealso><c>tracer/2</c>.</p>
+ <p>For details, see <seealso marker="#tracer2"><c>tracer/2</c></seealso>.</p>
</desc>
</func>
<func>
diff --git a/lib/ssh/doc/src/ssh_connection.xml b/lib/ssh/doc/src/ssh_connection.xml
index 5422633dc3..e2b4e2ceb7 100644
--- a/lib/ssh/doc/src/ssh_connection.xml
+++ b/lib/ssh/doc/src/ssh_connection.xml
@@ -85,7 +85,7 @@
<tag><em>data_events()</em></tag>
<item>
<taglist>
- <tag><c><![CDATA[{data, ssh_channel_id(), ssh_data_type_code(), binary() = Data}]]></c></tag>
+ <tag><c><![CDATA[{data, ssh_channel_id(), ssh_data_type_code(), Data :: binary()}]]></c></tag>
<item><p>Data has arrived on the channel. This event is sent as a
result of calling <seealso marker="ssh_connection#send-3">
ssh_connection:send/[3,4,5]</seealso>.</p></item>
@@ -110,15 +110,15 @@
referred to are on OS-level and not something generated by an
Erlang program.</p></item>
- <tag><c><![CDATA[{exit_signal, ssh_channel_id(), string() = ExitSignal, string() = ErrorMsg,
- string() = LanguageString}]]></c></tag>
+ <tag><c><![CDATA[{exit_signal, ssh_channel_id(), ExitSignal :: string(), ErrorMsg ::string(),
+ LanguageString :: string()}]]></c></tag>
<item><p>A remote execution can terminate violently because of a signal.
Then this message can be received. For details on valid string
values, see <url href="http://www.ietf.org/rfc/rfc4254.txt">RFC 4254</url>
Section 6.10, which shows a special case of these signals.</p></item>
- <tag><c><![CDATA[{exit_status, ssh_channel_id(), integer() = ExitStatus}]]></c></tag>
+ <tag><c><![CDATA[{exit_status, ssh_channel_id(), ExitStatus :: integer()}]]></c></tag>
<item><p>When the command running at the other end terminates, the
following message can be sent to return the exit status of the
command. A zero <c>exit_status</c> usually means that the command
@@ -148,18 +148,18 @@
with the boolean value of <c>WantReply</c> as the second argument.</p>
<taglist>
- <tag><c><![CDATA[{env, ssh_channel_id(), boolean() = WantReply,
- string() = Var, string() = Value}]]></c></tag>
+ <tag><c><![CDATA[{env, ssh_channel_id(), WantReply :: boolean(),
+ Var ::string(), Value :: string()}]]></c></tag>
<item><p>Environment variables can be passed to the shell/command
to be started later. This event is sent as a result of calling <seealso
marker="ssh_connection#setenv-5"> ssh_connection:setenv/5</seealso>.
</p></item>
<tag><c><![CDATA[{pty, ssh_channel_id(),
- boolean() = WantReply, {string() = Terminal, integer() = CharWidth,
- integer() = RowHeight, integer() = PixelWidth, integer() = PixelHeight,
- [{atom() | integer() = Opcode,
- integer() = Value}] = TerminalModes}}]]></c></tag>
+ WantReply :: boolean(), {Terminal :: string(), CharWidth :: integer(),
+ RowHeight :: integer(), PixelWidth :: integer(), PixelHeight :: integer(),
+ TerminalModes :: [{Opcode :: atom() | integer(),
+ Value :: integer()}]}}]]></c></tag>
<item><p>A pseudo-terminal has been requested for the
session. <c>Terminal</c> is the value of the TERM environment
variable value, that is, <c>vt100</c>. Zero dimension parameters must
@@ -174,20 +174,20 @@
echo</c>. This event is sent as a result of calling <seealso
marker="ssh_connection#ptty_alloc/4">ssh_connection:ptty_alloc/4</seealso>.</p></item>
- <tag><c><![CDATA[{shell, boolean() = WantReply}]]></c></tag>
+ <tag><c><![CDATA[{shell, WantReply :: boolean()}]]></c></tag>
<item><p>This message requests that the user default shell
is started at the other end. This event is sent as a result of calling
<seealso marker="ssh_connection#shell-2"> ssh_connection:shell/2</seealso>.
</p></item>
- <tag><c><![CDATA[{window_change, ssh_channel_id(), integer() = CharWidth,
- integer() = RowHeight, integer() = PixWidth, integer() = PixHeight}]]></c></tag>
+ <tag><c><![CDATA[{window_change, ssh_channel_id(), CharWidth() :: integer(),
+ RowHeight :: integer(), PixWidth :: integer(), PixHeight :: integer()}]]></c></tag>
<item><p>When the window (terminal) size changes on the client
side, it <em>can</em> send a message to the server side to inform it of
the new dimensions. No API function generates this event.</p></item>
<tag><c><![CDATA[{exec, ssh_channel_id(),
- boolean() = WantReply, string() = Cmd}]]></c></tag>
+ WantReply :: boolean(), Cmd :: string()}]]></c></tag>
<item><p>This message requests that the server starts
execution of the given command. This event is sent as a result of calling <seealso
marker="ssh_connection#exec-4">ssh_connection:exec/4 </seealso>.
@@ -256,7 +256,7 @@
<taglist>
<tag><c>N x {ssh_cm, ssh_connection_ref(),
- {data, ssh_channel_id(), ssh_data_type_code(), binary() = Data}}</c></tag>
+ {data, ssh_channel_id(), ssh_data_type_code(), Data :: binary()}}</c></tag>
<item><p>The result of executing the command can be only one line
or thousands of lines depending on the command.</p></item>
@@ -265,12 +265,12 @@
<tag><c>0 or 1 x {ssh_cm,
ssh_connection_ref(), {exit_signal,
- ssh_channel_id(), string() = ExitSignal, string() = ErrorMsg, string() = LanguageString}}</c></tag>
+ ssh_channel_id(), ExitSignal :: string(), ErrorMsg :: string(), LanguageString :: string()}}</c></tag>
<item><p>Not all systems send signals. For details on valid string
values, see RFC 4254, Section 6.10</p></item>
<tag><c>0 or 1 x {ssh_cm, ssh_connection_ref(), {exit_status,
- ssh_channel_id(), integer() = ExitStatus}}</c></tag>
+ ssh_channel_id(), ExitStatus :: integer()}}</c></tag>
<item><p>It is recommended by the SSH Connection Protocol to send this
message, but that is not always the case.</p></item>
diff --git a/lib/ssl/test/ssl_ECC_SUITE.erl b/lib/ssl/test/ssl_ECC_SUITE.erl
index 3566a8a0a5..399ca7d0ee 100644
--- a/lib/ssl/test/ssl_ECC_SUITE.erl
+++ b/lib/ssl/test/ssl_ECC_SUITE.erl
@@ -31,8 +31,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, 'tlsv1.2'},
diff --git a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
index ae76f5849e..ee79a9d641 100644
--- a/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_alpn_handshake_SUITE.erl
@@ -30,8 +30,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index e131c363d1..44a5f192e1 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -45,9 +45,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, basic},
diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
index dab7a941db..9ace41acf8 100644
--- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl
+++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl
@@ -37,9 +37,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[{group, active},
{group, passive},
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
index 3433f9a445..4cf80e1f43 100644
--- a/lib/ssl/test/ssl_cipher_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
@@ -34,9 +34,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[aes_decipher_good, aes_decipher_fail, padding_test].
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
index c6bf8898ad..79e1910b18 100644
--- a/lib/ssl/test/ssl_crl_SUITE.erl
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -31,10 +31,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() ->
- [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, check_true},
diff --git a/lib/ssl/test/ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 1a1b2af8d4..5a6556ffb8 100644
--- a/lib/ssl/test/ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -38,10 +38,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() ->
- [{ct_hooks,[ts_install_cth]}].
-
all() ->
[basic, payload, plain_options, plain_verify_options].
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index d4433393a1..7ee5f50b58 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -31,8 +31,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() -> [decode_hello_handshake,
decode_single_hello_extension_correctly,
decode_supported_elliptic_curves_hello_extension_correctly,
diff --git a/lib/ssl/test/ssl_npn_handshake_SUITE.erl b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
index 8e95679306..fa55898835 100644
--- a/lib/ssl/test/ssl_npn_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_handshake_SUITE.erl
@@ -29,8 +29,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
diff --git a/lib/ssl/test/ssl_npn_hello_SUITE.erl b/lib/ssl/test/ssl_npn_hello_SUITE.erl
index 68ff9172e9..288bca621e 100644
--- a/lib/ssl/test/ssl_npn_hello_SUITE.erl
+++ b/lib/ssl/test/ssl_npn_hello_SUITE.erl
@@ -32,9 +32,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[encode_and_decode_npn_client_hello_test,
encode_and_decode_npn_server_hello_test,
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index d50498f547..12a9cad127 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -44,9 +44,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, 'tlsv1.2'},
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index f95eae51b7..aa0cc70315 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -29,8 +29,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, 'tlsv1.2'},
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 36d086338e..3501d7e120 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -41,8 +41,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[session_cleanup,
session_cache_process_list,
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index b059ff991b..1785dc4b86 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -28,7 +28,6 @@
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
all() -> [no_sni_header,
sni_match,
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 21ce4c4a29..463ab8088c 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -37,8 +37,6 @@
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
all() ->
[
{group, basic},
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index 1d7396adee..ac51bb3b79 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -393,6 +393,15 @@ handle_call({start_child, EArgs}, _From, State) when ?is_simple(State) ->
{reply, What, State}
end;
+handle_call({start_child, ChildSpec}, _From, State) ->
+ case check_childspec(ChildSpec) of
+ {ok, Child} ->
+ {Resp, NState} = handle_start_child(Child, State),
+ {reply, Resp, NState};
+ What ->
+ {reply, {error, What}, State}
+ end;
+
%% terminate_child for simple_one_for_one can only be done with pid
handle_call({terminate_child, Name}, _From, State) when not is_pid(Name),
?is_simple(State) ->
@@ -411,20 +420,10 @@ handle_call({terminate_child, Name}, _From, State) ->
{reply, {error, not_found}, State}
end;
-%%% The requests delete_child and restart_child are invalid for
-%%% simple_one_for_one supervisors.
-handle_call({_Req, _Data}, _From, State) when ?is_simple(State) ->
+%% restart_child request is invalid for simple_one_for_one supervisors
+handle_call({restart_child, _Name}, _From, State) when ?is_simple(State) ->
{reply, {error, simple_one_for_one}, State};
-handle_call({start_child, ChildSpec}, _From, State) ->
- case check_childspec(ChildSpec) of
- {ok, Child} ->
- {Resp, NState} = handle_start_child(Child, State),
- {reply, Resp, NState};
- What ->
- {reply, {error, What}, State}
- end;
-
handle_call({restart_child, Name}, _From, State) ->
case get_child(Name, State) of
{value, Child} when Child#child.pid =:= undefined ->
@@ -446,6 +445,10 @@ handle_call({restart_child, Name}, _From, State) ->
{reply, {error, not_found}, State}
end;
+%% delete_child request is invalid for simple_one_for_one supervisors
+handle_call({delete_child, _Name}, _From, State) when ?is_simple(State) ->
+ {reply, {error, simple_one_for_one}, State};
+
handle_call({delete_child, Name}, _From, State) ->
case get_child(Name, State) of
{value, Child} when Child#child.pid =:= undefined ->
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index 015b09f35e..31d4b44f30 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -39,7 +39,8 @@
sup_start_ignore_temporary_child_start_child_simple/1,
sup_start_ignore_permanent_child_start_child_simple/1,
sup_start_error_return/1, sup_start_fail/1,
- sup_start_map/1, sup_start_map_faulty_specs/1,
+ sup_start_map/1, sup_start_map_simple/1,
+ sup_start_map_faulty_specs/1,
sup_stop_infinity/1, sup_stop_timeout/1, sup_stop_brutal_kill/1,
child_adm/1, child_adm_simple/1, child_specs/1, extra_return/1,
sup_flags/1]).
@@ -103,7 +104,7 @@ groups() ->
sup_start_ignore_permanent_child_start_child_simple,
sup_start_error_return, sup_start_fail]},
{sup_start_map, [],
- [sup_start_map, sup_start_map_faulty_specs]},
+ [sup_start_map, sup_start_map_simple, sup_start_map_faulty_specs]},
{sup_stop, [],
[sup_stop_infinity, sup_stop_timeout,
sup_stop_brutal_kill]},
@@ -323,6 +324,30 @@ sup_start_map(Config) when is_list(Config) ->
terminate(Pid, shutdown).
%%-------------------------------------------------------------------------
+%% Tests that the supervisor process starts correctly with map
+%% startspec, and that the full childspec can be read when using
+%% simple_one_for_one strategy.
+sup_start_map_simple(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SupFlags = #{strategy=>simple_one_for_one},
+ ChildSpec = #{id=>undefined,
+ start=>{supervisor_1, start_child, []},
+ restart=>temporary},
+ {ok, Pid} = start_link({ok, {SupFlags, [ChildSpec]}}),
+
+ {ok, Child1} = supervisor:start_child(Pid, []),
+ {ok, Child2} = supervisor:start_child(Pid, []),
+ {ok, Child3} = supervisor:start_child(Pid, []),
+
+ Spec = ChildSpec#{type=>worker, shutdown=>5000, modules=>[supervisor_1]},
+
+ {ok, Spec} = supervisor:get_childspec(Pid, Child1),
+ {ok, Spec} = supervisor:get_childspec(Pid, Child2),
+ {ok, Spec} = supervisor:get_childspec(Pid, Child3),
+ {error,not_found} = supervisor:get_childspec(Pid, self()),
+ terminate(Pid, shutdown).
+
+%%-------------------------------------------------------------------------
%% Tests that the supervisor produces good error messages when start-
%% and child specs are faulty.
sup_start_map_faulty_specs(Config) when is_list(Config) ->