[Python-Dev] Re: [Python-checkins] CVS: python/dist/src/Modules _tkinter.c,1.99,1.100

Michael Hudson mwh21@cam.ac.uk
19 Jun 2000 00:15:25 +0100


"A.M. Kuchling" <akuchling@users.sourceforge.net> writes:

> Update of /cvsroot/python/python/dist/src/Modules
> In directory slayer.i.sourceforge.net:/tmp/cvs-serv10064/Modules
> 
> Modified Files:
> 	_tkinter.c 
> Log Message:
> Patch from /F:
> this patch adds a fast _flatten function to the _tkinter
> module, and imports it from Tkinter.py (if available).
> 
> this speeds up canvas operations like create_line and
> create_polygon.  for example, a create_line with 5000
> vertices runs about 50 times faster with this patch in
> place.

Unfortunately this introduces another Way To Make Python Core:

[mwh21@atrus build]$ ./python 
Python 1.6a2 (#4, Jun 18 2000, 23:57:36)  [GCC 2.95.1 19990816/Linux (release)] on linux2
Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam
Copyright 1995-2000 Corporation for National Research Initiatives (CNRI)
>>> import Tkinter
>>> l = []
>>> l.append(l)
>>> Tkinter._flatten(l)
Segmentation fault (core dumped)

Here's a simple solution:

Index: _tkinter.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/_tkinter.c,v
retrieving revision 1.100
diff -u -r1.100 _tkinter.c
--- _tkinter.c	2000/06/18 18:45:50	1.100
+++ _tkinter.c	2000/06/18 23:13:22
@@ -2001,13 +2001,16 @@
 }
 
 static int
-_flatten1(FlattenContext* context, PyObject* item)
+_flatten1(FlattenContext* context, PyObject* item, int depth)
 {
 	/* add tuple or list to argument tuple (recursively) */
 
 	int i, size;
 
-	if (PyList_Check(item)) {
+	if (depth > 1000) {
+		PyErr_SetString(PyExc_ValueError,"nesting too deep in _flatten");
+		return 0;
+	} else if (PyList_Check(item)) {
 		size = PyList_GET_SIZE(item);
 		/* preallocate (assume no nesting) */
 		if (context->size + size > context->maxsize && !_bump(context, size))
@@ -2016,7 +2019,7 @@
 		for (i = 0; i < size; i++) {
 			PyObject *o = PyList_GET_ITEM(item, i);
 			if (PyList_Check(o) || PyTuple_Check(o)) {
-				if (!_flatten1(context, o))
+				if (!_flatten1(context, o, depth + 1))
 					return 0;
 			} else if (o != Py_None) {
 				if (context->size + 1 > context->maxsize && !_bump(context, 1))
@@ -2033,7 +2036,7 @@
 		for (i = 0; i < size; i++) {
 			PyObject *o = PyTuple_GET_ITEM(item, i);
 			if (PyList_Check(o) || PyTuple_Check(o)) {
-				if (!_flatten1(context, o))
+				if (!_flatten1(context, o, depth + 1))
 					return 0;
 			} else if (o != Py_None) {
 				if (context->size + 1 > context->maxsize && !_bump(context, 1))
@@ -2068,7 +2071,7 @@
 	
 	context.size = 0;
 
-	if (!_flatten1(&context, item))
+	if (!_flatten1(&context, item,0))
 		return NULL;
 
 	if (_PyTuple_Resize(&context.tuple, context.size, 0))

"seems to work"; I've not tested it for performance, but I can't
believe this is too hard a hit.

Cheers,
M.