Skip to content

Commit c7e8c6f

Browse files
committed
py/gc: Execute finaliser code in a protected environment.
If a finaliser raises an exception then it must not propagate through the GC sweep function. This patch protects against such a thing by running finaliser code via the mp_call_function_1_protected call. This patch also adds scheduler lock/unlock calls around the finaliser execution to further protect against any possible reentrancy issues: the memory manager is already locked when doing a collection, but we also don't want to allow any scheduled code to run, KeyboardInterrupts to interupt the code, nor threads to switch.
1 parent 08242ee commit c7e8c6f

1 file changed

Lines changed: 8 additions & 6 deletions

File tree

py/gc.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -258,18 +258,20 @@ STATIC void gc_sweep(void) {
258258
case AT_HEAD:
259259
#if MICROPY_ENABLE_FINALISER
260260
if (FTB_GET(block)) {
261-
#if MICROPY_PY_THREAD
262-
// TODO need to think about reentrancy with finaliser code
263-
assert(!"finaliser with threading not implemented");
264-
#endif
265261
mp_obj_base_t *obj = (mp_obj_base_t*)PTR_FROM_BLOCK(block);
266262
if (obj->type != NULL) {
267263
// if the object has a type then see if it has a __del__ method
268264
mp_obj_t dest[2];
269265
mp_load_method_maybe(MP_OBJ_FROM_PTR(obj), MP_QSTR___del__, dest);
270266
if (dest[0] != MP_OBJ_NULL) {
271-
// load_method returned a method
272-
mp_call_method_n_kw(0, 0, dest);
267+
// load_method returned a method, execute it in a protected environment
268+
#if MICROPY_ENABLE_SCHEDULER
269+
mp_sched_lock();
270+
#endif
271+
mp_call_function_1_protected(dest[0], dest[1]);
272+
#if MICROPY_ENABLE_SCHEDULER
273+
mp_sched_unlock();
274+
#endif
273275
}
274276
}
275277
// clear finaliser flag

0 commit comments

Comments
 (0)