Create a gist now

Instantly share code, notes, and snippets.

Reveals bug in prim_inet:close/1
-module(close_bug).
-export([bad_ports/0, start/1]).
bad_ports() ->
[{P, element(2, erlang:port_info(P, connected))} || {P, {links, []}} <- [{P, erlang:port_info(P, links)} || P <- erlang:ports()]].
opts() ->
[binary, {active, false}, {exit_on_close, false}, {packet, 1}, {nodelay, true}].
start(N) ->
[] = bad_ports(),
erlang:process_flag(trap_exit, true),
{ok, Listen} = gen_tcp:listen(0, [{backlog, 100} | opts()]),
{ok, Port} = inet:port(Listen),
Pids = loop(N, Port, Listen, self()),
join(Pids),
ok = gen_tcp:close(Listen),
bad_ports().
loop(0, _, _, _) ->
[];
loop(N, Port, Listen, Self) ->
Pid = spawn_link(fun() -> accept(Port, Listen, Self) end),
[Pid | loop(N - 1, Port, Listen, Self)].
join([Pid | Next]) ->
receive
{'EXIT', Pid, _} ->
receive
{done, Pid} -> ok
after 0 ->
io:format("killed ~p\n", [Pid])
end
end,
join(Next);
join([]) ->
ok.
accept(Port, Listen, Parent) ->
spawn(fun() -> connect(Port) end),
{ok, S} = gen_tcp:accept(Listen, 5000),
{ok, <<"ping">>} = gen_tcp:recv(S, 0),
ok = gen_tcp:send(S, term_to_binary(self())),
receive
{close, Pid} -> ok
end,
true = erlang:link(Pid),
Pid ! {closing, self()},
ok = gen_tcp:close(S),
Parent ! {done, self()}.
connect(Port) ->
{ok, S} = gen_tcp:connect({0,0,0,0}, Port, opts()),
ok = gen_tcp:send(S, <<"ping">>),
{ok, B} = gen_tcp:recv(S, 0),
Pid = binary_to_term(B),
Pid ! {close, self()},
receive
{closing, Pid} -> exit(goodbye)
end.
@RumataEstor
Owner

As of R16B03-1 is seems to be fixed, cool!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment