Skip to content

Commit aafd60c

Browse files
author
Moshe Zadka
committed
Backported pyexpat memory-leak plugs
backported by Martin van Lowis
1 parent bf9183e commit aafd60c

File tree

2 files changed

+91
-24
lines changed

2 files changed

+91
-24
lines changed

Misc/NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,8 @@ http://sourceforge.net/tracker/index.php?func=detail&aid=<id>&group_id=5470&atid
153153
- distutils/command/install.py - make .get_outputs() produce a list of unique
154154
filenames
155155

156+
- pyexpat.c - removed memory leaks
157+
156158
What's New in Python 2.0?
157159
=========================
158160

Modules/pyexpat.c

+89-24
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
#include "xmlparse.h"
66
#endif
77

8+
#ifndef PyGC_HEAD_SIZE
9+
#define PyGC_HEAD_SIZE 0
10+
#define PyObject_GC_Init(x)
11+
#define PyObject_GC_Fini(m)
12+
#define Py_TPFLAGS_GC 0
13+
#endif
14+
815
enum HandlerTypes {
916
StartElement,
1017
EndElement,
@@ -75,6 +82,7 @@ conv_atts_using_string(XML_Char **atts)
7582
}
7683
if (PyDict_SetItemString(attrs_obj,
7784
(char*)*attrs_k, rv) < 0) {
85+
Py_DECREF(rv);
7886
Py_DECREF(attrs_obj);
7987
attrs_obj = NULL;
8088
goto finally;
@@ -198,12 +206,12 @@ conv_string_len_to_utf8(const XML_Char *str, int len)
198206

199207
/* Callback routines */
200208

201-
static void clear_handlers(xmlparseobject *self);
209+
static void clear_handlers(xmlparseobject *self, int decref);
202210

203211
static void
204212
flag_error(xmlparseobject *self)
205213
{
206-
clear_handlers(self);
214+
clear_handlers(self, 1);
207215
}
208216

209217
#define RC_HANDLER(RC, NAME, PARAMS, INIT, PARAM_FORMAT, CONVERSION, \
@@ -500,6 +508,13 @@ xmlparse_ParseFile(xmlparseobject *self, PyObject *args)
500508
if (!rv || bytes_read == 0)
501509
break;
502510
}
511+
if (rv == 0) {
512+
PyErr_Format(ErrorObject, "%.200s: line %i, column %i",
513+
XML_ErrorString(XML_GetErrorCode(self->itself)),
514+
XML_GetErrorLineNumber(self->itself),
515+
XML_GetErrorColumnNumber(self->itself));
516+
return NULL;
517+
}
503518
return Py_BuildValue("i", rv);
504519
}
505520

@@ -568,10 +583,13 @@ xmlparse_ExternalEntityParserCreate(xmlparseobject *self, PyObject *args)
568583
#endif
569584

570585
new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context,
571-
encoding);
572-
if (!new_parser) {
573-
Py_DECREF(new_parser);
574-
return PyErr_NoMemory();
586+
encoding);
587+
new_parser->handlers = 0;
588+
PyObject_GC_Init(new_parser);
589+
590+
if (!new_parser->itself) {
591+
Py_DECREF(new_parser);
592+
return PyErr_NoMemory();
575593
}
576594

577595
XML_SetUserData(new_parser->itself, (void *)new_parser);
@@ -581,7 +599,11 @@ xmlparse_ExternalEntityParserCreate(xmlparseobject *self, PyObject *args)
581599
/* do nothing */;
582600

583601
new_parser->handlers = malloc(sizeof(PyObject *)*i);
584-
clear_handlers(new_parser);
602+
if (!new_parser->handlers) {
603+
Py_DECREF(new_parser);
604+
return PyErr_NoMemory();
605+
}
606+
clear_handlers(new_parser, 0);
585607

586608
/* then copy handlers from self */
587609
for (i = 0; handler_info[i].name != NULL; i++) {
@@ -615,7 +637,7 @@ static struct PyMethodDef xmlparse_methods[] = {
615637
/* ---------- */
616638

617639

618-
static xmlparseobject *
640+
static PyObject *
619641
newxmlparseobject(char *encoding, char *namespace_separator)
620642
{
621643
int i;
@@ -635,12 +657,14 @@ newxmlparseobject(char *encoding, char *namespace_separator)
635657

636658
self->returns_unicode = 1;
637659
#endif
660+
self->handlers = NULL;
638661
if (namespace_separator) {
639662
self->itself = XML_ParserCreateNS(encoding, *namespace_separator);
640663
}
641664
else{
642665
self->itself = XML_ParserCreate(encoding);
643666
}
667+
PyObject_GC_Init(self);
644668
if (self->itself == NULL) {
645669
PyErr_SetString(PyExc_RuntimeError,
646670
"XML_ParserCreate failed");
@@ -653,22 +677,30 @@ newxmlparseobject(char *encoding, char *namespace_separator)
653677
/* do nothing */;
654678

655679
self->handlers = malloc(sizeof(PyObject *)*i);
656-
clear_handlers(self);
680+
if (!self->handlers){
681+
Py_DECREF(self);
682+
return PyErr_NoMemory();
683+
}
684+
clear_handlers(self, 0);
657685

658-
return self;
686+
return (PyObject*)self;
659687
}
660688

661689

662690
static void
663691
xmlparse_dealloc(xmlparseobject *self)
664692
{
665693
int i;
694+
PyObject_GC_Fini(self);
666695
if (self->itself)
667696
XML_ParserFree(self->itself);
668697
self->itself = NULL;
669698

670-
for (i=0; handler_info[i].name != NULL; i++) {
671-
Py_XDECREF(self->handlers[i]);
699+
if(self->handlers){
700+
for (i=0; handler_info[i].name != NULL; i++) {
701+
Py_XDECREF(self->handlers[i]);
702+
}
703+
free (self->handlers);
672704
}
673705
#if PY_MAJOR_VERSION == 1 && PY_MINOR_VERSION < 6
674706
/* Code for versions before 1.6 */
@@ -780,14 +812,37 @@ xmlparse_setattr(xmlparseobject *self, char *name, PyObject *v)
780812
return -1;
781813
}
782814

815+
#ifdef WITH_CYCLE_GC
816+
static int
817+
xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
818+
{
819+
int i, err;
820+
for (i = 0; handler_info[i].name != NULL; i++) {
821+
if (!op->handlers[i])
822+
continue;
823+
err = visit(op->handlers[i], arg);
824+
if (err)
825+
return err;
826+
}
827+
return 0;
828+
}
829+
830+
static int
831+
xmlparse_clear(xmlparseobject *op)
832+
{
833+
clear_handlers(op, 1);
834+
return 0;
835+
}
836+
#endif
837+
783838
static char Xmlparsetype__doc__[] =
784839
"XML parser";
785840

786841
static PyTypeObject Xmlparsetype = {
787842
PyObject_HEAD_INIT(NULL)
788843
0, /*ob_size*/
789844
"xmlparser", /*tp_name*/
790-
sizeof(xmlparseobject), /*tp_basicsize*/
845+
sizeof(xmlparseobject) + PyGC_HEAD_SIZE,/*tp_basicsize*/
791846
0, /*tp_itemsize*/
792847
/* methods */
793848
(destructor)xmlparse_dealloc, /*tp_dealloc*/
@@ -802,10 +857,17 @@ static PyTypeObject Xmlparsetype = {
802857
(hashfunc)0, /*tp_hash*/
803858
(ternaryfunc)0, /*tp_call*/
804859
(reprfunc)0, /*tp_str*/
805-
806-
/* Space for future expansion */
807-
0L,0L,0L,0L,
808-
Xmlparsetype__doc__ /* Documentation string */
860+
0, /* tp_getattro */
861+
0, /* tp_setattro */
862+
0, /* tp_as_buffer */
863+
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_GC, /*tp_flags*/
864+
Xmlparsetype__doc__, /* Documentation string */
865+
#ifdef WITH_CYCLE_GC
866+
(traverseproc)xmlparse_traverse, /* tp_traverse */
867+
(inquiry)xmlparse_clear /* tp_clear */
868+
#else
869+
0, 0
870+
#endif
809871
};
810872

811873
/* End of code for xmlparser objects */
@@ -968,14 +1030,17 @@ initpyexpat(void)
9681030
}
9691031

9701032
static void
971-
clear_handlers(xmlparseobject *self)
1033+
clear_handlers(xmlparseobject *self, int decref)
9721034
{
973-
int i = 0;
974-
975-
for (; handler_info[i].name!=NULL; i++) {
976-
self->handlers[i]=NULL;
977-
handler_info[i].setter(self->itself, NULL);
978-
}
1035+
int i = 0;
1036+
1037+
for (; handler_info[i].name!=NULL; i++) {
1038+
if (decref){
1039+
Py_XDECREF(self->handlers[i]);
1040+
}
1041+
self->handlers[i]=NULL;
1042+
handler_info[i].setter(self->itself, NULL);
1043+
}
9791044
}
9801045

9811046
typedef void (*pairsetter)(XML_Parser, void *handler1, void *handler2);

0 commit comments

Comments
 (0)