Skip to content

Commit e1c0470

Browse files
committed
pyexpat.c: Disallow collection of in-use parent parsers
Within libexpat, a parser created via XML_ExternalEntityParserCreate is relying on its parent parser throughout its entire lifetime. Prior to this fix, is was possible for the parent parser to be garbage-collected by CPython. This fixes related reference counting, to stop that from happening.
1 parent d3e3b2b commit e1c0470

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

Modules/pyexpat.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ pyexpat_get_state(PyObject *module)
7272

7373
/* Declarations for objects of type xmlparser */
7474

75-
typedef struct {
75+
typedef struct xmlparseobject_ {
7676
PyObject_HEAD
7777

7878
XML_Parser itself;
79+
struct xmlparseobject_ * parent;
7980
int ordered_attributes; /* Return attributes as a list. */
8081
int specified_attributes; /* Report only specified attributes. */
8182
int in_callback; /* Is a callback active? */
@@ -1065,6 +1066,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
10651066
return NULL;
10661067
}
10671068

1069+
// The new subparser will make use of the parent XML_Parser inside of Expat.
1070+
// So we need to take subparsers into account with the reference counting
1071+
// of their parent parser.
1072+
Py_INCREF(self);
1073+
10681074
new_parser->buffer_size = self->buffer_size;
10691075
new_parser->buffer_used = 0;
10701076
new_parser->buffer = NULL;
@@ -1074,18 +1080,21 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
10741080
new_parser->ns_prefixes = self->ns_prefixes;
10751081
new_parser->itself = XML_ExternalEntityParserCreate(self->itself, context,
10761082
encoding);
1083+
new_parser->parent = self;
10771084
new_parser->handlers = 0;
10781085
new_parser->intern = Py_XNewRef(self->intern);
10791086

10801087
if (self->buffer != NULL) {
10811088
new_parser->buffer = PyMem_Malloc(new_parser->buffer_size);
10821089
if (new_parser->buffer == NULL) {
10831090
Py_DECREF(new_parser);
1091+
Py_DECREF(self);
10841092
return PyErr_NoMemory();
10851093
}
10861094
}
10871095
if (!new_parser->itself) {
10881096
Py_DECREF(new_parser);
1097+
Py_DECREF(self);
10891098
return PyErr_NoMemory();
10901099
}
10911100

@@ -1099,6 +1108,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
10991108
new_parser->handlers = PyMem_New(PyObject *, i);
11001109
if (!new_parser->handlers) {
11011110
Py_DECREF(new_parser);
1111+
Py_DECREF(self);
11021112
return PyErr_NoMemory();
11031113
}
11041114
clear_handlers(new_parser, 1);
@@ -1479,6 +1489,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
14791489
/* namespace_separator is either NULL or contains one char + \0 */
14801490
self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler,
14811491
namespace_separator);
1492+
self->parent = NULL;
14821493
if (self->itself == NULL) {
14831494
PyErr_SetString(PyExc_RuntimeError,
14841495
"XML_ParserCreate failed");
@@ -1538,6 +1549,10 @@ xmlparse_dealloc(PyObject *op)
15381549
XML_ParserFree(self->itself);
15391550
}
15401551
self->itself = NULL;
1552+
if (self->parent != NULL) {
1553+
Py_DECREF(self->parent);
1554+
self->parent = NULL;
1555+
}
15411556

15421557
if (self->handlers != NULL) {
15431558
PyMem_Free(self->handlers);

0 commit comments

Comments
 (0)