From f5a1c56f0ab2a276b5c2add54b8b0d6d276e1361 Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Fri, 12 Aug 2016 16:18:25 +0200
Subject: erts: Fix port monitor memory leak

---
 erts/emulator/beam/erl_process.c  |  1 -
 erts/emulator/test/port_SUITE.erl | 25 +++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)

(limited to 'erts')

diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index b5d8c5bc75..aa6af7427c 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -12276,7 +12276,6 @@ static void doit_exit_monitor(ErtsMonitor *mon, void *vpcontext)
                 erts_port_demonitor(pcontext->p,
                                     ERTS_PORT_DEMONITOR_ORIGIN_ON_DEATHBED,
                                     prt, mon->ref, NULL);
-                return; /* let erts_port_demonitor do the deletion */
             } else { /* remote by pid */
 		ASSERT(is_external_pid(mon->pid));
 		dep = external_pid_dist_entry(mon->pid);
diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl
index 5c0bfdffd4..a9814d7df9 100644
--- a/erts/emulator/test/port_SUITE.erl
+++ b/erts/emulator/test/port_SUITE.erl
@@ -104,6 +104,7 @@
     mon_port_name_demonitor/1,
     mon_port_named/1,
     mon_port_origin_dies/1,
+    mon_port_owner_dies/1,
     mon_port_pid_demonitor/1,
     mon_port_remote_on_remote/1,
     mon_port_driver_die/1,
@@ -173,6 +174,7 @@ all() ->
      mon_port_remote_on_remote,
      mon_port_bad_remote_on_local,
      mon_port_origin_dies,
+     mon_port_owner_dies,
      mon_port_named,
      mon_port_bad_named,
      mon_port_pid_demonitor,
@@ -2637,6 +2639,29 @@ mon_port_origin_dies(Config) ->
     Port5 ! {self(), {command, <<"1">>}}, % make port quit
     ok.
 
+%% Port and Monitor owner dies before port is closed
+%% This testcase checks for a regression memory leak in erts
+%% when the controlling and monitoring process is the same process
+%% and the process dies
+mon_port_owner_dies(Config) ->
+    Self = self(),
+    Proc = spawn(fun() ->
+                         Port = create_port(Config, ["-h1", "-q"]),
+                         Self ! {test_started, Port},
+                         erlang:monitor(port, Port),
+                         receive stop -> ok end
+                  end),
+    erlang:monitor(process, Proc), % we want to sync with its death
+    Port = receive {test_started,P} -> P
+    after 1000 -> ?assert(false) end,
+    ?assertMatch({proc_monitors, true, port_monitored_by, true},
+                 port_is_monitored(Proc, Port)),
+    Proc ! stop,
+    %% receive from monitor
+    receive ExitP5 -> ?assertMatch({'DOWN', _, process, Proc, _}, ExitP5)
+    after 1000 -> ?assert(false) end,
+    ok.
+
 %% Monitor a named port
 mon_port_named(Config) ->
     Name6 = test_port6,
-- 
cgit v1.2.3