Skip to content

Commit 066a9b1

Browse files
committed
Fix leak with disterl monitor by name
Also add `monitored_by` in `process_info/2` to test this fix Signed-off-by: Paul Guyot <[email protected]>
1 parent 630c11d commit 066a9b1

File tree

7 files changed

+68
-11
lines changed

7 files changed

+68
-11
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
5353
- Added `binary:replace/3`, `binary:replace/4`
5454
- Added `binary:match/2` and `binary:match/3`
5555
- Added `supervisor:which_children/1`
56+
- Added `monitored_by` in `process_info/2`
5657

5758
### Changed
5859

@@ -72,6 +73,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7273
- Support for zero count in `lists:duplicate/2`.
7374
- packbeam: fix memory leak preventing building with address sanitizer
7475
- Fixed a bug where empty atom could not be created on some platforms, thus breaking receiving a message for a registered process from an OTP node.
76+
- Fix a memory leak in distribution when a BEAM node would monitor a process by name.
7577

7678
## [0.6.7] - Unreleased
7779

libs/estdlib/src/erlang.erl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,9 @@
178178
| port()
179179
| atom().
180180

181+
% Current type until we make these references
182+
-type resource() :: binary().
183+
181184
%%-----------------------------------------------------------------------------
182185
%% @param Time time in milliseconds after which to send the timeout message.
183186
%% @param Dest Pid or server name to which to send the timeout message.
@@ -255,6 +258,7 @@ send_after(Time, Dest, Msg) ->
255258
%% <li><b>message_queue_len</b> the number of messages enqueued for the process (integer)</li>
256259
%% <li><b>memory</b> the estimated total number of bytes in use by the process (integer)</li>
257260
%% <li><b>links</b> the list of linked processes</li>
261+
%% <li><b>monitored_by</b> the list of processes, NIF resources or ports that monitor the process</li>
258262
%% </ul>
259263
%% Specifying an unsupported term or atom raises a bad_arg error.
260264
%%
@@ -267,7 +271,8 @@ send_after(Time, Dest, Msg) ->
267271
(Pid :: pid(), stack_size) -> {stack_size, non_neg_integer()};
268272
(Pid :: pid(), message_queue_len) -> {message_queue_len, non_neg_integer()};
269273
(Pid :: pid(), memory) -> {memory, non_neg_integer()};
270-
(Pid :: pid(), links) -> {links, [pid()]}.
274+
(Pid :: pid(), links) -> {links, [pid()]};
275+
(Pid :: pid(), monitored_by) -> {monitored_by, [pid() | resource() | port()]}.
271276
process_info(_Pid, _Key) ->
272277
erlang:nif_error(undefined).
273278

src/libAtomVM/context.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,19 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
492492
}
493493
break;
494494
}
495+
case MONITORED_BY_ATOM: {
496+
struct ListHead *item;
497+
ret_size = TUPLE_SIZE(2);
498+
LIST_FOR_EACH (item, &ctx->monitors_head) {
499+
struct Monitor *monitor = GET_LIST_ENTRY(item, struct Monitor, monitor_list_head);
500+
if (monitor->monitor_type == CONTEXT_MONITOR_MONITORED_LOCAL) {
501+
ret_size += CONS_SIZE;
502+
} else if (monitor->monitor_type == CONTEXT_MONITOR_RESOURCE) {
503+
ret_size += CONS_SIZE + TERM_BOXED_RESOURCE_SIZE;
504+
}
505+
}
506+
break;
507+
}
495508
default:
496509
if (out != NULL) {
497510
*out = BADARG_ATOM;
@@ -582,6 +595,24 @@ bool context_get_process_info(Context *ctx, term *out, size_t *term_size, term a
582595
term_put_tuple_element(ret, 1, list);
583596
break;
584597
}
598+
// pids of monitoring processes / resources
599+
case MONITORED_BY_ATOM: {
600+
term_put_tuple_element(ret, 0, MONITORED_BY_ATOM);
601+
term list = term_nil();
602+
struct ListHead *item;
603+
LIST_FOR_EACH (item, &ctx->monitors_head) {
604+
struct Monitor *monitor = GET_LIST_ENTRY(item, struct Monitor, monitor_list_head);
605+
if (monitor->monitor_type == CONTEXT_MONITOR_MONITORED_LOCAL) {
606+
struct MonitorLocalMonitor *monitored_monitor = CONTAINER_OF(monitor, struct MonitorLocalMonitor, monitor);
607+
list = term_list_prepend(monitored_monitor->monitor_obj, list, heap);
608+
} else if (monitor->monitor_type == CONTEXT_MONITOR_RESOURCE) {
609+
struct ResourceContextMonitor *resource_monitor = CONTAINER_OF(monitor, struct ResourceContextMonitor, monitor);
610+
list = term_list_prepend(term_from_resource(resource_monitor->resource_obj, heap), list, heap);
611+
}
612+
}
613+
term_put_tuple_element(ret, 1, list);
614+
break;
615+
}
585616

586617
default:
587618
UNREACHABLE();

src/libAtomVM/defaultatoms.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,5 @@ X(SCOPE_ATOM, "\x5", "scope")
190190
X(NOMATCH_ATOM, "\x7", "nomatch")
191191

192192
X(INIT_ATOM, "\x4", "init")
193+
194+
X(MONITORED_BY_ATOM, "\xC", "monitored_by")

src/libAtomVM/dist_nifs.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -414,12 +414,13 @@ static term nif_erlang_dist_ctrl_get_data(Context *ctx, int argc, term argv[])
414414

415415
term dist_monitor(struct DistConnection *conn_obj, term from_pid, term target_proc, term monitor_ref, Context *ctx)
416416
{
417-
if (term_is_atom(target_proc)) {
418-
target_proc = globalcontext_get_registered_process(ctx->global, term_to_atom_index(target_proc));
419-
}
420417
int target_process_id = 0;
421-
if (term_is_local_pid(target_proc)) {
422-
target_process_id = term_to_local_process_id(target_proc);
418+
term target_process_pid = target_proc;
419+
if (term_is_atom(target_process_pid)) {
420+
target_process_pid = globalcontext_get_registered_process(ctx->global, term_to_atom_index(target_process_pid));
421+
}
422+
if (term_is_local_pid(target_process_pid)) {
423+
target_process_id = term_to_local_process_id(target_process_pid);
423424
} else {
424425
RAISE_ERROR(BADARG_ATOM);
425426
}

tests/erlang_tests/test_process_info.erl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,11 @@ start() ->
4040
{links, [Self]} = process_info(Pid, links),
4141
unlink(Pid),
4242
{links, []} = process_info(Pid, links),
43+
Monitor = monitor(process, Pid),
44+
% Twice because of spawn_opt above
45+
{monitored_by, [Self, Self]} = process_info(Pid, monitored_by),
46+
demonitor(Monitor),
47+
{monitored_by, [Self]} = process_info(Pid, monitored_by),
4348
Pid ! {Self, stop},
4449
_Accum =
4550
receive

tests/libs/estdlib/test_net_kernel.erl

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,14 @@ test_autoconnect_to_beam(Platform) ->
170170
"F = fun(G) ->"
171171
" receive"
172172
" {Caller, ping} -> Caller ! {self(), pong}, G(G);"
173-
" {Caller, quit} -> Caller ! {self(), quit}"
174-
" after 5000 -> exit(timeout)"
175-
" end "
176-
"end, "
177-
"F(F).\" -s init stop -noshell"
173+
" {Caller, net_adm_ping} -> Caller ! {self(), net_adm:ping('" ++
174+
atom_to_list(Node) ++
175+
"')}, G(G);"
176+
" {Caller, quit} -> Caller ! {self(), quit}"
177+
" after 5000 -> exit(timeout)"
178+
" end "
179+
"end, "
180+
"F(F).\" -s init stop -noshell"
178181
)
179182
end,
180183
[link, monitor]
@@ -202,6 +205,14 @@ test_autoconnect_to_beam(Platform) ->
202205
{OTPPid, pong} -> ok
203206
after 5000 -> timeout
204207
end,
208+
OTPPid ! {self(), net_adm_ping},
209+
ok =
210+
receive
211+
{OTPPid, pong} -> ok
212+
after 5000 -> timeout
213+
end,
214+
% Ensure there is no leak
215+
{monitored_by, []} = process_info(whereis(net_kernel), monitored_by),
205216
erlang:send(OTPPid, {self(), quit}),
206217
ok =
207218
receive

0 commit comments

Comments
 (0)