Skip to content

Commit 964bb33

Browse files
committed
json: make JSON scanner thread safe
1 parent 0e0b389 commit 964bb33

File tree

1 file changed

+17
-21
lines changed

1 file changed

+17
-21
lines changed

‎Modules/_json.c‎

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ typedef struct _PyScannerObject {
2424
PyObject *parse_float;
2525
PyObject *parse_int;
2626
PyObject *parse_constant;
27-
PyObject *memo;
2827
} PyScannerObject;
2928

3029
static PyMemberDef scanner_members[] = {
@@ -70,7 +69,7 @@ ascii_escape_unicode(PyObject *pystr);
7069
static PyObject *
7170
py_encode_basestring_ascii(PyObject* Py_UNUSED(self), PyObject *pystr);
7271
static PyObject *
73-
scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr);
72+
scan_once_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr);
7473
static PyObject *
7574
_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx);
7675
static PyObject *
@@ -640,7 +639,6 @@ scanner_traverse(PyScannerObject *self, visitproc visit, void *arg)
640639
Py_VISIT(self->parse_float);
641640
Py_VISIT(self->parse_int);
642641
Py_VISIT(self->parse_constant);
643-
Py_VISIT(self->memo);
644642
return 0;
645643
}
646644

@@ -652,12 +650,11 @@ scanner_clear(PyScannerObject *self)
652650
Py_CLEAR(self->parse_float);
653651
Py_CLEAR(self->parse_int);
654652
Py_CLEAR(self->parse_constant);
655-
Py_CLEAR(self->memo);
656653
return 0;
657654
}
658655

659656
static PyObject *
660-
_parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)
657+
_parse_object_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)
661658
{
662659
/* Read a JSON object from PyUnicode pystr.
663660
idx is the index of the first character after the opening curly brace.
@@ -705,7 +702,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
705702
key = scanstring_unicode(pystr, idx + 1, s->strict, &next_idx);
706703
if (key == NULL)
707704
goto bail;
708-
memokey = PyDict_SetDefault(s->memo, key, key);
705+
memokey = PyDict_SetDefault(memo, key, key);
709706
if (memokey == NULL) {
710707
goto bail;
711708
}
@@ -722,7 +719,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
722719
while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
723720

724721
/* read any JSON term */
725-
val = scan_once_unicode(s, pystr, idx, &next_idx);
722+
val = scan_once_unicode(s, memo, pystr, idx, &next_idx);
726723
if (val == NULL)
727724
goto bail;
728725

@@ -786,7 +783,7 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
786783
}
787784

788785
static PyObject *
789-
_parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {
786+
_parse_array_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {
790787
/* Read a JSON array from PyUnicode pystr.
791788
idx is the index of the first character after the opening brace.
792789
*next_idx_ptr is a return-by-reference index to the first character after
@@ -820,7 +817,7 @@ _parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssi
820817
while (1) {
821818

822819
/* read any JSON term */
823-
val = scan_once_unicode(s, pystr, idx, &next_idx);
820+
val = scan_once_unicode(s, memo, pystr, idx, &next_idx);
824821
if (val == NULL)
825822
goto bail;
826823

@@ -1004,7 +1001,7 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
10041001
}
10051002

10061003
static PyObject *
1007-
scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)
1004+
scan_once_unicode(PyScannerObject *s, PyObject *memo, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)
10081005
{
10091006
/* Read one JSON term (of any kind) from PyUnicode pystr.
10101007
idx is the index of the first character of the term
@@ -1043,15 +1040,15 @@ scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
10431040
if (_Py_EnterRecursiveCall(" while decoding a JSON object "
10441041
"from a unicode string"))
10451042
return NULL;
1046-
res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr);
1043+
res = _parse_object_unicode(s, memo, pystr, idx + 1, next_idx_ptr);
10471044
_Py_LeaveRecursiveCall();
10481045
return res;
10491046
case '[':
10501047
/* array */
10511048
if (_Py_EnterRecursiveCall(" while decoding a JSON array "
10521049
"from a unicode string"))
10531050
return NULL;
1054-
res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr);
1051+
res = _parse_array_unicode(s, memo, pystr, idx + 1, next_idx_ptr);
10551052
_Py_LeaveRecursiveCall();
10561053
return res;
10571054
case 'n':
@@ -1127,16 +1124,19 @@ scanner_call(PyScannerObject *self, PyObject *args, PyObject *kwds)
11271124
if (!PyArg_ParseTupleAndKeywords(args, kwds, "On:scan_once", kwlist, &pystr, &idx))
11281125
return NULL;
11291126

1130-
if (PyUnicode_Check(pystr)) {
1131-
rval = scan_once_unicode(self, pystr, idx, &next_idx);
1132-
}
1133-
else {
1127+
if (!PyUnicode_Check(pystr)) {
11341128
PyErr_Format(PyExc_TypeError,
11351129
"first argument must be a string, not %.80s",
11361130
Py_TYPE(pystr)->tp_name);
11371131
return NULL;
11381132
}
1139-
PyDict_Clear(self->memo);
1133+
1134+
PyObject *memo = PyDict_New();
1135+
if (memo == NULL) {
1136+
return NULL;
1137+
}
1138+
rval = scan_once_unicode(self, memo, pystr, idx, &next_idx);
1139+
Py_DECREF(memo);
11401140
if (rval == NULL)
11411141
return NULL;
11421142
return _build_rval_index_tuple(rval, next_idx);
@@ -1158,10 +1158,6 @@ scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
11581158
return NULL;
11591159
}
11601160

1161-
s->memo = PyDict_New();
1162-
if (s->memo == NULL)
1163-
goto bail;
1164-
11651161
/* All of these will fail "gracefully" so we don't need to verify them */
11661162
strict = PyObject_GetAttrString(ctx, "strict");
11671163
if (strict == NULL)

0 commit comments

Comments
 (0)