From 01054f20925b92229402750979864f8d38a76916 Mon Sep 17 00:00:00 2001 From: Eric Poulsen Date: Tue, 16 Jul 2019 14:29:22 -0700 Subject: [PATCH] py/objdict: Quote non-string types when used as keys in JSON output. JSON requires that keys of objects be strings. CPython will therefore automatically quote simple types (NoneType, bool, int, float) when they are used directly as keys in JSON output. To prevent subtle bugs and emit compliant JSON, MicroPython should at least test for such keys so they aren't silently let through. Then doing the actual quoting is a similar cost to raising an exception, so that's what is implemented by this patch. Fixes issue #4790. --- py/objdict.c | 8 ++++++++ tests/extmod/ujson_dumps.py | 4 ++++ tests/extmod/ujson_dumps_float.py | 1 + 3 files changed, 13 insertions(+) diff --git a/py/objdict.c b/py/objdict.c index 0a223f731..02a2346fd 100644 --- a/py/objdict.c +++ b/py/objdict.c @@ -31,6 +31,7 @@ #include "py/runtime.h" #include "py/builtin.h" #include "py/objtype.h" +#include "py/objstr.h" #define mp_obj_is_dict_type(o) (mp_obj_is_obj(o) && ((mp_obj_base_t*)MP_OBJ_TO_PTR(o))->type->make_new == dict_make_new) @@ -70,7 +71,14 @@ STATIC void dict_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_ mp_print_str(print, ", "); } first = false; + bool add_quote = MICROPY_PY_UJSON && kind == PRINT_JSON && !mp_obj_is_str_or_bytes(next->key); + if (add_quote) { + mp_print_str(print, "\""); + } mp_obj_print_helper(print, next->key, kind); + if (add_quote) { + mp_print_str(print, "\""); + } mp_print_str(print, ": "); mp_obj_print_helper(print, next->value, kind); } diff --git a/tests/extmod/ujson_dumps.py b/tests/extmod/ujson_dumps.py index d73271801..c33126cec 100644 --- a/tests/extmod/ujson_dumps.py +++ b/tests/extmod/ujson_dumps.py @@ -26,3 +26,7 @@ print(json.dumps({"a":1})) print(json.dumps({"a":(2,[3,None])})) print(json.dumps('"quoted"')) print(json.dumps('space\n\r\tspace')) +print(json.dumps({None: -1})) +print(json.dumps({False: 0})) +print(json.dumps({True: 1})) +print(json.dumps({1: 2})) diff --git a/tests/extmod/ujson_dumps_float.py b/tests/extmod/ujson_dumps_float.py index e8cceb6f1..40adb1e26 100644 --- a/tests/extmod/ujson_dumps_float.py +++ b/tests/extmod/ujson_dumps_float.py @@ -8,3 +8,4 @@ except ImportError: raise SystemExit print(json.dumps(1.2)) +print(json.dumps({1.5: 'hi'}))