Skip to content

Commit 894f0e5

Browse files
authored
gh-111784: Fix two segfaults in the elementtree module (GH-113405)
First fix resolve situation when pyexpat module (which contains expat_CAPI capsule) deallocates before _elementtree, so we need to hold a strong reference to pyexpat module to. Second fix resolve situation when module state is deallocated before deallocation of XMLParser instances, which uses module state to clear some stuff.
1 parent 050783c commit 894f0e5

File tree

2 files changed

+19
-2
lines changed

2 files changed

+19
-2
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix segfaults in the ``_elementtree`` module.
2+
Fix first segfault during deallocation of ``_elementtree.XMLParser`` instances by keeping strong reference
3+
to ``pyexpat`` module in module state for capsule lifetime.
4+
Fix second segfault which happens in the same deallocation process by keeping strong reference
5+
to ``_elementtree`` module in ``XMLParser`` structure for ``_elementtree`` module lifetime.

Modules/_elementtree.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ typedef struct {
9898
PyTypeObject *TreeBuilder_Type;
9999
PyTypeObject *XMLParser_Type;
100100

101+
PyObject *expat_capsule;
101102
struct PyExpat_CAPI *expat_capi;
102103
} elementtreestate;
103104

@@ -155,6 +156,7 @@ elementtree_clear(PyObject *m)
155156
Py_CLEAR(st->ElementIter_Type);
156157
Py_CLEAR(st->TreeBuilder_Type);
157158
Py_CLEAR(st->XMLParser_Type);
159+
Py_CLEAR(st->expat_capsule);
158160

159161
st->expat_capi = NULL;
160162
return 0;
@@ -175,6 +177,7 @@ elementtree_traverse(PyObject *m, visitproc visit, void *arg)
175177
Py_VISIT(st->ElementIter_Type);
176178
Py_VISIT(st->TreeBuilder_Type);
177179
Py_VISIT(st->XMLParser_Type);
180+
Py_VISIT(st->expat_capsule);
178181
return 0;
179182
}
180183

@@ -3066,6 +3069,7 @@ typedef struct {
30663069
PyObject *handle_close;
30673070

30683071
elementtreestate *state;
3072+
PyObject *elementtree_module;
30693073
} XMLParserObject;
30703074

30713075
/* helpers */
@@ -3607,7 +3611,11 @@ xmlparser_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
36073611
self->handle_start = self->handle_data = self->handle_end = NULL;
36083612
self->handle_comment = self->handle_pi = self->handle_close = NULL;
36093613
self->handle_doctype = NULL;
3610-
self->state = get_elementtree_state_by_type(type);
3614+
self->elementtree_module = PyType_GetModuleByDef(type, &elementtreemodule);
3615+
assert(self->elementtree_module != NULL);
3616+
Py_INCREF(self->elementtree_module);
3617+
// See gh-111784 for explanation why is reference to module needed here.
3618+
self->state = get_elementtree_state(self->elementtree_module);
36113619
}
36123620
return (PyObject *)self;
36133621
}
@@ -3784,6 +3792,7 @@ xmlparser_gc_clear(XMLParserObject *self)
37843792
EXPAT(st, ParserFree)(parser);
37853793
}
37863794

3795+
Py_CLEAR(self->elementtree_module);
37873796
Py_CLEAR(self->handle_close);
37883797
Py_CLEAR(self->handle_pi);
37893798
Py_CLEAR(self->handle_comment);
@@ -4343,7 +4352,10 @@ module_exec(PyObject *m)
43434352
goto error;
43444353

43454354
/* link against pyexpat */
4346-
st->expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
4355+
if (!(st->expat_capsule = _PyImport_GetModuleAttrString("pyexpat", "expat_CAPI")))
4356+
goto error;
4357+
if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME)))
4358+
goto error;
43474359
if (st->expat_capi) {
43484360
/* check that it's usable */
43494361
if (strcmp(st->expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 ||

0 commit comments

Comments
 (0)