@@ -3080,33 +3080,60 @@ Tkapp_Dealloc(PyObject *op)
30803080
30813081/**** Tkinter Module ****/
30823082
3083+ typedef struct {
3084+ PyObject * tuple ;
3085+ Py_ssize_t size ; /* current size */
3086+ Py_ssize_t maxsize ; /* allocated size */
3087+ } FlattenContext ;
3088+
30833089static int
3084- _flatten1 (PyTupleWriter * writer , PyObject * item , int depth )
3090+ _bump (FlattenContext * context , Py_ssize_t size )
3091+ {
3092+ /* expand tuple to hold (at least) size new items.
3093+ return true if successful, false if an exception was raised */
3094+
3095+ Py_ssize_t maxsize = context -> maxsize * 2 ; /* never overflows */
3096+
3097+ if (maxsize < context -> size + size )
3098+ maxsize = context -> size + size ; /* never overflows */
3099+
3100+ context -> maxsize = maxsize ;
3101+
3102+ return _PyTuple_Resize (& context -> tuple , maxsize ) >= 0 ;
3103+ }
3104+
3105+ static int
3106+ _flatten1 (FlattenContext * context , PyObject * item , int depth )
30853107{
30863108 /* add tuple or list to argument tuple (recursively) */
30873109
3110+ Py_ssize_t i , size ;
3111+
30883112 if (depth > 1000 ) {
30893113 PyErr_SetString (PyExc_ValueError ,
30903114 "nesting too deep in _flatten" );
30913115 return 0 ;
3092- }
3093-
3094- if (PyTuple_Check (item ) || PyList_Check (item )) {
3095- Py_ssize_t size = PySequence_Fast_GET_SIZE (item );
3116+ } else if (PyTuple_Check (item ) || PyList_Check (item )) {
3117+ size = PySequence_Fast_GET_SIZE (item );
3118+ /* preallocate (assume no nesting) */
3119+ if (context -> size + size > context -> maxsize &&
3120+ !_bump (context , size ))
3121+ return 0 ;
30963122 /* copy items to output tuple */
3097- for (Py_ssize_t i = 0 ; i < size ; i ++ ) {
3123+ for (i = 0 ; i < size ; i ++ ) {
30983124 PyObject * o = PySequence_Fast_GET_ITEM (item , i );
30993125 if (PyList_Check (o ) || PyTuple_Check (o )) {
3100- if (!_flatten1 (writer , o , depth + 1 ))
3126+ if (!_flatten1 (context , o , depth + 1 ))
31013127 return 0 ;
31023128 } else if (o != Py_None ) {
3103- if (PyTupleWriter_Add (writer , o ) < 0 ) {
3129+ if (context -> size + 1 > context -> maxsize &&
3130+ !_bump (context , 1 ))
31043131 return 0 ;
3105- }
3132+ PyTuple_SET_ITEM (context -> tuple ,
3133+ context -> size ++ , Py_NewRef (o ));
31063134 }
31073135 }
3108- }
3109- else {
3136+ } else {
31103137 PyErr_SetString (PyExc_TypeError , "argument must be sequence" );
31113138 return 0 ;
31123139 }
@@ -3125,25 +3152,29 @@ static PyObject *
31253152_tkinter__flatten (PyObject * module , PyObject * item )
31263153/*[clinic end generated code: output=cad02a3f97f29862 input=6b9c12260aa1157f]*/
31273154{
3128- Py_ssize_t maxsize = PySequence_Size (item );
3129- if (maxsize < 0 ) {
3155+ FlattenContext context ;
3156+
3157+ context .maxsize = PySequence_Size (item );
3158+ if (context .maxsize < 0 )
31303159 return NULL ;
3131- }
3132- if (maxsize == 0 ) {
3160+ if (context .maxsize == 0 )
31333161 return PyTuple_New (0 );
3134- }
31353162
3136- PyTupleWriter * writer = PyTupleWriter_Create ( maxsize );
3137- if (writer == NULL ) {
3163+ context . tuple = PyTuple_New ( context . maxsize );
3164+ if (! context . tuple )
31383165 return NULL ;
3139- }
31403166
3141- if (!_flatten1 (writer , item , 0 )) {
3142- PyTupleWriter_Discard (writer );
3167+ context .size = 0 ;
3168+
3169+ if (!_flatten1 (& context , item , 0 )) {
3170+ Py_XDECREF (context .tuple );
31433171 return NULL ;
31443172 }
31453173
3146- return PyTupleWriter_Finish (writer );
3174+ if (_PyTuple_Resize (& context .tuple , context .size ))
3175+ return NULL ;
3176+
3177+ return context .tuple ;
31473178}
31483179
31493180/*[clinic input]
0 commit comments