@@ -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" );
@@ -1204,7 +1224,6 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
1204
1224
return (PyObject * )self ;
1205
1225
}
1206
1226
1207
-
1208
1227
static void
1209
1228
xmlparse_dealloc (xmlparseobject * self )
1210
1229
{
@@ -1213,6 +1232,7 @@ xmlparse_dealloc(xmlparseobject *self)
1213
1232
if (self -> itself != NULL )
1214
1233
XML_ParserFree (self -> itself );
1215
1234
self -> itself = NULL ;
1235
+ Py_CLEAR (self -> parent );
1216
1236
1217
1237
if (self -> handlers != NULL ) {
1218
1238
for (i = 0 ; handler_info [i ].name != NULL ; i ++ )
@@ -1499,6 +1519,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
1499
1519
int i ;
1500
1520
for (i = 0 ; handler_info [i ].name != NULL ; i ++ )
1501
1521
Py_VISIT (op -> handlers [i ]);
1522
+ Py_VISIT (op -> parent );
1502
1523
return 0 ;
1503
1524
}
1504
1525
@@ -1507,6 +1528,10 @@ xmlparse_clear(xmlparseobject *op)
1507
1528
{
1508
1529
clear_handlers (op , 0 );
1509
1530
Py_CLEAR (op -> intern );
1531
+ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling
1532
+ // XML_ParserFree(op->itself), or a subparser could lose its parent
1533
+ // XML_Parser while still making use of it internally.
1534
+ // https://github.com/python/cpython/issues/139400
1510
1535
return 0 ;
1511
1536
}
1512
1537
0 commit comments