perf tools: Make the JSON parser more conformant when in strict mode
authorJames Clark <james.clark@arm.com>
Thu, 7 Oct 2021 11:05:41 +0000 (12:05 +0100)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 8 Oct 2021 18:59:46 +0000 (15:59 -0300)
Return an error when a trailing comma is found or a new item is
encountered before a comma or an opening brace. This ensures that the
perf JSON files conform more closely to the spec at https://www.json.org

Reviewed-by: Andi Kleen <ak@linux.intel.com>
Reviewed-by: Kajol Jain<kjain@linux.ibm.com>
Signed-off-by: James Clark <james.clark@arm.com>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andrew.Kilroy@arm.com
Cc: John Garry <john.garry@huawei.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nick.Forrington@arm.com
Cc: Will Deacon <will@kernel.org>
Cc: linux-arm-kernel@lists.infradead.org
Link: https://lore.kernel.org/r/20211007110543.564963-3-james.clark@arm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/pmu-events/jsmn.c

index 11d1fa1..8124d2d 100644 (file)
@@ -176,6 +176,14 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
        jsmnerr_t r;
        int i;
        jsmntok_t *token;
+#ifdef JSMN_STRICT
+       /*
+        * Keeps track of whether a new object/list/primitive is expected. New items are only
+        * allowed after an opening brace, comma or colon. A closing brace after a comma is not
+        * valid JSON.
+        */
+       int expecting_item = 1;
+#endif
 
        for (; parser->pos < len; parser->pos++) {
                char c;
@@ -185,6 +193,10 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                switch (c) {
                case '{':
                case '[':
+#ifdef JSMN_STRICT
+                       if (!expecting_item)
+                               return JSMN_ERROR_INVAL;
+#endif
                        token = jsmn_alloc_token(parser, tokens, num_tokens);
                        if (token == NULL)
                                return JSMN_ERROR_NOMEM;
@@ -196,6 +208,10 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                        break;
                case '}':
                case ']':
+#ifdef JSMN_STRICT
+                       if (expecting_item)
+                               return JSMN_ERROR_INVAL;
+#endif
                        type = (c == '}' ? JSMN_OBJECT : JSMN_ARRAY);
                        for (i = parser->toknext - 1; i >= 0; i--) {
                                token = &tokens[i];
@@ -219,6 +235,11 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                        }
                        break;
                case '\"':
+#ifdef JSMN_STRICT
+                       if (!expecting_item)
+                               return JSMN_ERROR_INVAL;
+                       expecting_item = 0;
+#endif
                        r = jsmn_parse_string(parser, js, len, tokens,
                                              num_tokens);
                        if (r < 0)
@@ -229,11 +250,15 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                case '\t':
                case '\r':
                case '\n':
-               case ':':
-               case ',':
                case ' ':
                        break;
 #ifdef JSMN_STRICT
+               case ':':
+               case ',':
+                       if (expecting_item)
+                               return JSMN_ERROR_INVAL;
+                       expecting_item = 1;
+                       break;
                        /*
                         * In strict mode primitives are:
                         * numbers and booleans.
@@ -253,6 +278,9 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                case 'f':
                case 'n':
 #else
+               case ':':
+               case ',':
+                       break;
                        /*
                         * In non-strict mode every unquoted value
                         * is a primitive.
@@ -260,6 +288,12 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                        /*FALL THROUGH */
                default:
 #endif
+
+#ifdef JSMN_STRICT
+                       if (!expecting_item)
+                               return JSMN_ERROR_INVAL;
+                       expecting_item = 0;
+#endif
                        r = jsmn_parse_primitive(parser, js, len, tokens,
                                                 num_tokens);
                        if (r < 0)
@@ -282,7 +316,11 @@ jsmnerr_t jsmn_parse(jsmn_parser *parser, const char *js, size_t len,
                        return JSMN_ERROR_PART;
        }
 
+#ifdef JSMN_STRICT
+       return expecting_item ? JSMN_ERROR_INVAL : JSMN_SUCCESS;
+#else
        return JSMN_SUCCESS;
+#endif
 }
 
 /*