summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-03-30 11:09:00 +1100
committerDamien George <damien.p.george@gmail.com>2018-03-30 11:13:32 +1100
commit32807881954f106b9735de74fe984062a0815b81 (patch)
tree191a534e36c54c7c26005864045996fc87f6abb8
parentbc3a5f191714f28bef95d9f87c24f7367c90d54a (diff)
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.
-rw-r--r--py/obj.h1
-rw-r--r--py/objstr.c6
-rw-r--r--py/runtime.c8
-rw-r--r--tests/basics/fun_calldblstar.py5
4 files changed, 16 insertions, 4 deletions
diff --git a/py/obj.h b/py/obj.h
index 2779b3f86..80599966e 100644
--- a/py/obj.h
+++ b/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_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_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);
#if MICROPY_PY_BUILTINS_FLOAT
diff --git a/py/objstr.c b/py/objstr.c
index c42f38e75..0b11533f8 100644
--- a/py/objstr.c
+++ b/py/objstr.c
@@ -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);
}
+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) {
return mp_obj_new_str_copy(&mp_type_bytes, data, len);
}
diff --git a/py/runtime.c b/py/runtime.c
index 54ec0d70b..ca68fe982 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -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)) {
// the key must be a qstr, so intern it if it's a string
mp_obj_t key = map->table[i].key;
- if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
- key = mp_obj_str_intern(key);
+ if (!MP_OBJ_IS_QSTR(key)) {
+ key = mp_obj_str_intern_checked(key);
}
args2[args2_len++] = key;
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
- if (MP_OBJ_IS_TYPE(key, &mp_type_str)) {
- key = mp_obj_str_intern(key);
+ if (!MP_OBJ_IS_QSTR(key)) {
+ key = mp_obj_str_intern_checked(key);
}
// get the value corresponding to the key
diff --git a/tests/basics/fun_calldblstar.py b/tests/basics/fun_calldblstar.py
index aae9828cf..4a503698f 100644
--- a/tests/basics/fun_calldblstar.py
+++ b/tests/basics/fun_calldblstar.py
@@ -6,6 +6,11 @@ def f(a, b):
f(1, **{'b':2})
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
class A: