Skip to content

Commit 13b0257

Browse files
committed
Fix SMP bugs in dist_send_message and dist_send_link
Use write lock instead of read lock on dist_connections since both functions may insert new connections via dist_get_net_kernel_and_create_connection. Move lock lifecycle ownership to callers to prevent double unlock in error paths of dist_get_net_kernel_and_create_connection.
1 parent 269bcdf commit 13b0257

File tree

1 file changed

+6
-8
lines changed

1 file changed

+6
-8
lines changed

src/libAtomVM/dist_nifs.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -691,15 +691,13 @@ static term dist_get_net_kernel_and_create_connection(struct DistConnection **co
691691
// Ensure net_kernel process can be found to autoconnect
692692
term net_kernel_proc = globalcontext_get_registered_process(ctx->global, NET_KERNEL_ATOM_INDEX);
693693
if (UNLIKELY(!term_is_local_pid(net_kernel_proc))) {
694-
synclist_unlock(&ctx->global->dist_connections);
695-
RAISE_ERROR(NOPROC_ATOM);
694+
return term_invalid_term();
696695
}
697696

698697
// Create a resource object
699698
struct DistConnection *new_conn_obj = enif_alloc_resource(ctx->global->dist_connection_resource_type, sizeof(struct DistConnection));
700699
if (IS_NULL_PTR(new_conn_obj)) {
701-
synclist_unlock(&ctx->global->dist_connections);
702-
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
700+
return term_invalid_term();
703701
}
704702
*conn_obj = new_conn_obj;
705703
new_conn_obj->node_atom_index = node_atom_index;
@@ -752,7 +750,7 @@ term dist_send_message(term target, term payload, Context *ctx)
752750
}
753751

754752
// Search for dhandle.
755-
struct ListHead *dist_connections = synclist_rdlock(&ctx->global->dist_connections);
753+
struct ListHead *dist_connections = synclist_wrlock(&ctx->global->dist_connections);
756754
struct ListHead *item;
757755
LIST_FOR_EACH (item, dist_connections) {
758756
struct DistConnection *dist_connection = GET_LIST_ENTRY(item, struct DistConnection, head);
@@ -778,7 +776,7 @@ term dist_send_message(term target, term payload, Context *ctx)
778776
term net_kernel_proc = dist_get_net_kernel_and_create_connection(&new_conn_obj, node_atom_index, dist_connections, ctx);
779777
if (UNLIKELY(term_is_invalid_term(net_kernel_proc))) {
780778
synclist_unlock(&ctx->global->dist_connections);
781-
return term_invalid_term();
779+
RAISE_ERROR(NOPROC_ATOM);
782780
}
783781

784782
// Enqueue message
@@ -840,7 +838,7 @@ term dist_send_link(term from_pid, term to_pid, Context *ctx)
840838
uint32_t node_creation = term_get_external_node_creation(to_pid);
841839

842840
// Search for dhandle.
843-
struct ListHead *dist_connections = synclist_rdlock(&ctx->global->dist_connections);
841+
struct ListHead *dist_connections = synclist_wrlock(&ctx->global->dist_connections);
844842
struct ListHead *item;
845843
LIST_FOR_EACH (item, dist_connections) {
846844
struct DistConnection *dist_connection = GET_LIST_ENTRY(item, struct DistConnection, head);
@@ -861,7 +859,7 @@ term dist_send_link(term from_pid, term to_pid, Context *ctx)
861859
term net_kernel_proc = dist_get_net_kernel_and_create_connection(&new_conn_obj, node_atom_index, dist_connections, ctx);
862860
if (UNLIKELY(term_is_invalid_term(net_kernel_proc))) {
863861
synclist_unlock(&ctx->global->dist_connections);
864-
return term_invalid_term();
862+
RAISE_ERROR(NOPROC_ATOM);
865863
}
866864

867865
// Enqueue message

0 commit comments

Comments
 (0)