]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-113149: Improve error message when JSON has trailing comma (GH-113227)
authorCarson Radtke <carsonRadtke@users.noreply.github.com>
Sun, 17 Dec 2023 18:52:26 +0000 (12:52 -0600)
committerGitHub <noreply@github.com>
Sun, 17 Dec 2023 18:52:26 +0000 (20:52 +0200)
Lib/json/decoder.py
Lib/test/test_json/test_fail.py
Misc/NEWS.d/next/Library/2023-12-16-23-56-42.gh-issue-113149.7LWgTS.rst [new file with mode: 0644]
Modules/_json.c

index c5d9ae2d0d5d040708f097fbf6450b86eef334dd..d69a45d6793069038fcb6d2a1741bb698e5700c8 100644 (file)
@@ -200,10 +200,13 @@ def JSONObject(s_and_end, strict, scan_once, object_hook, object_pairs_hook,
             break
         elif nextchar != ',':
             raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)
+        comma_idx = end - 1
         end = _w(s, end).end()
         nextchar = s[end:end + 1]
         end += 1
         if nextchar != '"':
+            if nextchar == '}':
+                raise JSONDecodeError("Illegal trailing comma before end of object", s, comma_idx)
             raise JSONDecodeError(
                 "Expecting property name enclosed in double quotes", s, end - 1)
     if object_pairs_hook is not None:
@@ -240,13 +243,17 @@ def JSONArray(s_and_end, scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR):
             break
         elif nextchar != ',':
             raise JSONDecodeError("Expecting ',' delimiter", s, end - 1)
+        comma_idx = end - 1
         try:
             if s[end] in _ws:
                 end += 1
                 if s[end] in _ws:
                     end = _w(s, end + 1).end()
+            nextchar = s[end:end + 1]
         except IndexError:
             pass
+        if nextchar == ']':
+            raise JSONDecodeError("Illegal trailing comma before end of array", s, comma_idx)
 
     return values, end
 
index efc982e8b0eb04da291c74d105f4dd6902843310..d6bce605e21463c2c903cff95d7fd62548d5ab06 100644 (file)
@@ -143,11 +143,11 @@ class TestFail:
             ('{"spam":[}', 'Expecting value', 9),
             ('[42:', "Expecting ',' delimiter", 3),
             ('[42 "spam"', "Expecting ',' delimiter", 4),
-            ('[42,]', 'Expecting value', 4),
+            ('[42,]', "Illegal trailing comma before end of array", 3),
             ('{"spam":[42}', "Expecting ',' delimiter", 11),
             ('["]', 'Unterminated string starting at', 1),
             ('["spam":', "Expecting ',' delimiter", 7),
-            ('["spam",]', 'Expecting value', 8),
+            ('["spam",]', "Illegal trailing comma before end of array", 7),
             ('{:', 'Expecting property name enclosed in double quotes', 1),
             ('{,', 'Expecting property name enclosed in double quotes', 1),
             ('{42', 'Expecting property name enclosed in double quotes', 1),
@@ -159,7 +159,9 @@ class TestFail:
             ('[{"spam":]', 'Expecting value', 9),
             ('{"spam":42 "ham"', "Expecting ',' delimiter", 11),
             ('[{"spam":42]', "Expecting ',' delimiter", 11),
-            ('{"spam":42,}', 'Expecting property name enclosed in double quotes', 11),
+            ('{"spam":42,}', "Illegal trailing comma before end of object", 10),
+            ('{"spam":42 , }', "Illegal trailing comma before end of object", 11),
+            ('[123  , ]', "Illegal trailing comma before end of array", 6),
         ]
         for data, msg, idx in test_cases:
             with self.assertRaises(self.JSONDecodeError) as cm:
diff --git a/Misc/NEWS.d/next/Library/2023-12-16-23-56-42.gh-issue-113149.7LWgTS.rst b/Misc/NEWS.d/next/Library/2023-12-16-23-56-42.gh-issue-113149.7LWgTS.rst
new file mode 100644 (file)
index 0000000..0faa67f
--- /dev/null
@@ -0,0 +1,2 @@
+Improve error message when a JSON array or object contains a trailing comma.
+Patch by Carson Radtke.
index 0b1bfe34ad93044f2f6774881b8efbb4a6a1966b..24b292ce70e5ebda434e3ab027c7cc541056148a 100644 (file)
@@ -662,6 +662,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ss
     PyObject *key = NULL;
     int has_pairs_hook = (s->object_pairs_hook != Py_None);
     Py_ssize_t next_idx;
+    Py_ssize_t comma_idx;
 
     str = PyUnicode_DATA(pystr);
     kind = PyUnicode_KIND(pystr);
@@ -741,10 +742,16 @@ _parse_object_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ss
                 raise_errmsg("Expecting ',' delimiter", pystr, idx);
                 goto bail;
             }
+            comma_idx = idx;
             idx++;
 
             /* skip whitespace after , delimiter */
             while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
+
+            if (idx <= end_idx && PyUnicode_READ(kind, str, idx) == '}') {
+                raise_errmsg("Illegal trailing comma before end of object", pystr, comma_idx);
+                goto bail;
+            }
         }
     }
 
@@ -785,6 +792,7 @@ _parse_array_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssi
     PyObject *val = NULL;
     PyObject *rval;
     Py_ssize_t next_idx;
+    Py_ssize_t comma_idx;
 
     rval = PyList_New(0);
     if (rval == NULL)
@@ -822,10 +830,16 @@ _parse_array_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssi
                 raise_errmsg("Expecting ',' delimiter", pystr, idx);
                 goto bail;
             }
+            comma_idx = idx;
             idx++;
 
             /* skip whitespace after , */
             while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
+
+            if (idx <= end_idx && PyUnicode_READ(kind, str, idx) == ']') {
+                raise_errmsg("Illegal trailing comma before end of array", pystr, comma_idx);
+                goto bail;
+            }
         }
     }