Skip to content

Commit e2c754f

Browse files
authored
Fix data race when terminating or waiting for a thread (#1924)
There is a possibility that while iterating through a list of threads, the threads finish by themselves, making a list of exec_env invalid.
1 parent 2c8375e commit e2c754f

File tree

1 file changed

+74
-18
lines changed

1 file changed

+74
-18
lines changed

core/iwasm/libraries/thread-mgr/thread_manager.c

Lines changed: 74 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,58 @@ traverse_list(bh_list *l, list_visitor visitor, void *user_data)
7676
}
7777
}
7878

79+
/* Assumes cluster->lock is locked */
80+
static bool
81+
safe_traverse_exec_env_list(WASMCluster *cluster, list_visitor visitor,
82+
void *user_data)
83+
{
84+
Vector proc_nodes;
85+
void *node;
86+
bool ret = true;
87+
88+
if (!bh_vector_init(&proc_nodes, cluster->exec_env_list.len, sizeof(void *),
89+
false)) {
90+
ret = false;
91+
goto final;
92+
}
93+
94+
node = bh_list_first_elem(&cluster->exec_env_list);
95+
96+
while (node) {
97+
bool already_processed = false;
98+
void *proc_node;
99+
for (size_t i = 0; i < bh_vector_size(&proc_nodes); i++) {
100+
if (!bh_vector_get(&proc_nodes, i, &proc_node)) {
101+
ret = false;
102+
goto final;
103+
}
104+
if (proc_node == node) {
105+
already_processed = true;
106+
break;
107+
}
108+
}
109+
if (already_processed) {
110+
node = bh_list_elem_next(node);
111+
continue;
112+
}
113+
114+
os_mutex_unlock(&cluster->lock);
115+
visitor(node, user_data);
116+
os_mutex_lock(&cluster->lock);
117+
if (!bh_vector_append(&proc_nodes, &node)) {
118+
ret = false;
119+
goto final;
120+
}
121+
122+
node = bh_list_first_elem(&cluster->exec_env_list);
123+
}
124+
125+
final:
126+
bh_vector_destroy(&proc_nodes);
127+
128+
return ret;
129+
}
130+
79131
/* The caller must lock cluster->lock */
80132
static bool
81133
allocate_aux_stack(WASMCluster *cluster, uint32 *start, uint32 *size)
@@ -299,7 +351,6 @@ wasm_cluster_del_exec_env(WASMCluster *cluster, WASMExecEnv *exec_env)
299351
os_mutex_unlock(&cluster->debug_inst->wait_lock);
300352
}
301353
#endif
302-
303354
if (bh_list_remove(&cluster->exec_env_list, exec_env) != 0)
304355
ret = false;
305356

@@ -724,16 +775,22 @@ wasm_cluster_join_thread(WASMExecEnv *exec_env, void **ret_val)
724775
korp_tid handle;
725776

726777
os_mutex_lock(&cluster_list_lock);
778+
os_mutex_lock(&exec_env->cluster->lock);
779+
727780
if (!clusters_have_exec_env(exec_env) || exec_env->thread_is_detached) {
728781
/* Invalid thread, thread has exited or thread has been detached */
729782
if (ret_val)
730783
*ret_val = NULL;
784+
os_mutex_unlock(&exec_env->cluster->lock);
731785
os_mutex_unlock(&cluster_list_lock);
732786
return 0;
733787
}
734788
exec_env->wait_count++;
735789
handle = exec_env->handle;
790+
791+
os_mutex_unlock(&exec_env->cluster->lock);
736792
os_mutex_unlock(&cluster_list_lock);
793+
737794
return os_thread_join(handle, ret_val);
738795
}
739796

@@ -816,15 +873,22 @@ int32
816873
wasm_cluster_cancel_thread(WASMExecEnv *exec_env)
817874
{
818875
os_mutex_lock(&cluster_list_lock);
876+
os_mutex_lock(&exec_env->cluster->lock);
877+
878+
if (!exec_env->cluster) {
879+
goto final;
880+
}
819881
if (!clusters_have_exec_env(exec_env)) {
820882
/* Invalid thread or the thread has exited */
821-
os_mutex_unlock(&cluster_list_lock);
822-
return 0;
883+
goto final;
823884
}
824-
os_mutex_unlock(&cluster_list_lock);
825885

826886
set_thread_cancel_flags(exec_env);
827887

888+
final:
889+
os_mutex_unlock(&exec_env->cluster->lock);
890+
os_mutex_unlock(&cluster_list_lock);
891+
828892
return 0;
829893
}
830894

@@ -846,11 +910,9 @@ wasm_cluster_terminate_all(WASMCluster *cluster)
846910
{
847911
os_mutex_lock(&cluster->lock);
848912
cluster->processing = true;
849-
os_mutex_unlock(&cluster->lock);
850913

851-
traverse_list(&cluster->exec_env_list, terminate_thread_visitor, NULL);
914+
safe_traverse_exec_env_list(cluster, terminate_thread_visitor, NULL);
852915

853-
os_mutex_lock(&cluster->lock);
854916
cluster->processing = false;
855917
os_mutex_unlock(&cluster->lock);
856918
}
@@ -861,12 +923,10 @@ wasm_cluster_terminate_all_except_self(WASMCluster *cluster,
861923
{
862924
os_mutex_lock(&cluster->lock);
863925
cluster->processing = true;
864-
os_mutex_unlock(&cluster->lock);
865926

866-
traverse_list(&cluster->exec_env_list, terminate_thread_visitor,
867-
(void *)exec_env);
927+
safe_traverse_exec_env_list(cluster, terminate_thread_visitor,
928+
(void *)exec_env);
868929

869-
os_mutex_lock(&cluster->lock);
870930
cluster->processing = false;
871931
os_mutex_unlock(&cluster->lock);
872932
}
@@ -888,11 +948,9 @@ wams_cluster_wait_for_all(WASMCluster *cluster)
888948
{
889949
os_mutex_lock(&cluster->lock);
890950
cluster->processing = true;
891-
os_mutex_unlock(&cluster->lock);
892951

893-
traverse_list(&cluster->exec_env_list, wait_for_thread_visitor, NULL);
952+
safe_traverse_exec_env_list(cluster, wait_for_thread_visitor, NULL);
894953

895-
os_mutex_lock(&cluster->lock);
896954
cluster->processing = false;
897955
os_mutex_unlock(&cluster->lock);
898956
}
@@ -903,12 +961,10 @@ wasm_cluster_wait_for_all_except_self(WASMCluster *cluster,
903961
{
904962
os_mutex_lock(&cluster->lock);
905963
cluster->processing = true;
906-
os_mutex_unlock(&cluster->lock);
907964

908-
traverse_list(&cluster->exec_env_list, wait_for_thread_visitor,
909-
(void *)exec_env);
965+
safe_traverse_exec_env_list(cluster, wait_for_thread_visitor,
966+
(void *)exec_env);
910967

911-
os_mutex_lock(&cluster->lock);
912968
cluster->processing = false;
913969
os_mutex_unlock(&cluster->lock);
914970
}

0 commit comments

Comments
 (0)