@@ -76,6 +76,15 @@ typedef struct {
76
76
PyObject_HEAD
77
77
78
78
XML_Parser itself ;
79
+ /*
80
+ * Strong reference to a parent `xmlparseobject` if this parser
81
+ * is a child parser. Set to NULL if this parser is a root parser.
82
+ * This is needed to keep the parent parser alive as long as it has
83
+ * at least one child parser.
84
+ *
85
+ * See https://github.com/python/cpython/issues/139400 for details.
86
+ */
87
+ PyObject * parent ;
79
88
int ordered_attributes ; /* Return attributes as a list. */
80
89
int specified_attributes ; /* Report only specified attributes. */
81
90
int in_callback ; /* Is a callback active? */
@@ -1067,6 +1076,11 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1067
1076
return NULL ;
1068
1077
}
1069
1078
1079
+ // The new subparser will make use of the parent XML_Parser inside of Expat.
1080
+ // So we need to take subparsers into account with the reference counting
1081
+ // of their parent parser.
1082
+ Py_INCREF (self );
1083
+
1070
1084
new_parser -> buffer_size = self -> buffer_size ;
1071
1085
new_parser -> buffer_used = 0 ;
1072
1086
new_parser -> buffer = NULL ;
@@ -1076,18 +1090,21 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1076
1090
new_parser -> ns_prefixes = self -> ns_prefixes ;
1077
1091
new_parser -> itself = XML_ExternalEntityParserCreate (self -> itself , context ,
1078
1092
encoding );
1093
+ new_parser -> parent = (PyObject * )self ;
1079
1094
new_parser -> handlers = 0 ;
1080
1095
new_parser -> intern = Py_XNewRef (self -> intern );
1081
1096
1082
1097
if (self -> buffer != NULL ) {
1083
1098
new_parser -> buffer = PyMem_Malloc (new_parser -> buffer_size );
1084
1099
if (new_parser -> buffer == NULL ) {
1085
1100
Py_DECREF (new_parser );
1101
+ Py_DECREF (self );
1086
1102
return PyErr_NoMemory ();
1087
1103
}
1088
1104
}
1089
1105
if (!new_parser -> itself ) {
1090
1106
Py_DECREF (new_parser );
1107
+ Py_DECREF (self );
1091
1108
return PyErr_NoMemory ();
1092
1109
}
1093
1110
@@ -1101,6 +1118,7 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
1101
1118
new_parser -> handlers = PyMem_New (PyObject * , i );
1102
1119
if (!new_parser -> handlers ) {
1103
1120
Py_DECREF (new_parser );
1121
+ Py_DECREF (self );
1104
1122
return PyErr_NoMemory ();
1105
1123
}
1106
1124
clear_handlers (new_parser , 1 );
@@ -1481,6 +1499,7 @@ newxmlparseobject(pyexpat_state *state, const char *encoding,
1481
1499
/* namespace_separator is either NULL or contains one char + \0 */
1482
1500
self -> itself = XML_ParserCreate_MM (encoding , & ExpatMemoryHandler ,
1483
1501
namespace_separator );
1502
+ self -> parent = NULL ;
1484
1503
if (self -> itself == NULL ) {
1485
1504
PyErr_SetString (PyExc_RuntimeError ,
1486
1505
"XML_ParserCreate failed" );
@@ -1517,6 +1536,7 @@ xmlparse_traverse(PyObject *op, visitproc visit, void *arg)
1517
1536
for (size_t i = 0 ; handler_info [i ].name != NULL ; i ++ ) {
1518
1537
Py_VISIT (self -> handlers [i ]);
1519
1538
}
1539
+ Py_VISIT (self -> parent );
1520
1540
Py_VISIT (Py_TYPE (op ));
1521
1541
return 0 ;
1522
1542
}
@@ -1527,6 +1547,10 @@ xmlparse_clear(PyObject *op)
1527
1547
xmlparseobject * self = xmlparseobject_CAST (op );
1528
1548
clear_handlers (self , 0 );
1529
1549
Py_CLEAR (self -> intern );
1550
+ // NOTE: We cannot call Py_CLEAR(self->parent) prior to calling
1551
+ // XML_ParserFree(self->itself), or a subparser could lose its parent
1552
+ // XML_Parser while still making use of it internally.
1553
+ // https://github.com/python/cpython/issues/139400
1530
1554
return 0 ;
1531
1555
}
1532
1556
@@ -1540,6 +1564,7 @@ xmlparse_dealloc(PyObject *op)
1540
1564
XML_ParserFree (self -> itself );
1541
1565
}
1542
1566
self -> itself = NULL ;
1567
+ Py_CLEAR (self -> parent );
1543
1568
1544
1569
if (self -> handlers != NULL ) {
1545
1570
PyMem_Free (self -> handlers );
0 commit comments