summaryrefslogtreecommitdiff
path: root/Modules/_json.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_json.c')
-rw-r--r--Modules/_json.c177
1 files changed, 96 insertions, 81 deletions
diff --git a/Modules/_json.c b/Modules/_json.c
index db45c28fe4..301bc87d27 100644
--- a/Modules/_json.c
+++ b/Modules/_json.c
@@ -2,20 +2,6 @@
#include "structmember.h"
#include "accu.h"
-#if PY_VERSION_HEX < 0x02060000 && !defined(Py_TYPE)
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
-#endif
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
-typedef int Py_ssize_t;
-#define PY_SSIZE_T_MAX INT_MAX
-#define PY_SSIZE_T_MIN INT_MIN
-#define PyInt_FromSsize_t PyInt_FromLong
-#define PyInt_AsSsize_t PyInt_AsLong
-#endif
-#ifndef Py_IS_FINITE
-#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X))
-#endif
-
#ifdef __GNUC__
#define UNUSED __attribute__((__unused__))
#else
@@ -129,33 +115,14 @@ static void
raise_errmsg(char *msg, PyObject *s, Py_ssize_t end);
static PyObject *
encoder_encode_string(PyEncoderObject *s, PyObject *obj);
-static int
-_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr);
static PyObject *
-_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr);
+encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj);
static PyObject *
encoder_encode_float(PyEncoderObject *s, PyObject *obj);
#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"')
#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))
-static int
-_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr)
-{
- /* PyObject to Py_ssize_t converter */
- *size_ptr = PyLong_AsSsize_t(o);
- if (*size_ptr == -1 && PyErr_Occurred())
- return 0;
- return 1;
-}
-
-static PyObject *
-_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr)
-{
- /* Py_ssize_t to PyObject converter */
- return PyLong_FromSsize_t(*size_ptr);
-}
-
static Py_ssize_t
ascii_escape_unichar(Py_UCS4 c, unsigned char *output, Py_ssize_t chars)
{
@@ -174,14 +141,13 @@ ascii_escape_unichar(Py_UCS4 c, unsigned char *output, Py_ssize_t chars)
default:
if (c >= 0x10000) {
/* UTF-16 surrogate pair */
- Py_UCS4 v = c - 0x10000;
- c = 0xd800 | ((v >> 10) & 0x3ff);
+ Py_UCS4 v = Py_UNICODE_HIGH_SURROGATE(c);
output[chars++] = 'u';
- output[chars++] = Py_hexdigits[(c >> 12) & 0xf];
- output[chars++] = Py_hexdigits[(c >> 8) & 0xf];
- output[chars++] = Py_hexdigits[(c >> 4) & 0xf];
- output[chars++] = Py_hexdigits[(c ) & 0xf];
- c = 0xdc00 | (v & 0x3ff);
+ output[chars++] = Py_hexdigits[(v >> 12) & 0xf];
+ output[chars++] = Py_hexdigits[(v >> 8) & 0xf];
+ output[chars++] = Py_hexdigits[(v >> 4) & 0xf];
+ output[chars++] = Py_hexdigits[(v ) & 0xf];
+ c = Py_UNICODE_LOW_SURROGATE(c);
output[chars++] = '\\';
}
output[chars++] = 'u';
@@ -268,13 +234,23 @@ raise_errmsg(char *msg, PyObject *s, Py_ssize_t end)
if (errmsg_fn == NULL)
return;
}
- pymsg = PyObject_CallFunction(errmsg_fn, "(zOO&)", msg, s, _convertPyInt_FromSsize_t, &end);
+ pymsg = PyObject_CallFunction(errmsg_fn, "(zOn)", msg, s, end);
if (pymsg) {
PyErr_SetObject(PyExc_ValueError, pymsg);
Py_DECREF(pymsg);
}
}
+static void
+raise_stop_iteration(Py_ssize_t idx)
+{
+ PyObject *value = PyLong_FromSsize_t(idx);
+ if (value != NULL) {
+ PyErr_SetObject(PyExc_StopIteration, value);
+ Py_DECREF(value);
+ }
+}
+
static PyObject *
_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) {
/* return (rval, idx) tuple, stealing reference to rval */
@@ -344,7 +320,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
buf = PyUnicode_DATA(pystr);
kind = PyUnicode_KIND(pystr);
- if (end < 0 || len <= end) {
+ if (end < 0 || len < end) {
PyErr_SetString(PyExc_ValueError, "end is out of bounds");
goto bail;
}
@@ -433,7 +409,7 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
}
}
/* Surrogate pair */
- if ((c & 0xfc00) == 0xd800) {
+ if (Py_UNICODE_IS_HIGH_SURROGATE(c)) {
Py_UCS4 c2 = 0;
if (end + 6 >= len) {
raise_errmsg("Unpaired high surrogate", pystr, end - 5);
@@ -464,13 +440,13 @@ scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next
goto bail;
}
}
- if ((c2 & 0xfc00) != 0xdc00) {
+ if (!Py_UNICODE_IS_LOW_SURROGATE(c2)) {
raise_errmsg("Unpaired high surrogate", pystr, end - 5);
goto bail;
}
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));
+ c = Py_UNICODE_JOIN_SURROGATES(c, c2);
}
- else if ((c & 0xfc00) == 0xdc00) {
+ else if (Py_UNICODE_IS_LOW_SURROGATE(c)) {
raise_errmsg("Unpaired low surrogate", pystr, end - 5);
goto bail;
}
@@ -527,7 +503,7 @@ py_scanstring(PyObject* self UNUSED, PyObject *args)
Py_ssize_t end;
Py_ssize_t next_end = -1;
int strict = 1;
- if (!PyArg_ParseTuple(args, "OO&|i:scanstring", &pystr, _convertPyInt_AsSsize_t, &end, &strict)) {
+ if (!PyArg_ParseTuple(args, "On|i:scanstring", &pystr, &end, &strict)) {
return NULL;
}
if (PyUnicode_Check(pystr)) {
@@ -642,12 +618,12 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind,str, idx))) idx++;
/* only loop if the object is non-empty */
- if (idx <= end_idx && PyUnicode_READ(kind, str, idx) != '}') {
- while (idx <= end_idx) {
+ if (idx > end_idx || PyUnicode_READ(kind, str, idx) != '}') {
+ while (1) {
PyObject *memokey;
/* read key */
- if (PyUnicode_READ(kind, str, idx) != '"') {
+ if (idx > end_idx || PyUnicode_READ(kind, str, idx) != '"') {
raise_errmsg("Expecting property name enclosed in double quotes", pystr, idx);
goto bail;
}
@@ -704,11 +680,9 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
/* bail if the object is closed or we didn't get the , delimiter */
- if (idx > end_idx) break;
- if (PyUnicode_READ(kind, str, idx) == '}') {
+ if (idx <= end_idx && PyUnicode_READ(kind, str, idx) == '}')
break;
- }
- else if (PyUnicode_READ(kind, str, idx) != ',') {
+ if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ',') {
raise_errmsg("Expecting ',' delimiter", pystr, idx);
goto bail;
}
@@ -719,12 +693,6 @@ _parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ss
}
}
- /* verify that idx < end_idx, str[idx] should be '}' */
- if (idx > end_idx || PyUnicode_READ(kind, str, idx) != '}') {
- raise_errmsg("Expecting object", pystr, end_idx);
- goto bail;
- }
-
*next_idx_ptr = idx + 1;
if (has_pairs_hook) {
@@ -776,8 +744,8 @@ _parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssi
while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
/* only loop if the array is non-empty */
- if (idx <= end_idx && PyUnicode_READ(kind, str, idx) != ']') {
- while (idx <= end_idx) {
+ if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ']') {
+ while (1) {
/* read any JSON term */
val = scan_once_unicode(s, pystr, idx, &next_idx);
@@ -794,11 +762,9 @@ _parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssi
while (idx <= end_idx && IS_WHITESPACE(PyUnicode_READ(kind, str, idx))) idx++;
/* bail if the array is closed or we didn't get the , delimiter */
- if (idx > end_idx) break;
- if (PyUnicode_READ(kind, str, idx) == ']') {
+ if (idx <= end_idx && PyUnicode_READ(kind, str, idx) == ']')
break;
- }
- else if (PyUnicode_READ(kind, str, idx) != ',') {
+ if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ',') {
raise_errmsg("Expecting ',' delimiter", pystr, idx);
goto bail;
}
@@ -811,7 +777,7 @@ _parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssi
/* verify that idx < end_idx, PyUnicode_READ(kind, str, idx) should be ']' */
if (idx > end_idx || PyUnicode_READ(kind, str, idx) != ']') {
- raise_errmsg("Expecting object", pystr, end_idx);
+ raise_errmsg("Expecting value", pystr, end_idx);
goto bail;
}
*next_idx_ptr = idx + 1;
@@ -879,7 +845,7 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
if (PyUnicode_READ(kind, str, idx) == '-') {
idx++;
if (idx > end_idx) {
- PyErr_SetNone(PyExc_StopIteration);
+ raise_stop_iteration(start);
return NULL;
}
}
@@ -895,7 +861,7 @@ _match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_
}
/* no integer digits, error */
else {
- PyErr_SetNone(PyExc_StopIteration);
+ raise_stop_iteration(start);
return NULL;
}
@@ -988,7 +954,7 @@ scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_
length = PyUnicode_GET_LENGTH(pystr);
if (idx >= length) {
- PyErr_SetNone(PyExc_StopIteration);
+ raise_stop_iteration(idx);
return NULL;
}
@@ -1090,7 +1056,7 @@ scanner_call(PyObject *self, PyObject *args, PyObject *kwds)
PyScannerObject *s;
assert(PyScanner_Check(self));
s = (PyScannerObject *)self;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:scan_once", kwlist, &pystr, _convertPyInt_AsSsize_t, &idx))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "On:scan_once", kwlist, &pystr, &idx))
return NULL;
if (PyUnicode_Check(pystr)) {
@@ -1291,8 +1257,8 @@ encoder_call(PyObject *self, PyObject *args, PyObject *kwds)
assert(PyEncoder_Check(self));
s = (PyEncoderObject *)self;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:_iterencode", kwlist,
- &obj, _convertPyInt_AsSsize_t, &indent_level))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "On:_iterencode", kwlist,
+ &obj, &indent_level))
return NULL;
if (_PyAccu_Init(&acc))
return NULL;
@@ -1338,13 +1304,45 @@ _encoded_const(PyObject *obj)
}
static PyObject *
+encoder_encode_long(PyEncoderObject* s UNUSED, PyObject *obj)
+{
+ /* Return the JSON representation of a PyLong and PyLong subclasses.
+ Calls int() on PyLong subclasses in case the str() was changed.
+ Added specifically to deal with IntEnum. See Issue18264. */
+ PyObject *encoded, *longobj;
+ if (PyLong_CheckExact(obj)) {
+ encoded = PyObject_Str(obj);
+ }
+ else {
+ longobj = PyNumber_Long(obj);
+ if (longobj == NULL) {
+ PyErr_SetString(
+ PyExc_ValueError,
+ "Unable to coerce int subclass to int"
+ );
+ return NULL;
+ }
+ encoded = PyObject_Str(longobj);
+ Py_DECREF(longobj);
+ }
+ return encoded;
+}
+
+
+static PyObject *
encoder_encode_float(PyEncoderObject *s, PyObject *obj)
{
- /* Return the JSON representation of a PyFloat */
+ /* Return the JSON representation of a PyFloat.
+ Modified to call float() on float subclasses in case the subclass
+ changes the repr. See Issue18264. */
+ PyObject *encoded, *floatobj;
double i = PyFloat_AS_DOUBLE(obj);
if (!Py_IS_FINITE(i)) {
if (!s->allow_nan) {
- PyErr_SetString(PyExc_ValueError, "Out of range float values are not JSON compliant");
+ PyErr_SetString(
+ PyExc_ValueError,
+ "Out of range float values are not JSON compliant"
+ );
return NULL;
}
if (i > 0) {
@@ -1357,8 +1355,24 @@ encoder_encode_float(PyEncoderObject *s, PyObject *obj)
return PyUnicode_FromString("NaN");
}
}
- /* Use a better float format here? */
- return PyObject_Repr(obj);
+ /* coerce float subclasses to float (primarily for Enum) */
+ if (PyFloat_CheckExact(obj)) {
+ /* Use a better float format here? */
+ encoded = PyObject_Repr(obj);
+ }
+ else {
+ floatobj = PyNumber_Float(obj);
+ if (floatobj == NULL) {
+ PyErr_SetString(
+ PyExc_ValueError,
+ "Unable to coerce float subclass to float"
+ );
+ return NULL;
+ }
+ encoded = PyObject_Repr(floatobj);
+ Py_DECREF(floatobj);
+ }
+ return encoded;
}
static PyObject *
@@ -1402,7 +1416,7 @@ encoder_listencode_obj(PyEncoderObject *s, _PyAccu *acc,
return _steal_accumulate(acc, encoded);
}
else if (PyLong_Check(obj)) {
- PyObject *encoded = PyObject_Str(obj);
+ PyObject *encoded = encoder_encode_long(s, obj);
if (encoded == NULL)
return -1;
return _steal_accumulate(acc, encoded);
@@ -1587,9 +1601,10 @@ encoder_listencode_dict(PyEncoderObject *s, _PyAccu *acc,
goto bail;
}
else if (PyLong_Check(key)) {
- kstr = PyObject_Str(key);
- if (kstr == NULL)
+ kstr = encoder_encode_long(s, key);
+ if (kstr == NULL) {
goto bail;
+ }
}
else if (skipkeys) {
Py_DECREF(item);