Skip to content

Commit a893a8b

Browse files
committed
py/objtype: Eliminate __set_name__ hazard.
Signed-off-by: Anson Mansfield <amansfield@mantaro.com>
1 parent 1b103b9 commit a893a8b

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

py/objtype.c

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,38 @@ static bool check_for_special_accessors(mp_obj_t key, mp_obj_t value) {
974974
}
975975
#endif
976976

977+
#if MICROPY_PY_DESCRIPTORS
978+
static void run_set_name_hooks(mp_obj_t locals_dict, mp_obj_t owner) {
979+
// copy the dict so we can iterate safely even while __set_name__ potentially modifies the original
980+
mp_obj_dict_t *locals_dict_copy = MP_OBJ_TO_PTR(mp_obj_dict_copy(locals_dict));
981+
mp_map_t *locals_map = mp_obj_dict_get_map(locals_dict_copy);
982+
983+
// make sure we don't leak this copy's memory
984+
nlr_buf_t nlr;
985+
bool ok = (nlr_push(&nlr) == 0);
986+
if (ok) {
987+
// use the copy to call __set_name__ on each
988+
for (size_t i = 0; i < locals_map->alloc; i++) {
989+
if (mp_map_slot_is_filled(locals_map, i)) {
990+
mp_map_elem_t *elem = &(locals_map->table[i]);
991+
mp_obj_t set_name_method[4];
992+
mp_load_method_maybe(elem->value, MP_QSTR___set_name__, set_name_method);
993+
if (set_name_method[1] != MP_OBJ_NULL) {
994+
set_name_method[2] = owner;
995+
set_name_method[3] = elem->key;
996+
mp_call_method_n_kw(2, 0, set_name_method);
997+
}
998+
}
999+
}
1000+
nlr_pop();
1001+
}
1002+
m_del_obj(locals_dict_copy->base.type, locals_dict_copy);
1003+
if (!ok) {
1004+
nlr_raise(nlr.ret_val); // TODO cpython raises a RuntimeError from this instead
1005+
}
1006+
}
1007+
#endif
1008+
9771009
static void type_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
9781010
(void)kind;
9791011
mp_obj_type_t *self = MP_OBJ_TO_PTR(self_in);
@@ -1242,20 +1274,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
12421274
}
12431275

12441276
#if MICROPY_PY_DESCRIPTORS
1245-
// call __set_name__ on all entries (especially descriptors)
1246-
for (size_t i = 0; i < locals_map->alloc; i++) {
1247-
if (mp_map_slot_is_filled(locals_map, i)) {
1248-
elem = &(locals_map->table[i]);
1249-
1250-
mp_obj_t set_name_method[4];
1251-
mp_load_method_maybe(elem->value, MP_QSTR___set_name__, set_name_method);
1252-
if (set_name_method[1] != MP_OBJ_NULL) {
1253-
set_name_method[2] = MP_OBJ_FROM_PTR(o);
1254-
set_name_method[3] = elem->key;
1255-
mp_call_method_n_kw(2, 0, set_name_method);
1256-
}
1257-
}
1258-
}
1277+
run_set_name_hooks(locals_dict, MP_OBJ_FROM_PTR(o));
12591278
#endif
12601279

12611280
return MP_OBJ_FROM_PTR(o);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy