]> granicus.if.org Git - python/commitdiff
Issue #16228: Fix a crash in the json module where a list changes size while it is...
authorAntoine Pitrou <solipsis@pitrou.net>
Thu, 1 Nov 2012 18:59:21 +0000 (19:59 +0100)
committerAntoine Pitrou <solipsis@pitrou.net>
Thu, 1 Nov 2012 18:59:21 +0000 (19:59 +0100)
Patch by Serhiy Storchaka.

1  2 
Lib/test/json_tests/test_dump.py
Misc/NEWS
Modules/_json.c

index 4b3386f4f82fca51d40f235d1112fe0840ca389a,fee972eac4ab9b70ff106142496ce70a28a55ff0..237ee35b264edb0580248ac884df9e120e23180b
@@@ -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 Misc/NEWS
Simple merge
diff --cc Modules/_json.c
index fb8bd594e9cefc104de86af3b5248ecdd581c329,01436b6950a04bc0cb1d325794a3614243ee62f4..5b42f6f7186219a34eed2599c05b86f284de04a2
@@@ -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) {
          }
      }
  
-     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 */
              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) {