diff options
author | Damien George <damien.p.george@gmail.com> | 2019-04-15 11:30:19 +1000 |
---|---|---|
committer | Damien George <damien.p.george@gmail.com> | 2019-04-15 11:30:19 +1000 |
commit | 9ce25d70220853faee5c817f9e8d75e265cf73ee (patch) | |
tree | 3cea1cb1d61cc4337844af2a7a2719c2f0263b2b /py/runtime.c | |
parent | 3fa06cf61e6a94417402c4a074e326ccea9cd9d8 (diff) |
py/runtime: Fix mp_unpack_ex so seq can't be reclaimed by GC during use.
The issue described in the comment added here can be seen by forcing a
gc_collect() at the start of each call to gc_alloc().
Diffstat (limited to 'py/runtime.c')
-rw-r--r-- | py/runtime.c | 7 |
1 files changed, 6 insertions, 1 deletions
diff --git a/py/runtime.c b/py/runtime.c index 9210070de..a3628eecb 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -875,8 +875,12 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { DEBUG_OP_printf("unpack ex " UINT_FMT " " UINT_FMT "\n", num_left, num_right); size_t seq_len; if (mp_obj_is_type(seq_in, &mp_type_tuple) || mp_obj_is_type(seq_in, &mp_type_list)) { + // Make the seq variable volatile so the compiler keeps a reference to it, + // since if it's a tuple then seq_items points to the interior of the GC cell + // and mp_obj_new_list may trigger a GC which doesn't trace this and reclaims seq. + volatile mp_obj_t seq = seq_in; mp_obj_t *seq_items; - mp_obj_get_array(seq_in, &seq_len, &seq_items); + mp_obj_get_array(seq, &seq_len, &seq_items); if (seq_len < num_left + num_right) { goto too_short; } @@ -887,6 +891,7 @@ void mp_unpack_ex(mp_obj_t seq_in, size_t num_in, mp_obj_t *items) { for (size_t i = 0; i < num_left; i++) { items[num_right + 1 + i] = seq_items[num_left - 1 - i]; } + seq = MP_OBJ_NULL; } else { // Generic iterable; this gets a bit messy: we unpack known left length to the // items destination array, then the rest to a dynamically created list. Once the |