@@ -58,6 +58,15 @@ typedef struct {
58
58
PyObject_HEAD
59
59
60
60
XML_Parser itself ;
61
+ /*
62
+ * Strong reference to a parent `xmlparseobject` if this parser
63
+ * is a child parser. Set to NULL if this parser is a root parser.
64
+ * This is needed to keep the parent parser alive as long as it has
65
+ * at least one child parser.
66
+ *
67
+ * See https://github.com/python/cpython/issues/139400 for details.
68
+ */
69
+ PyObject * parent ;
61
70
int ordered_attributes ; /* Return attributes as a list. */
62
71
int specified_attributes ; /* Report only specified attributes. */
63
72
int in_callback ; /* Is a callback active? */
@@ -967,6 +976,12 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
967
976
new_parser = PyObject_GC_New (xmlparseobject , & Xmlparsetype );
968
977
if (new_parser == NULL )
969
978
return NULL ;
979
+
980
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
981
+ // So we need to take subparsers into account with the reference counting
982
+ // of their parent parser.
983
+ Py_INCREF (self );
984
+
970
985
new_parser -> buffer_size = self -> buffer_size ;
971
986
new_parser -> buffer_used = 0 ;
972
987
new_parser -> buffer = NULL ;
@@ -976,6 +991,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
976
991
new_parser -> ns_prefixes = self -> ns_prefixes ;
977
992
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
978
993
encoding );
994
+ new_parser -> parent = (PyObject * )self ;
979
995
new_parser -> handlers = 0 ;
980
996
new_parser -> intern = self -> intern ;
981
997
Py_XINCREF (new_parser -> intern );
@@ -984,11 +1000,13 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
984
1000
new_parser -> buffer = PyMem_Malloc (new_parser -> buffer_size );
985
1001
if (new_parser -> buffer == NULL ) {
986
1002
Py_DECREF (new_parser );
1003
+ Py_DECREF (self );
987
1004
return PyErr_NoMemory ();
988
1005
}
989
1006
}
990
1007
if (!new_parser -> itself ) {
991
1008
Py_DECREF (new_parser );
1009
+ Py_DECREF (self );
992
1010
return PyErr_NoMemory ();
993
1011
}
994
1012
@@ -1001,6 +1019,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1001
1019
new_parser -> handlers = PyMem_New (PyObject * , i );
1002
1020
if (!new_parser -> handlers ) {
1003
1021
Py_DECREF (new_parser );
1022
+ Py_DECREF (self );
1004
1023
return PyErr_NoMemory ();
1005
1024
}
1006
1025
clear_handlers (new_parser , 1 );
@@ -1175,6 +1194,7 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
1175
1194
/* namespace_separator is either NULL or contains one char + \0 */
1176
1195
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1177
1196
namespace_separator );
1197
+ self -> parent = NULL ;
1178
1198
if (self -> itself == NULL ) {
1179
1199
PyErr_SetString (PyExc_RuntimeError ,
1180
1200
"XML_ParserCreate failed" );
@@ -1213,6 +1233,7 @@ xmlparse_dealloc(xmlparseobject *self)
1213
1233
if (self -> itself != NULL )
1214
1234
XML_ParserFree (self -> itself );
1215
1235
self -> itself = NULL ;
1236
+ Py_CLEAR (self -> parent );
1216
1237
1217
1238
if (self -> handlers != NULL ) {
1218
1239
for (i = 0 ; handler_info [i ].name != NULL ; i ++ )
@@ -1499,6 +1520,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
1499
1520
int i ;
1500
1521
for (i = 0 ; handler_info [i ].name != NULL ; i ++ )
1501
1522
Py_VISIT (op -> handlers [i ]);
1523
+ Py_VISIT (op -> parent );
1502
1524
return 0 ;
1503
1525
}
1504
1526
@@ -1507,6 +1529,10 @@ xmlparse_clear(xmlparseobject *op)
1507
1529
{
1508
1530
clear_handlers (op , 0 );
1509
1531
Py_CLEAR (op -> intern );
1532
+ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling
1533
+ // XML_ParserFree(op->itself), or a subparser could lose its parent
1534
+ // XML_Parser while still making use of it internally.
1535
+ // https://github.com/python/cpython/issues/139400
1510
1536
return 0 ;
1511
1537
}
1512
1538
0 commit comments