Commits

Anonymous committed 6b0ff52

Backported pyexpat memory-leak plugs
backported by Martin van Lowis

Comments (0)

Files changed (2)

 - distutils/command/install.py - make .get_outputs() produce a list of unique 
                                  filenames
 
+- pyexpat.c - removed memory leaks
+
 What's New in Python 2.0?
 =========================
 

Modules/pyexpat.c

 #include "xmlparse.h"
 #endif
 
+#ifndef PyGC_HEAD_SIZE
+#define PyGC_HEAD_SIZE 0
+#define PyObject_GC_Init(x)
+#define PyObject_GC_Fini(m)
+#define Py_TPFLAGS_GC 0
+#endif
+
 enum HandlerTypes {
     StartElement,
     EndElement,
             }
             if (PyDict_SetItemString(attrs_obj,
                                      (char*)*attrs_k, rv) < 0) {
+                Py_DECREF(rv);
                 Py_DECREF(attrs_obj);
                 attrs_obj = NULL;
                 goto finally;
 
 /* Callback routines */
 
-static void clear_handlers(xmlparseobject *self);
+static void clear_handlers(xmlparseobject *self, int decref);
 
 static void
 flag_error(xmlparseobject *self)
 {
-    clear_handlers(self);
+    clear_handlers(self, 1);
 }
 
 #define RC_HANDLER(RC, NAME, PARAMS, INIT, PARAM_FORMAT, CONVERSION, \
         if (!rv || bytes_read == 0)
             break;
     }
+    if (rv == 0) {
+        PyErr_Format(ErrorObject, "%.200s: line %i, column %i",
+                     XML_ErrorString(XML_GetErrorCode(self->itself)),
+                     XML_GetErrorLineNumber(self->itself),
+                     XML_GetErrorColumnNumber(self->itself));
+        return NULL;
+    }
     return Py_BuildValue("i", rv);
 }
 
 #endif
     
     new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context,
-							encoding);    
-    if (!new_parser) {
-        Py_DECREF(new_parser);
-        return PyErr_NoMemory();
+							encoding);
+    new_parser->handlers = 0;
+    PyObject_GC_Init(new_parser);
+
+    if (!new_parser->itself) {
+	    Py_DECREF(new_parser);
+	    return PyErr_NoMemory();
     }
 
     XML_SetUserData(new_parser->itself, (void *)new_parser);
       /* do nothing */;
 
     new_parser->handlers = malloc(sizeof(PyObject *)*i);
-    clear_handlers(new_parser);
+    if (!new_parser->handlers) {
+	    Py_DECREF(new_parser);
+	    return PyErr_NoMemory();
+    }
+    clear_handlers(new_parser, 0);
 
     /* then copy handlers from self */
     for (i = 0; handler_info[i].name != NULL; i++) {
 /* ---------- */
 
 
-static xmlparseobject *
+static PyObject *
 newxmlparseobject(char *encoding, char *namespace_separator)
 {
     int i;
 
     self->returns_unicode = 1;
 #endif
+    self->handlers = NULL;
     if (namespace_separator) {
         self->itself = XML_ParserCreateNS(encoding, *namespace_separator);
     }
     else{
         self->itself = XML_ParserCreate(encoding);
     }
+    PyObject_GC_Init(self);
     if (self->itself == NULL) {
         PyErr_SetString(PyExc_RuntimeError, 
                         "XML_ParserCreate failed");
         /* do nothing */;
 
     self->handlers = malloc(sizeof(PyObject *)*i);
-    clear_handlers(self);
+    if (!self->handlers){
+	    Py_DECREF(self);
+	    return PyErr_NoMemory();
+    }
+    clear_handlers(self, 0);
 
-    return self;
+    return (PyObject*)self;
 }
 
 
 xmlparse_dealloc(xmlparseobject *self)
 {
     int i;
+    PyObject_GC_Fini(self);
     if (self->itself)
         XML_ParserFree(self->itself);
     self->itself = NULL;
 
-    for (i=0; handler_info[i].name != NULL; i++) {
-        Py_XDECREF(self->handlers[i]);
+    if(self->handlers){
+	    for (i=0; handler_info[i].name != NULL; i++) {
+		    Py_XDECREF(self->handlers[i]);
+	    }
+	    free (self->handlers);
     }
 #if PY_MAJOR_VERSION == 1 && PY_MINOR_VERSION < 6
     /* Code for versions before 1.6 */
     return -1;
 }
 
+#ifdef WITH_CYCLE_GC
+static int
+xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
+{
+	int i, err;
+	for (i = 0; handler_info[i].name != NULL; i++) {
+		if (!op->handlers[i])
+			continue;
+		err = visit(op->handlers[i], arg);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
+static int
+xmlparse_clear(xmlparseobject *op)
+{
+	clear_handlers(op, 1);
+	return 0;
+}
+#endif
+
 static char Xmlparsetype__doc__[] = 
 "XML parser";
 
 	PyObject_HEAD_INIT(NULL)
 	0,				/*ob_size*/
 	"xmlparser",			/*tp_name*/
-	sizeof(xmlparseobject),		/*tp_basicsize*/
+	sizeof(xmlparseobject) + PyGC_HEAD_SIZE,/*tp_basicsize*/
 	0,				/*tp_itemsize*/
 	/* methods */
 	(destructor)xmlparse_dealloc,	/*tp_dealloc*/
 	(hashfunc)0,		/*tp_hash*/
 	(ternaryfunc)0,		/*tp_call*/
 	(reprfunc)0,		/*tp_str*/
-
-	/* Space for future expansion */
-	0L,0L,0L,0L,
-	Xmlparsetype__doc__ /* Documentation string */
+	0,		/* tp_getattro */
+	0,		/* tp_setattro */
+	0,		/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/	
+	Xmlparsetype__doc__, /* Documentation string */
+#ifdef WITH_CYCLE_GC
+	(traverseproc)xmlparse_traverse,	/* tp_traverse */
+	(inquiry)xmlparse_clear		/* tp_clear */
+#else
+	0, 0
+#endif
 };
 
 /* End of code for xmlparser objects */
 }
 
 static void
-clear_handlers(xmlparseobject *self)
+clear_handlers(xmlparseobject *self, int decref)
 {
-    int i = 0;
+	int i = 0;
 
-    for (; handler_info[i].name!=NULL; i++) {
-        self->handlers[i]=NULL;
-        handler_info[i].setter(self->itself, NULL);
-    }
+	for (; handler_info[i].name!=NULL; i++) {
+		if (decref){
+			Py_XDECREF(self->handlers[i]);
+		}
+		self->handlers[i]=NULL;
+		handler_info[i].setter(self->itself, NULL);
+	}
 }
 
 typedef void (*pairsetter)(XML_Parser, void *handler1, void *handler2);
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.