Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork33.7k
Description
Bug report
Bug description:
bug.cpp
#include<thread>#include<cstdio>#include<latch>#include<Python.h>PyObject*callInDestructor(PyObject *self, PyObject *args) {auto state =PyGILState_Ensure();printf("In destructor\n");PyGILState_Release(state); Py_RETURN_NONE;}PyObject *doStuff(PyObject *self, PyObject *cls) { PyObject *o; Py_BEGIN_ALLOW_THREADS// I'm not really sure why this is needed... { std::latchl1(1); std::latchl2(1); std::latchl3(1);auto thread1 =std::jthread([&](){ l1.wait();auto state =PyGILState_Ensure(); o =PyObject_CallNoArgs(cls); l2.count_down();// printf("0\n"); l3.wait();PyGILState_Release(state);printf("thread1 end\n"); });auto thread2 =std::jthread([&](){ l1.count_down();auto state =PyGILState_Ensure(); l2.wait();Py_XDECREF(o); l3.count_down();PyGILState_Release(state);printf("thread2 end\n"); }); } Py_END_ALLOW_THREADS Py_RETURN_NONE;}static PyMethodDef methods[] = { {"doStuff", doStuff, METH_O,"Demonstrate error."}, {"callInDestructor", callInDestructor, METH_NOARGS,"destruct"}, {NULL,NULL,0,NULL}/* Sentinel*/};staticstructPyModuleDef moduleDef = { PyModuleDef_HEAD_INIT,"bug",/* name of module*/NULL, -1,/* size of per-interpreter state of the module, or -1 if the module keeps state in global variables.*/ methods};PyMODINIT_FUNCPyInit_bug(void){ PyObject *m; m =PyModule_Create(&moduleDef);if (m ==NULL)returnNULL;return m;}
setupbug.py
fromsetuptoolsimportExtension,setupsetup(ext_modules=[Extension(name="bug",sources=["bug.cpp"],language="C++",extra_compile_args=['-std=c++20'],extra_link_args=['-lstdc++'], ), ])
testbug.py
importbugclassC:def__del__(self):bug.callInDestructor()bug.doStuff(C)
Build withpython setupbug.py build_ext --inplace
Run withpython -Xgil=0 testbug.py
I'm a little unclear on exactly what's going wrong here, but essentially it's destroying the C object from withinmerge_queued_objects(&brc->local_objects_to_merge);,callInDestruction() callsPyGILState_Ensure andPyGILState_Release (which is unnecessary because it already has the GIL, but should be fine anyway), and it's around here that it crashes with a segmentation fault.
If I remove the GIL handing fromcallInDestruction then it doesn't crash for me.
This is a cut-down version of something I've seen in Cythoncython/cython#6214 (comment) with a very similar crash but happening in a slightly different way.
CPython versions tested on:
3.13
Operating systems tested on:
Linux