Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-111784: Add PyCapsule_ImportCapsule and fix segfault in _elementtree.c #112053

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
5 changes: 5 additions & 0 deletions Include/pycapsule.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ PyAPI_FUNC(void *) PyCapsule_Import(
const char *name, /* UTF-8 encoded string */
int no_block);

PyAPI_FUNC(PyObject *) PyCapsule_ImportCapsule(
const char *name,
int no_block
);

#ifdef __cplusplus
}
#endif
Expand Down
8 changes: 7 additions & 1 deletion Modules/_elementtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ typedef struct {
PyTypeObject *TreeBuilder_Type;
PyTypeObject *XMLParser_Type;

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

Expand Down Expand Up @@ -137,6 +138,7 @@ elementtree_clear(PyObject *m)
Py_CLEAR(st->parseerror_obj);
Py_CLEAR(st->deepcopy_obj);
Py_CLEAR(st->elementpath_obj);
Py_CLEAR(st->expat_capsule);
Py_CLEAR(st->comment_factory);
Py_CLEAR(st->pi_factory);

Expand Down Expand Up @@ -167,6 +169,7 @@ elementtree_traverse(PyObject *m, visitproc visit, void *arg)
Py_VISIT(st->parseerror_obj);
Py_VISIT(st->deepcopy_obj);
Py_VISIT(st->elementpath_obj);
Py_VISIT(st->expat_capsule);
Py_VISIT(st->comment_factory);
Py_VISIT(st->pi_factory);

Expand Down Expand Up @@ -4343,7 +4346,10 @@ module_exec(PyObject *m)
goto error;

/* link against pyexpat */
st->expat_capi = PyCapsule_Import(PyExpat_CAPSULE_NAME, 0);
if (!(st->expat_capsule = PyCapsule_ImportCapsule(PyExpat_CAPSULE_NAME, 0)))
goto error;
if (!(st->expat_capi = PyCapsule_GetPointer(st->expat_capsule, PyExpat_CAPSULE_NAME)))
goto error;
if (st->expat_capi) {
/* check that it's usable */
if (strcmp(st->expat_capi->magic, PyExpat_CAPI_MAGIC) != 0 ||
Expand Down
51 changes: 51 additions & 0 deletions Objects/capsule.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,57 @@ _PyCapsule_SetTraverse(PyObject *op, traverseproc traverse_func, inquiry clear_f
}


PyObject *
PyCapsule_ImportCapsule(const char *name, int no_block)
{
PyObject *object = NULL;
char *trace;
size_t name_length = (strlen(name) + 1) * sizeof(char);
char *name_dup = (char *)PyMem_Malloc(name_length);

if (!name_dup) {
return PyErr_NoMemory();
}

memcpy(name_dup, name, name_length);

trace = name_dup;
while (trace) {
char *dot = strchr(trace, '.');
if (dot) {
*dot++ = '\0';
}

if (object == NULL) {
object = PyImport_ImportModule(trace);
if (!object) {
PyErr_Format(PyExc_ImportError, "PyCapsule_Import could not import module \"%s\"", trace);
}
} else {
PyObject *object2 = PyObject_GetAttrString(object, trace);
Py_SETREF(object, object2);
}
if (!object) {
goto EXIT;
}

trace = dot;
}

/* compare attribute name to module.name by hand */
if (!PyCapsule_IsValid(object, name)) {
PyErr_Format(PyExc_AttributeError,
"PyCapsule_Import \"%s\" is not valid",
name);
}
EXIT:
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need here Py_XDECREF(object) as in the PyCapsule_Import, because we do it later manually. So, we can control a process of capsule's deallocation

if (name_dup) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

name_dup is always non-NULL here, as we return MemoryError at line 236 if PyMem_Malloc fails.

Copy link
Member Author

@Eclips4 Eclips4 Nov 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a final version 😅
Currently we just talking about idea, sadly, but this solution is incorrect :(
FYI, it's just copied from PyCapsule_Import

PyMem_Free(name_dup);
}
return object;
}


void *
PyCapsule_Import(const char *name, int no_block)
{
Expand Down