From 32807881954f106b9735de74fe984062a0815b81 Mon Sep 17 00:00:00 2001 From: Damien George Date: Fri, 30 Mar 2018 11:09:00 +1100 Subject: [PATCH] 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. --- py/obj.h | 1 + py/objstr.c | 6 ++++++ py/runtime.c | 8 ++++---- tests/basics/fun_calldblstar.py | 5 +++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/py/obj.h b/py/obj.h index 2779b3f861..80599966e2 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 c42f38e75b..0b11533f82 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 54ec0d70b4..ca68fe982d 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 aae9828cf7..4a503698ff 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: