py/objdict: Disallow possible modifications to fixed dicts.

This commit is contained in:
Mike Wadsten 2018-02-18 21:51:04 -06:00
parent 5a82ba8e07
commit a3e01d3642
3 changed files with 68 additions and 0 deletions

View File

@ -195,9 +195,16 @@ STATIC mp_obj_t dict_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
/******************************************************************************/ /******************************************************************************/
/* dict methods */ /* dict methods */
STATIC void mp_ensure_not_fixed(const mp_obj_dict_t *dict) {
if (dict->map.is_fixed) {
mp_raise_TypeError(NULL);
}
}
STATIC mp_obj_t dict_clear(mp_obj_t self_in) { STATIC mp_obj_t dict_clear(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_ensure_not_fixed(self);
mp_map_clear(&self->map); mp_map_clear(&self->map);
@ -253,6 +260,9 @@ STATIC MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, MP_ROM_PTR(&dict_fromk
STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) { STATIC mp_obj_t dict_get_helper(size_t n_args, const mp_obj_t *args, mp_map_lookup_kind_t lookup_kind) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
if (lookup_kind != MP_MAP_LOOKUP) {
mp_ensure_not_fixed(self);
}
mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind); mp_map_elem_t *elem = mp_map_lookup(&self->map, args[1], lookup_kind);
mp_obj_t value; mp_obj_t value;
if (elem == NULL || elem->value == MP_OBJ_NULL) { 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
STATIC mp_obj_t dict_popitem(mp_obj_t self_in) { STATIC mp_obj_t dict_popitem(mp_obj_t self_in) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_ensure_not_fixed(self);
size_t cur = 0; size_t cur = 0;
mp_map_elem_t *next = dict_iter_next(self, &cur); mp_map_elem_t *next = dict_iter_next(self, &cur);
if (next == NULL) { if (next == NULL) {
@ -313,6 +324,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(dict_popitem_obj, dict_popitem);
STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) { STATIC mp_obj_t dict_update(size_t n_args, const mp_obj_t *args, mp_map_t *kwargs) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0])); mp_check_self(MP_OBJ_IS_DICT_TYPE(args[0]));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]); mp_obj_dict_t *self = MP_OBJ_TO_PTR(args[0]);
mp_ensure_not_fixed(self);
mp_arg_check_num(n_args, kwargs->used, 1, 2, true); mp_arg_check_num(n_args, kwargs->used, 1, 2, true);
@ -578,6 +590,7 @@ size_t mp_obj_dict_len(mp_obj_t self_in) {
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) { mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in)); mp_check_self(MP_OBJ_IS_DICT_TYPE(self_in));
mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in); mp_obj_dict_t *self = MP_OBJ_TO_PTR(self_in);
mp_ensure_not_fixed(self);
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value; mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
return self_in; return self_in;
} }

View File

@ -0,0 +1,48 @@
# test that fixed dictionaries cannot be modified
try:
import uerrno
except ImportError:
print("SKIP")
raise SystemExit
# Save a copy of uerrno.errorcode, so we can check later
# that it hasn't been modified.
errorcode_copy = uerrno.errorcode.copy()
try:
uerrno.errorcode.popitem()
except TypeError:
print("TypeError")
try:
uerrno.errorcode.pop(0)
except TypeError:
print("TypeError")
try:
uerrno.errorcode.setdefault(0, 0)
except TypeError:
print("TypeError")
try:
uerrno.errorcode.update([(1, 2)])
except TypeError:
print("TypeError")
try:
del uerrno.errorcode[1]
except TypeError:
print("TypeError")
try:
uerrno.errorcode[1] = 'foo'
except TypeError:
print("TypeError")
try:
uerrno.errorcode.clear()
except TypeError:
print("TypeError")
assert uerrno.errorcode == errorcode_copy

View File

@ -0,0 +1,7 @@
TypeError
TypeError
TypeError
TypeError
TypeError
TypeError
TypeError