cpython: 656c13024ede (original) (raw)

Mercurial > cpython

changeset 72756:656c13024ede

Issue #12911: Fix memory consumption when calculating the repr() of huge tuples or lists. This introduces a small private API for this common pattern. The issue has been discovered thanks to Martin's huge-mem buildbot. [#12911]

Antoine Pitrou solipsis@pitrou.net
date Thu, 06 Oct 2011 19:04:12 +0200
parents 9a91ab415109(current diff)f9f782f2369e(diff)
children e685b02ddcac
files Include/Python.h Makefile.pre.in Misc/NEWS Objects/listobject.c Objects/tupleobject.c PC/VC6/pythoncore.dsp PC/VS7.1/pythoncore.vcproj PCbuild/pythoncore.vcproj
diffstat 13 files changed, 268 insertions(+), 84 deletions(-)[+] [-] Include/Python.h 2 Include/accu.h 35 Lib/test/test_list.py 11 Lib/test/test_tuple.py 10 Makefile.pre.in 2 Misc/NEWS 3 Objects/accu.c 114 Objects/listobject.c 79 Objects/tupleobject.c 73 PC/VC6/pythoncore.dsp 4 PC/VS7.1/pythoncore.vcproj 3 PC/VS8.0/pythoncore.vcproj 8 PCbuild/pythoncore.vcproj 8

line wrap: on

line diff

--- a/Include/Python.h +++ b/Include/Python.h @@ -101,7 +101,7 @@ #include "warnings.h" #include "weakrefobject.h" #include "structseq.h" - +#include "accu.h" #include "codecs.h" #include "pyerrors.h"

new file mode 100644 --- /dev/null +++ b/Include/accu.h @@ -0,0 +1,35 @@ +#ifndef Py_LIMITED_API +#ifndef Py_ACCU_H +#define Py_ACCU_H + +/*** This is a private API for use by the interpreter and the stdlib.

+} _PyAccu; + +PyAPI_FUNC(int) _PyAccu_Init(_PyAccu *acc); +PyAPI_FUNC(int) _PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode); +PyAPI_FUNC(PyObject *) _PyAccu_FinishAsList(_PyAccu *acc); +PyAPI_FUNC(PyObject *) _PyAccu_Finish(_PyAccu *acc); +PyAPI_FUNC(void) _PyAccu_Destroy(_PyAccu acc); + +#ifdef __cplusplus +} +#endif + +#endif / Py_ACCU_H / +#endif / Py_LIMITED_API */

--- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -59,6 +59,17 @@ class ListTest(list_tests.CommonTest): self.assertRaises((MemoryError, OverflowError), mul, lst, n) self.assertRaises((MemoryError, OverflowError), imul, lst, n)

+ + def test_main(verbose=None): support.run_unittest(ListTest)

--- a/Lib/test/test_tuple.py +++ b/Lib/test/test_tuple.py @@ -154,6 +154,16 @@ class TupleTest(seq_tests.CommonTest): # Trying to untrack an unfinished tuple could crash Python self._not_tracked(tuple(gc.collect() for i in range(101)))

+ def test_main(): support.run_unittest(TupleTest)

--- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -342,6 +342,7 @@ PYTHON_OBJS= [](#l5.3)

Objects

OBJECT_OBJS= [](#l5.5) Objects/abstract.o [](#l5.6) + Objects/accu.o [](#l5.7) Objects/boolobject.o [](#l5.8) Objects/bytes_methods.o [](#l5.9) Objects/bytearrayobject.o [](#l5.10) @@ -661,6 +662,7 @@ Objects/typeobject.o: $(srcdir)/Objects/ PYTHON_HEADERS= [](#l5.12) Include/Python.h [](#l5.13) Include/abstract.h [](#l5.14) + Include/accu.h [](#l5.15) Include/asdl.h [](#l5.16) Include/ast.h [](#l5.17) Include/bltinmodule.h [](#l5.18)

--- a/Misc/NEWS +++ b/Misc/NEWS @@ -10,6 +10,9 @@ What's New in Python 3.3 Alpha 1? Core and Builtins ----------------- +- Issue #12911: Fix memory consumption when calculating the repr() of huge

new file mode 100644 --- /dev/null +++ b/Objects/accu.c @@ -0,0 +1,114 @@ +/* Accumulator struct implementation */ + +#include "Python.h" + +static PyObject * +join_list_unicode(PyObject *lst) +{

+} + +int +_PyAccu_Init(_PyAccu *acc) +{

+} + +static int +flush_accumulator(_PyAccu *acc) +{

+} + +int +_PyAccu_Accumulate(_PyAccu *acc, PyObject *unicode) +{

+

+} + +PyObject * +_PyAccu_FinishAsList(_PyAccu *acc) +{

+

+} + +PyObject * +_PyAccu_Finish(_PyAccu *acc) +{

+} + +void +_PyAccu_Destroy(_PyAccu *acc) +{

+}

--- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -321,70 +321,59 @@ static PyObject * list_repr(PyListObject *v) { Py_ssize_t i;

+

+

i = Py_ReprEnter((PyObject*)v); if (i != 0) { return i > 0 ? PyUnicode_FromString("[...]") : NULL; }

/* Do repr() on each element. Note that this may mutate the list, so must refetch the list size on each iteration. */ for (i = 0; i < Py_SIZE(v); ++i) {

- s = PyUnicode_FromString("]");

-Done:

+error:

} static Py_ssize_t

--- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -240,13 +240,20 @@ static PyObject * tuplerepr(PyTupleObject *v) { Py_ssize_t i, n;

n = Py_SIZE(v); if (n == 0) return PyUnicode_FromString("()");

+ /* While not mutable, it is still possible to end up with a cycle in a tuple through an object that stores itself within a tuple (and thus infinitely asks for the repr of itself). This should only be @@ -256,52 +263,42 @@ tuplerepr(PyTupleObject *v) return i > 0 ? PyUnicode_FromString("(...)") : NULL; }

+

/* Do repr() on each element. */ for (i = 0; i < n; ++i) { if (Py_EnterRecursiveCall(" while getting the repr of a tuple"))

- -Done:

+error:

} /* The addend 82520, was selected from the range(0, 1000000) for

--- a/PC/VC6/pythoncore.dsp +++ b/PC/VC6/pythoncore.dsp @@ -205,6 +205,10 @@ SOURCE=....\Objects\abstract.c

End Source File

Begin Source File

+SOURCE=....\Objects\accu.c +# End Source File +# Begin Source File + SOURCE=....\Parser\acceler.c

End Source File

Begin Source File

--- a/PC/VS7.1/pythoncore.vcproj +++ b/PC/VS7.1/pythoncore.vcproj @@ -445,6 +445,9 @@ RelativePath="....\Objects\abstract.c"> <File + RelativePath="....\Objects\accu.c"> + + <File RelativePath="....\Parser\acceler.c"> <File

--- a/PC/VS8.0/pythoncore.vcproj +++ b/PC/VS8.0/pythoncore.vcproj @@ -635,6 +635,10 @@ > <File + RelativePath="....\Include\accu.h" + > + + <File RelativePath="....\Include\asdl.h" > @@ -1447,6 +1451,10 @@ > <File + RelativePath="....\Objects\accu.c" + > + + <File RelativePath="....\Objects\boolobject.c" >

--- a/PCbuild/pythoncore.vcproj +++ b/PCbuild/pythoncore.vcproj @@ -635,6 +635,10 @@ > <File + RelativePath="..\Include\accu.h" + > + + <File RelativePath="..\Include\asdl.h" > @@ -1455,6 +1459,10 @@ > <File + RelativePath="..\Objects\accu.c" + > + + <File RelativePath="..\Objects\boolobject.c" >