py/runtime: Check that keys in dicts passed as ** args are strings.
Prior to this patch the code would crash if a key in a ** dict was anything other than a str or qstr. This is because mp_setup_code_state() assumes that keys in kwargs are qstrs (for efficiency). Thanks to @jepler for finding the bug.
This commit is contained in:
parent
bc3a5f1917
commit
3280788195
1
py/obj.h
1
py/obj.h
@ -720,6 +720,7 @@ qstr mp_obj_str_get_qstr(mp_obj_t self_in); // use this if you will anyway conve
|
|||||||
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
|
const char *mp_obj_str_get_str(mp_obj_t self_in); // use this only if you need the string to be null terminated
|
||||||
const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len);
|
const char *mp_obj_str_get_data(mp_obj_t self_in, size_t *len);
|
||||||
mp_obj_t mp_obj_str_intern(mp_obj_t str);
|
mp_obj_t mp_obj_str_intern(mp_obj_t str);
|
||||||
|
mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj);
|
||||||
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes);
|
void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t str_len, bool is_bytes);
|
||||||
|
|
||||||
#if MICROPY_PY_BUILTINS_FLOAT
|
#if MICROPY_PY_BUILTINS_FLOAT
|
||||||
|
@ -2062,6 +2062,12 @@ mp_obj_t mp_obj_str_intern(mp_obj_t str) {
|
|||||||
return mp_obj_new_str_via_qstr((const char*)data, len);
|
return mp_obj_new_str_via_qstr((const char*)data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t mp_obj_str_intern_checked(mp_obj_t obj) {
|
||||||
|
size_t len;
|
||||||
|
const char *data = mp_obj_str_get_data(obj, &len);
|
||||||
|
return mp_obj_new_str_via_qstr((const char*)data, len);
|
||||||
|
}
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) {
|
mp_obj_t mp_obj_new_bytes(const byte* data, size_t len) {
|
||||||
return mp_obj_new_str_copy(&mp_type_bytes, data, len);
|
return mp_obj_new_str_copy(&mp_type_bytes, data, len);
|
||||||
}
|
}
|
||||||
|
@ -748,8 +748,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
|
|||||||
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
|
if (MP_MAP_SLOT_IS_FILLED(map, i)) {
|
||||||
// the key must be a qstr, so intern it if it's a string
|
// the key must be a qstr, so intern it if it's a string
|
||||||
mp_obj_t key = map->table[i].key;
|
mp_obj_t key = map->table[i].key;
|
||||||
if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
|
if (!MP_OBJ_IS_QSTR(key)) {
|
||||||
key = mp_obj_str_intern(key);
|
key = mp_obj_str_intern_checked(key);
|
||||||
}
|
}
|
||||||
args2[args2_len++] = key;
|
args2[args2_len++] = key;
|
||||||
args2[args2_len++] = map->table[i].value;
|
args2[args2_len++] = map->table[i].value;
|
||||||
@ -778,8 +778,8 @@ void mp_call_prepare_args_n_kw_var(bool have_self, size_t n_args_n_kw, const mp_
|
|||||||
}
|
}
|
||||||
|
|
||||||
// the key must be a qstr, so intern it if it's a string
|
// the key must be a qstr, so intern it if it's a string
|
||||||
if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
|
if (!MP_OBJ_IS_QSTR(key)) {
|
||||||
key = mp_obj_str_intern(key);
|
key = mp_obj_str_intern_checked(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the value corresponding to the key
|
// get the value corresponding to the key
|
||||||
|
@ -6,6 +6,11 @@ def f(a, b):
|
|||||||
f(1, **{'b':2})
|
f(1, **{'b':2})
|
||||||
f(1, **{'b':val for val in range(1)})
|
f(1, **{'b':val for val in range(1)})
|
||||||
|
|
||||||
|
try:
|
||||||
|
f(1, **{len:2})
|
||||||
|
except TypeError:
|
||||||
|
print('TypeError')
|
||||||
|
|
||||||
# test calling a method with keywords given by **dict
|
# test calling a method with keywords given by **dict
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
Loading…
Reference in New Issue
Block a user