@@ -69,6 +69,15 @@ typedef struct {
69
69
PyObject_HEAD
70
70
71
71
XML_Parser itself ;
72
+ /*
73
+ * Strong reference to a parent `xmlparseobject` if this parser
74
+ * is a child parser. Set to NULL if this parser is a root parser.
75
+ * This is needed to keep the parent parser alive as long as it has
76
+ * at least one child parser.
77
+ *
78
+ * See https://github.com/python/cpython/issues/139400 for details.
79
+ */
80
+ PyObject * parent ;
72
81
int ordered_attributes ; /* Return attributes as a list. */
73
82
int specified_attributes ; /* Report only specified attributes. */
74
83
int in_callback ; /* Is a callback active? */
@@ -990,6 +999,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
990
999
return NULL ;
991
1000
}
992
1001
1002
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
1003
+ // So we need to take subparsers into account with the reference counting
1004
+ // of their parent parser.
1005
+ Py_INCREF (self );
1006
+
993
1007
new_parser -> buffer_size = self -> buffer_size ;
994
1008
new_parser -> buffer_used = 0 ;
995
1009
new_parser -> buffer = NULL ;
@@ -999,18 +1013,21 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
999
1013
new_parser -> ns_prefixes = self -> ns_prefixes ;
1000
1014
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
1001
1015
encoding );
1016
+ new_parser -> parent = (PyObject * )self ;
1002
1017
new_parser -> handlers = 0 ;
1003
1018
new_parser -> intern = Py_XNewRef (self -> intern );
1004
1019
1005
1020
if (self -> buffer != NULL ) {
1006
1021
new_parser -> buffer = PyMem_Malloc (new_parser -> buffer_size );
1007
1022
if (new_parser -> buffer == NULL ) {
1008
1023
Py_DECREF (new_parser );
1024
+ Py_DECREF (self );
1009
1025
return PyErr_NoMemory ();
1010
1026
}
1011
1027
}
1012
1028
if (!new_parser -> itself ) {
1013
1029
Py_DECREF (new_parser );
1030
+ Py_DECREF (self );
1014
1031
return PyErr_NoMemory ();
1015
1032
}
1016
1033
@@ -1023,6 +1040,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1023
1040
new_parser -> handlers = PyMem_New (PyObject * , i );
1024
1041
if (!new_parser -> handlers ) {
1025
1042
Py_DECREF (new_parser );
1043
+ Py_DECREF (self );
1026
1044
return PyErr_NoMemory ();
1027
1045
}
1028
1046
clear_handlers (new_parser , 1 );
@@ -1212,6 +1230,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
1212
1230
/* namespace_separator is either NULL or contains one char + \0 */
1213
1231
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1214
1232
namespace_separator );
1233
+ self -> parent = NULL ;
1215
1234
if (self -> itself == NULL ) {
1216
1235
PyErr_SetString (PyExc_RuntimeError ,
1217
1236
"XML_ParserCreate failed" );
@@ -1247,6 +1266,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
1247
1266
for (int i = 0 ; handler_info [i ].name != NULL ; i ++ ) {
1248
1267
Py_VISIT (op -> handlers [i ]);
1249
1268
}
1269
+ Py_VISIT (op -> parent );
1250
1270
Py_VISIT (Py_TYPE (op ));
1251
1271
return 0 ;
1252
1272
}
@@ -1256,6 +1276,10 @@ xmlparse_clear(xmlparseobject *op)
1256
1276
{
1257
1277
clear_handlers (op , 0 );
1258
1278
Py_CLEAR (op -> intern );
1279
+ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling
1280
+ // XML_ParserFree(op->itself), or a subparser could lose its parent
1281
+ // XML_Parser while still making use of it internally.
1282
+ // https://github.com/python/cpython/issues/139400
1259
1283
return 0 ;
1260
1284
}
1261
1285
@@ -1267,6 +1291,7 @@ xmlparse_dealloc(xmlparseobject *self)
1267
1291
if (self -> itself != NULL )
1268
1292
XML_ParserFree (self -> itself );
1269
1293
self -> itself = NULL ;
1294
+ Py_CLEAR (self -> parent );
1270
1295
1271
1296
if (self -> handlers != NULL ) {
1272
1297
PyMem_Free (self -> handlers );
0 commit comments