@@ -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? */
@@ -989,6 +998,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
989
998
return NULL ;
990
999
}
991
1000
1001
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
1002
+ // So we need to take subparsers into account with the reference counting
1003
+ // of their parent parser.
1004
+ Py_INCREF (self );
1005
+
992
1006
new_parser -> buffer_size = self -> buffer_size ;
993
1007
new_parser -> buffer_used = 0 ;
994
1008
new_parser -> buffer = NULL ;
@@ -998,6 +1012,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
998
1012
new_parser -> ns_prefixes = self -> ns_prefixes ;
999
1013
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
1000
1014
encoding );
1015
+ new_parser -> parent = (PyObject * )self ;
1001
1016
new_parser -> handlers = 0 ;
1002
1017
new_parser -> intern = self -> intern ;
1003
1018
Py_XINCREF (new_parser -> intern );
@@ -1006,11 +1021,13 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
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 );
@@ -1201,6 +1219,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
1201
1219
/* namespace_separator is either NULL or contains one char + \0 */
1202
1220
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1203
1221
namespace_separator );
1222
+ self -> parent = NULL ;
1204
1223
if (self -> itself == NULL ) {
1205
1224
PyErr_SetString (PyExc_RuntimeError ,
1206
1225
"XML_ParserCreate failed" );
@@ -1236,6 +1255,7 @@ xmlparse_traverse(xmlparseobject *op, visitproc visit, void *arg)
1236
1255
for (int i = 0 ; handler_info [i ].name != NULL ; i ++ ) {
1237
1256
Py_VISIT (op -> handlers [i ]);
1238
1257
}
1258
+ Py_VISIT (op -> parent );
1239
1259
Py_VISIT (Py_TYPE (op ));
1240
1260
return 0 ;
1241
1261
}
@@ -1245,6 +1265,10 @@ xmlparse_clear(xmlparseobject *op)
1245
1265
{
1246
1266
clear_handlers (op , 0 );
1247
1267
Py_CLEAR (op -> intern );
1268
+ // NOTE: We cannot call Py_CLEAR(op->parent) prior to calling
1269
+ // XML_ParserFree(op->itself), or a subparser could lose its parent
1270
+ // XML_Parser while still making use of it internally.
1271
+ // https://github.com/python/cpython/issues/139400
1248
1272
return 0 ;
1249
1273
}
1250
1274
@@ -1256,6 +1280,7 @@ xmlparse_dealloc(xmlparseobject *self)
1256
1280
if (self -> itself != NULL )
1257
1281
XML_ParserFree (self -> itself );
1258
1282
self -> itself = NULL ;
1283
+ Py_CLEAR (self -> parent );
1259
1284
1260
1285
if (self -> handlers != NULL ) {
1261
1286
PyMem_Free (self -> handlers );
0 commit comments