Skip to content

Commit 722cff5

Browse files
committed
py/modthread: Be more careful with root pointers when creating a thread.
1 parent f1b6db2 commit 722cff5

File tree

1 file changed

+25
-11
lines changed

1 file changed

+25
-11
lines changed

py/modthread.c

Lines changed: 25 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ typedef struct _thread_entry_args_t {
142142
mp_obj_t fun;
143143
size_t n_args;
144144
size_t n_kw;
145-
const mp_obj_t *args;
145+
mp_obj_t args[];
146146
} thread_entry_args_t;
147147

148148
STATIC void *thread_entry(void *args_in) {
@@ -186,35 +186,49 @@ STATIC void *thread_entry(void *args_in) {
186186
}
187187

188188
STATIC mp_obj_t mod_thread_start_new_thread(size_t n_args, const mp_obj_t *args) {
189+
// This structure holds the Python function and arguments for thread entry.
190+
// We copy all arguments into this structure to keep ownership of them.
191+
// We must be very careful about root pointers because this pointer may
192+
// disappear from our address space before the thread is created.
193+
thread_entry_args_t *th_args;
194+
195+
// get positional arguments
189196
mp_uint_t pos_args_len;
190197
mp_obj_t *pos_args_items;
191198
mp_obj_get_array(args[1], &pos_args_len, &pos_args_items);
192-
thread_entry_args_t *th_args = m_new_obj(thread_entry_args_t);
193-
th_args->fun = args[0];
199+
200+
// check for keyword arguments
194201
if (n_args == 2) {
195202
// just position arguments
196-
th_args->n_args = pos_args_len;
203+
th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len);
197204
th_args->n_kw = 0;
198-
th_args->args = pos_args_items;
199205
} else {
200206
// positional and keyword arguments
201207
if (mp_obj_get_type(args[2]) != &mp_type_dict) {
202208
nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "expecting a dict for keyword args"));
203209
}
204210
mp_map_t *map = &((mp_obj_dict_t*)MP_OBJ_TO_PTR(args[2]))->map;
205-
th_args->n_args = pos_args_len;
211+
th_args = m_new_obj_var(thread_entry_args_t, mp_obj_t, pos_args_len + 2 * map->used);
206212
th_args->n_kw = map->used;
207-
mp_obj_t *all_args = m_new(mp_obj_t, th_args->n_args + 2 * th_args->n_kw);
208-
memcpy(all_args, pos_args_items, pos_args_len * sizeof(mp_obj_t));
213+
// copy across the keyword arguments
209214
for (size_t i = 0, n = pos_args_len; i < map->alloc; ++i) {
210215
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
211-
all_args[n++] = map->table[i].key;
212-
all_args[n++] = map->table[i].value;
216+
th_args->args[n++] = map->table[i].key;
217+
th_args->args[n++] = map->table[i].value;
213218
}
214219
}
215-
th_args->args = all_args;
216220
}
221+
222+
// copy agross the positional arguments
223+
th_args->n_args = pos_args_len;
224+
memcpy(th_args->args, pos_args_items, pos_args_len * sizeof(mp_obj_t));
225+
226+
// set the function for thread entry
227+
th_args->fun = args[0];
228+
229+
// spawn the thread!
217230
mp_thread_create(thread_entry, th_args, thread_stack_size);
231+
218232
return mp_const_none;
219233
}
220234
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_thread_start_new_thread_obj, 2, 3, mod_thread_start_new_thread);

0 commit comments

Comments
 (0)