Skip to content

Commit a3e01d3

Browse files
committed
py/objdict: Disallow possible modifications to fixed dicts.
1 parent 5a82ba8 commit a3e01d3

3 files changed

Lines changed: 68 additions & 0 deletions

File tree

py/objdict.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,9 +195,16 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
195195
/******************************************************************************/
196196
/* dict methods */
197197

198+
STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
199+
if (dict->map.is_fixed) {
200+
mp_raise_TypeError(NULL);
201+
}
202+
}
203+
198204
STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
199205
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
200206
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
207+
mp_ensure_not_fixed(self);
201208

202209
mp_map_clear(&self->map);
203210

@@ -253,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk
253260
STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {
254261
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
255262
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
263+
if (lookup_kind != MP_MAP_LOOKUP) {
264+
mp_ensure_not_fixed(self);
265+
}
256266
mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind);
257267
mp_obj_t value;
258268
if (elem == NULL || elem->value == MP_OBJ_NULL) {
@@ -295,6 +305,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_setdefault_obj, 2, 3, dict_setde
295305
STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
296306
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
297307
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
308+
mp_ensure_not_fixed(self);
298309
size_t cur = 0;
299310
mp_map_elem_t *next = dict_iter_next(self, &cur);
300311
if (next == NULL) {
@@ -313,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
313324
STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
314325
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
315326
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
327+
mp_ensure_not_fixed(self);
316328

317329
mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
318330

@@ -578,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
578590
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
579591
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
580592
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
593+
mp_ensure_not_fixed(self);
581594
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
582595
return self_in;
583596
}

tests/basics/dict_fixed.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# test that fixed dictionaries cannot be modified
2+
3+
try:
4+
import uerrno
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
# Save a copy of uerrno.errorcode, so we can check later
10+
# that it hasn't been modified.
11+
errorcode_copy = uerrno.errorcode.copy()
12+
13+
try:
14+
uerrno.errorcode.popitem()
15+
except TypeError:
16+
print("TypeError")
17+
18+
try:
19+
uerrno.errorcode.pop(0)
20+
except TypeError:
21+
print("TypeError")
22+
23+
try:
24+
uerrno.errorcode.setdefault(0, 0)
25+
except TypeError:
26+
print("TypeError")
27+
28+
try:
29+
uerrno.errorcode.update([(1, 2)])
30+
except TypeError:
31+
print("TypeError")
32+
33+
try:
34+
del uerrno.errorcode[1]
35+
except TypeError:
36+
print("TypeError")
37+
38+
try:
39+
uerrno.errorcode[1] = 'foo'
40+
except TypeError:
41+
print("TypeError")
42+
43+
try:
44+
uerrno.errorcode.clear()
45+
except TypeError:
46+
print("TypeError")
47+
48+
assert uerrno.errorcode == errorcode_copy

tests/basics/dict_fixed.py.exp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
TypeError
2+
TypeError
3+
TypeError
4+
TypeError
5+
TypeError
6+
TypeError
7+
TypeError

0 commit comments

Comments
 (0)