From f7171eb2f28ca42114922ce129a3f293927113bf Mon Sep 17 00:00:00 2001 From: Aivars Kalvans Date: Fri, 25 Jul 2025 17:09:58 +0300 Subject: [PATCH 1/5] A better circular check for json.dump() When check_circular=True (default) is used, the JSON module created a map and created a new Long object for each object pointer and stored it in the map to prevent circular references and dumping the same object again. Other Python objects like list and dict solve this problem by using Py_ReprEnter/Py_ReprLeave without creating a new Long object for each object. Use Py_ReprEnter/Py_ReprLeave for JSON as well. --- Modules/_json.c | 105 ++++++++++++++++++++---------------------------- 1 file changed, 43 insertions(+), 62 deletions(-) diff --git a/Modules/_json.c b/Modules/_json.c index 7580b589e2d937..59744f482d8d26 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1522,52 +1522,46 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, return rv; } else { - PyObject *ident = NULL; + int rc; + if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(obj); - if (ident == NULL) - return -1; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) + rc = Py_ReprEnter(obj); + if (rc != 0) { + if (rc > 0) { PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - Py_DECREF(ident); - return -1; - } - if (PyDict_SetItem(s->markers, ident, obj)) { - Py_DECREF(ident); - return -1; + } + goto bail; } } + newobj = PyObject_CallOneArg(s->defaultfn, obj); if (newobj == NULL) { - Py_XDECREF(ident); - return -1; + goto bail; } if (_Py_EnterRecursiveCall(" while encoding a JSON object")) { Py_DECREF(newobj); - Py_XDECREF(ident); - return -1; + goto bail; } rv = encoder_listencode_obj(s, writer, newobj, indent_level, indent_cache); _Py_LeaveRecursiveCall(); - Py_DECREF(newobj); if (rv) { _PyErr_FormatNote("when serializing %T object", obj); - Py_XDECREF(ident); - return -1; + Py_DECREF(newobj); + goto bail; } - if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) { - Py_XDECREF(ident); - return -1; - } - Py_XDECREF(ident); + + if (s->markers != Py_None) { + Py_ReprLeave(obj); } + Py_DECREF(newobj); return rv; +bail: + if (s->markers != Py_None) { + Py_ReprLeave(obj); + } + return -1; } } @@ -1649,10 +1643,10 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, Py_ssize_t indent_level, PyObject *indent_cache) { /* Encode Python dict dct a JSON term */ - PyObject *ident = NULL; PyObject *items = NULL; PyObject *key, *value; bool first = true; + int rc; if (PyDict_GET_SIZE(dct) == 0) { /* Fast path */ @@ -1660,17 +1654,11 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, } if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(dct); - if (ident == NULL) - goto bail; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) + rc = Py_ReprEnter(dct); + if (rc != 0) { + if (rc > 0) { PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - goto bail; - } - if (PyDict_SetItem(s->markers, ident, dct)) { + } goto bail; } } @@ -1719,11 +1707,6 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, } } - if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) - goto bail; - Py_CLEAR(ident); - } if (s->indent != Py_None && !first) { indent_level--; if (write_newline_indent(writer, indent_level, indent_cache) < 0) { @@ -1734,11 +1717,16 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, if (PyUnicodeWriter_WriteChar(writer, '}')) { goto bail; } + if (s->markers != Py_None) { + Py_ReprLeave(dct); + } return 0; bail: + if (s->markers != Py_None) { + Py_ReprLeave(dct); + } Py_XDECREF(items); - Py_XDECREF(ident); return -1; } @@ -1747,11 +1735,10 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, PyObject *seq, Py_ssize_t indent_level, PyObject *indent_cache) { - PyObject *ident = NULL; PyObject *s_fast = NULL; Py_ssize_t i; + int rc; - ident = NULL; s_fast = PySequence_Fast(seq, "_iterencode_list needs a sequence"); if (s_fast == NULL) return -1; @@ -1761,17 +1748,11 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, } if (s->markers != Py_None) { - int has_key; - ident = PyLong_FromVoidPtr(seq); - if (ident == NULL) - goto bail; - has_key = PyDict_Contains(s->markers, ident); - if (has_key) { - if (has_key != -1) + rc = Py_ReprEnter(seq); + if (rc != 0) { + if (rc > 0) { PyErr_SetString(PyExc_ValueError, "Circular reference detected"); - goto bail; - } - if (PyDict_SetItem(s->markers, ident, seq)) { + } goto bail; } } @@ -1801,11 +1782,6 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, goto bail; } } - if (ident != NULL) { - if (PyDict_DelItem(s->markers, ident)) - goto bail; - Py_CLEAR(ident); - } if (s->indent != Py_None) { indent_level--; @@ -1817,11 +1793,16 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, if (PyUnicodeWriter_WriteChar(writer, ']')) { goto bail; } + if (s->markers != Py_None) { + Py_ReprLeave(seq); + } Py_DECREF(s_fast); return 0; bail: - Py_XDECREF(ident); + if (s->markers != Py_None) { + Py_ReprLeave(seq); + } Py_DECREF(s_fast); return -1; } From af983094b8a7006b2816ccbfe349cca413d5df44 Mon Sep 17 00:00:00 2001 From: Aivars Kalvans Date: Sat, 26 Jul 2025 13:13:01 +0300 Subject: [PATCH 2/5] make the diff smaller --- Modules/_json.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Modules/_json.c b/Modules/_json.c index 59744f482d8d26..b488d23feed738 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1546,6 +1546,7 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, rv = encoder_listencode_obj(s, writer, newobj, indent_level, indent_cache); _Py_LeaveRecursiveCall(); + Py_DECREF(newobj); if (rv) { _PyErr_FormatNote("when serializing %T object", obj); Py_DECREF(newobj); @@ -1555,7 +1556,6 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, if (s->markers != Py_None) { Py_ReprLeave(obj); } - Py_DECREF(newobj); return rv; bail: if (s->markers != Py_None) { @@ -1707,6 +1707,9 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, } } + if (s->markers != Py_None) { + Py_ReprLeave(dct); + } if (s->indent != Py_None && !first) { indent_level--; if (write_newline_indent(writer, indent_level, indent_cache) < 0) { @@ -1717,16 +1720,13 @@ encoder_listencode_dict(PyEncoderObject *s, PyUnicodeWriter *writer, if (PyUnicodeWriter_WriteChar(writer, '}')) { goto bail; } - if (s->markers != Py_None) { - Py_ReprLeave(dct); - } return 0; bail: + Py_XDECREF(items); if (s->markers != Py_None) { Py_ReprLeave(dct); } - Py_XDECREF(items); return -1; } @@ -1783,6 +1783,9 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, } } + if (s->markers != Py_None) { + Py_ReprLeave(seq); + } if (s->indent != Py_None) { indent_level--; if (write_newline_indent(writer, indent_level, indent_cache) < 0) { @@ -1793,9 +1796,6 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, if (PyUnicodeWriter_WriteChar(writer, ']')) { goto bail; } - if (s->markers != Py_None) { - Py_ReprLeave(seq); - } Py_DECREF(s_fast); return 0; From 429356e8783445aa8a64032b28c2643eee139a55 Mon Sep 17 00:00:00 2001 From: Aivars Kalvans Date: Sat, 26 Jul 2025 13:27:30 +0300 Subject: [PATCH 3/5] fix --- Modules/_json.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_json.c b/Modules/_json.c index b488d23feed738..5acbf4be471588 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1549,7 +1549,6 @@ encoder_listencode_obj(PyEncoderObject *s, PyUnicodeWriter *writer, Py_DECREF(newobj); if (rv) { _PyErr_FormatNote("when serializing %T object", obj); - Py_DECREF(newobj); goto bail; } From 2402f3114393dccdb90a5859c09fced6b4388a1a Mon Sep 17 00:00:00 2001 From: Aivars Kalvans Date: Sat, 26 Jul 2025 13:30:05 +0300 Subject: [PATCH 4/5] smaller diff --- Modules/_json.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Modules/_json.c b/Modules/_json.c index 5acbf4be471588..abaeb6c81ac73d 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1781,7 +1781,6 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, goto bail; } } - if (s->markers != Py_None) { Py_ReprLeave(seq); } From 088b3e57a38623f096197c556c4e2d82c5758c72 Mon Sep 17 00:00:00 2001 From: Aivars Kalvans Date: Sat, 26 Jul 2025 13:31:26 +0300 Subject: [PATCH 5/5] better? --- Modules/_json.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_json.c b/Modules/_json.c index abaeb6c81ac73d..6809a70e428dae 100644 --- a/Modules/_json.c +++ b/Modules/_json.c @@ -1784,6 +1784,7 @@ encoder_listencode_list(PyEncoderObject *s, PyUnicodeWriter *writer, if (s->markers != Py_None) { Py_ReprLeave(seq); } + if (s->indent != Py_None) { indent_level--; if (write_newline_indent(writer, indent_level, indent_cache) < 0) { pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy