@@ -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? */
@@ -988,6 +997,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
988
997
return NULL ;
989
998
}
990
999
1000
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
1001
+ // So we need to take subparsers into account with the reference counting
1002
+ // of their parent parser.
1003
+ Py_INCREF (self );
1004
+
991
1005
new_parser -> buffer_size = self -> buffer_size ;
992
1006
new_parser -> buffer_used = 0 ;
993
1007
new_parser -> buffer = NULL ;
@@ -997,18 +1011,21 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
997
1011
new_parser -> ns_prefixes = self -> ns_prefixes ;
998
1012
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
999
1013
encoding );
1014
+ new_parser -> parent = (PyObject * )self ;
1000
1015
new_parser -> handlers = 0 ;
1001
1016
new_parser -> intern = Py_XNewRef (self -> intern );
1002
1017
1003
1018
if (self -> buffer != NULL ) {
1004
1019
new_parser -> buffer = PyMem_Malloc (new_parser -> buffer_size );
1005
1020
if (new_parser -> buffer == NULL ) {
1006
1021
Py_DECREF (new_parser );
1022
+ Py_DECREF (self );
1007
1023
return PyErr_NoMemory ();
1008
1024
}
1009
1025
}
1010
1026
if (!new_parser -> itself ) {
1011
1027
Py_DECREF (new_parser );
1028
+ Py_DECREF (self );
1012
1029
return PyErr_NoMemory ();
1013
1030
}
1014
1031
@@ -1021,6 +1038,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1021
1038
new_parser -> handlers = PyMem_New (PyObject * , i );
1022
1039
if (!new_parser -> handlers ) {
1023
1040
Py_DECREF (new_parser );
1041
+ Py_DECREF (self );
1024
1042
return PyErr_NoMemory ();
1025
1043
}
1026
1044
clear_handlers (new_parser , 1 );
@@ -1210,6 +1228,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
1210
1228
/* namespace_separator is either NULL or contains one char + \0 */
1211
1229
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1212
1230
namespace_separator );
1231
+ self -> parent = NULL ;
1213
1232
if (self -> itself == NULL ) {
1214
1233
PyErr_SetString (PyExc_RuntimeError ,
1215
1234
"XML_ParserCreate failed" );
@@ -1245,6 +1264,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
1245
1264
for (int i = 0 ; handler_info [i ].name != NULL ; i ++ ) {
1246
1265
Py_VISIT (op -> handlers [i ]);
1247
1266
}
1267
+ Py_VISIT (op -> parent );
1248
1268
Py_VISIT (Py_TYPE (op ));
1249
1269
return 0 ;
1250
1270
}
@@ -1254,6 +1274,10 @@ xmlparse_clear(xmlparseobject *op)
1254
1274
{
1255
1275
clear_handlers (op , 0 );
1256
1276
Py_CLEAR (op -> intern );
1277
+ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling
1278
+ // XML_ParserFree(op->itself), or a subparser could lose its parent
1279
+ // XML_Parser while still making use of it internally.
1280
+ // https://github.com/python/cpython/issues/139400
1257
1281
return 0 ;
1258
1282
}
1259
1283
@@ -1265,6 +1289,7 @@ xmlparse_dealloc(xmlparseobject *self)
1265
1289
if (self -> itself != NULL )
1266
1290
XML_ParserFree (self -> itself );
1267
1291
self -> itself = NULL ;
1292
+ Py_CLEAR (self -> parent );
1268
1293
1269
1294
if (self -> handlers != NULL ) {
1270
1295
PyMem_Free (self -> handlers );
0 commit comments