@@ -74,6 +74,15 @@ typedef struct {
74
74
PyObject_HEAD
75
75
76
76
XML_Parser itself ;
77
+ /*
78
+ * Strong reference to a parent `xmlparseobject` if this parser
79
+ * is a child parser. Set to NULL if this parser is a root parser.
80
+ * This is needed to keep the parent parser alive as long as it has
81
+ * at least one child parser.
82
+ *
83
+ * See https://github.com/python/cpython/issues/139400 for details.
84
+ */
85
+ PyObject * parent ;
77
86
int ordered_attributes ; /* Return attributes as a list. */
78
87
int specified_attributes ; /* Report only specified attributes. */
79
88
int in_callback ; /* Is a callback active? */
@@ -1019,6 +1028,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1019
1028
return NULL ;
1020
1029
}
1021
1030
1031
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
1032
+ // So we need to take subparsers into account with the reference counting
1033
+ // of their parent parser.
1034
+ Py_INCREF (self );
1035
+
1022
1036
new_parser -> buffer_size = self -> buffer_size ;
1023
1037
new_parser -> buffer_used = 0 ;
1024
1038
new_parser -> buffer = NULL ;
@@ -1028,18 +1042,21 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1028
1042
new_parser -> ns_prefixes = self -> ns_prefixes ;
1029
1043
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
1030
1044
encoding );
1045
+ new_parser -> parent = (PyObject * )self ;
1031
1046
new_parser -> handlers = 0 ;
1032
1047
new_parser -> intern = Py_XNewRef (self -> intern );
1033
1048
1034
1049
if (self -> buffer != NULL ) {
1035
1050
new_parser -> buffer = PyMem_Malloc (new_parser -> buffer_size );
1036
1051
if (new_parser -> buffer == NULL ) {
1037
1052
Py_DECREF (new_parser );
1053
+ Py_DECREF (self );
1038
1054
return PyErr_NoMemory ();
1039
1055
}
1040
1056
}
1041
1057
if (!new_parser -> itself ) {
1042
1058
Py_DECREF (new_parser );
1059
+ Py_DECREF (self );
1043
1060
return PyErr_NoMemory ();
1044
1061
}
1045
1062
@@ -1053,6 +1070,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1053
1070
new_parser -> handlers = PyMem_New (PyObject * , i );
1054
1071
if (!new_parser -> handlers ) {
1055
1072
Py_DECREF (new_parser );
1073
+ Py_DECREF (self );
1056
1074
return PyErr_NoMemory ();
1057
1075
}
1058
1076
clear_handlers (new_parser , 1 );
@@ -1242,6 +1260,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
1242
1260
/* namespace_separator is either NULL or contains one char + \0 */
1243
1261
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1244
1262
namespace_separator );
1263
+ self -> parent = NULL ;
1245
1264
if (self -> itself == NULL ) {
1246
1265
PyErr_SetString (PyExc_RuntimeError ,
1247
1266
"XML_ParserCreate failed" );
@@ -1278,6 +1297,7 @@ xmlparse_traverse(PyObject *op, visitproc visit, void *arg)
1278
1297
for (size_t i = 0 ; handler_info [i ].name != NULL ; i ++ ) {
1279
1298
Py_VISIT (self -> handlers [i ]);
1280
1299
}
1300
+ Py_VISIT (self -> parent );
1281
1301
Py_VISIT (Py_TYPE (op ));
1282
1302
return 0 ;
1283
1303
}
@@ -1288,6 +1308,10 @@ xmlparse_clear(PyObject *op)
1288
1308
xmlparseobject * self = xmlparseobject_CAST (op );
1289
1309
clear_handlers (self , 0 );
1290
1310
Py_CLEAR (self -> intern );
1311
+ // NOTE: We cannot call Py_CLEAR(self->parent) prior to calling
1312
+ // XML_ParserFree(self->itself), or a subparser could lose its parent
1313
+ // XML_Parser while still making use of it internally.
1314
+ // https://github.com/python/cpython/issues/139400
1291
1315
return 0 ;
1292
1316
}
1293
1317
@@ -1301,6 +1325,7 @@ xmlparse_dealloc(PyObject *op)
1301
1325
XML_ParserFree (self -> itself );
1302
1326
}
1303
1327
self -> itself = NULL ;
1328
+ Py_CLEAR (self -> parent );
1304
1329
1305
1330
if (self -> handlers != NULL ) {
1306
1331
PyMem_Free (self -> handlers );
0 commit comments