From: Antoine Pitrou Date: Thu, 1 Nov 2012 18:59:21 +0000 (+0100) Subject: Issue #16228: Fix a crash in the json module where a list changes size while it is... X-Git-Tag: v3.3.1rc1~704 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5ebe65f8cb541b10f07fb6ce2b4283a26c7e1d80;p=python Issue #16228: Fix a crash in the json module where a list changes size while it is being encoded. Patch by Serhiy Storchaka. --- 5ebe65f8cb541b10f07fb6ce2b4283a26c7e1d80 diff --cc Lib/test/json_tests/test_dump.py index 4b3386f4f8,fee972eac4..237ee35b26 --- a/Lib/test/json_tests/test_dump.py +++ b/Lib/test/json_tests/test_dump.py @@@ -20,22 -19,14 +20,30 @@@ class TestDump {2: 3.0, 4.0: 5, False: 1, 6: True}, sort_keys=True), '{"false": 1, "2": 3.0, "4.0": 5, "6": true}') + # Issue 16228: Crash on encoding resized list + def test_encode_mutated(self): + a = [object()] * 10 + def crasher(obj): + del a[-1] + self.assertEqual(self.dumps(a, default=crasher), + '[null, null, null, null, null]') + class TestPyDump(TestDump, PyTest): pass -class TestCDump(TestDump, CTest): pass + +class TestCDump(TestDump, CTest): + + # The size requirement here is hopefully over-estimated (actual + # memory consumption depending on implementation details, and also + # system memory management, since this may allocate a lot of + # small objects). + + @bigmemtest(size=_1G, memuse=1) + def test_large_list(self, size): + N = int(30 * 1024 * 1024 * (size / _1G)) + l = [1] * N + encoded = self.dumps(l) + self.assertEqual(len(encoded), N * 3) + self.assertEqual(encoded[:1], "[") + self.assertEqual(encoded[-2:], "1]") + self.assertEqual(encoded[1:-2], "1, " * (N - 1)) diff --cc Modules/_json.c index fb8bd594e9,01436b6950..5b42f6f718 --- a/Modules/_json.c +++ b/Modules/_json.c @@@ -1675,10 -1598,9 +1673,9 @@@ encoder_listencode_list(PyEncoderObjec s_fast = PySequence_Fast(seq, "_iterencode_list needs a sequence"); if (s_fast == NULL) return -1; - num_items = PySequence_Fast_GET_SIZE(s_fast); - if (num_items == 0) { + if (PySequence_Fast_GET_SIZE(s_fast) == 0) { Py_DECREF(s_fast); - return PyList_Append(rval, empty_array); + return _PyAccu_Accumulate(acc, empty_array); } if (s->markers != Py_None) { @@@ -1697,8 -1619,7 +1694,7 @@@ } } - seq_items = PySequence_Fast_ITEMS(s_fast); - if (PyList_Append(rval, open_array)) + if (_PyAccu_Accumulate(acc, open_array)) goto bail; if (s->indent != Py_None) { /* TODO: DOES NOT RUN */ @@@ -1709,13 -1630,13 +1705,13 @@@ buf += newline_indent */ } - for (i = 0; i < num_items; i++) { - PyObject *obj = seq_items[i]; + for (i = 0; i < PySequence_Fast_GET_SIZE(s_fast); i++) { + PyObject *obj = PySequence_Fast_GET_ITEM(s_fast, i); if (i) { - if (PyList_Append(rval, s->item_separator)) + if (_PyAccu_Accumulate(acc, s->item_separator)) goto bail; } - if (encoder_listencode_obj(s, rval, obj, indent_level)) + if (encoder_listencode_obj(s, acc, obj, indent_level)) goto bail; } if (ident != NULL) {