Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 33 additions & 6 deletions Include/pyexpat.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,29 @@

/* note: you must import expat.h before importing this module! */

#ifndef PyExpat_CAPI_H
#define PyExpat_CAPI_H
#ifdef __cplusplus
extern "C" {
#endif

/*
* Only bump the magic number when PyExpat_CAPI changes but not its size.
* If the structure changes because of an additional field, the magic number
* should not be bumped (see https://github.com/python/cpython/issues/115398).
*/
#define PyExpat_CAPI_MAGIC "pyexpat.expat_CAPI 1.1"
#define PyExpat_CAPSULE_NAME "pyexpat.expat_CAPI"

struct PyExpat_CAPI
{
char* magic; /* set to PyExpat_CAPI_MAGIC */
int size; /* set to sizeof(struct PyExpat_CAPI) */
typedef struct PyExpat_CAPI {
char *magic; /* set to PyExpat_CAPI_MAGIC */
int size; /* set to sizeof(PyExpat_CAPI) */
int MAJOR_VERSION;
int MINOR_VERSION;
int MICRO_VERSION;
/* pointers to selected expat functions. add new functions at
the end, if needed */
const XML_LChar * (*ErrorString)(enum XML_Error code);
const XML_LChar *(*ErrorString)(enum XML_Error code);
enum XML_Error (*GetErrorCode)(XML_Parser parser);
XML_Size (*GetErrorColumnNumber)(XML_Parser parser);
XML_Size (*GetErrorLineNumber)(XML_Parser parser);
Expand Down Expand Up @@ -63,5 +73,22 @@ struct PyExpat_CAPI
XML_Bool (*SetBillionLaughsAttackProtectionMaximumAmplification)(
XML_Parser parser, float maxAmplificationFactor);
/* always add new stuff to the end! */
};
} PyExpat_CAPI;

static inline int
PyExpat_CheckCompatibility(const PyExpat_CAPI *capi)
{
assert(capi != NULL);
return (
strcmp(capi->magic, PyExpat_CAPI_MAGIC) == 0
&& (size_t)capi->size >= sizeof(PyExpat_CAPI)
&& capi->MAJOR_VERSION == XML_MAJOR_VERSION
&& capi->MINOR_VERSION == XML_MINOR_VERSION
&& capi->MICRO_VERSION == XML_MICRO_VERSION
);
}

#ifdef __cplusplus
}
#endif
#endif /* !PyExpat_CAPI_H */
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Expose :c:func:`!PyExpat_CheckCompatibility` for checking Expat C API
compatibility. Patch by Bénédikt Tran.
30 changes: 9 additions & 21 deletions Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ typedef struct {
PyTypeObject *TreeBuilder_Type;
PyTypeObject *XMLParser_Type;

PyObject *expat_capsule;
struct PyExpat_CAPI *expat_capi;
} elementtreestate;

Expand Down Expand Up @@ -156,7 +155,6 @@ elementtree_clear(PyObject *m)
Py_CLEAR(st->ElementIter_Type);
Py_CLEAR(st->TreeBuilder_Type);
Py_CLEAR(st->XMLParser_Type);
Py_CLEAR(st->expat_capsule);

st->expat_capi = NULL;
return 0;
Expand All @@ -177,7 +175,7 @@ elementtree_traverse(PyObject *m, visitproc visit, void *arg)
Py_VISIT(st->ElementIter_Type);
Py_VISIT(st->TreeBuilder_Type);
Py_VISIT(st->XMLParser_Type);
Py_VISIT(st->expat_capsule);

return 0;
}

Expand Down Expand Up @@ -4430,28 +4428,18 @@ module_exec(PyObject *m)
if (st->deepcopy_obj == NULL) {
goto error;
}

assert(!PyErr_Occurred());
if (!(st->elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath")))
st->elementpath_obj = PyImport_ImportModule("xml.etree.ElementPath");
if (st->elementpath_obj == NULL) {
goto error;
}

/* link against pyexpat */
if (!(st->expat_capsule = PyImport_ImportModuleAttrString("pyexpat", "expat_CAPI")))
goto error;
if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME)))
st->expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
if (st->expat_capi == NULL) {
goto error;
if (st->expat_capi) {
/* check that it's usable */
if (strcmp(st->expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 ||
(size_t)st->expat_capi->size < sizeof(struct PyExpat_CAPI) ||
st->expat_capi->MAJOR_VERSION != XML_MAJOR_VERSION ||
st->expat_capi->MINOR_VERSION != XML_MINOR_VERSION ||
st->expat_capi->MICRO_VERSION != XML_MICRO_VERSION) {
PyErr_SetString(PyExc_ImportError,
"pyexpat version is incompatible");
goto error;
}
} else {
}
if (!PyExpat_CheckCompatibility(st->expat_capi)) {
PyErr_SetString(PyExc_ImportError, "pyexpat version is incompatible");
goto error;
}

Expand Down
Loading