Python3 C++ 模块 - 异常 - 未保留 GIL
Python3 C++ Module - Exception - GIL not held
我创建了一个我遇到的问题的最小重现,试图创建一个基于 C++ 的 Python3 模块。构建环境为CMake,Visual Studio Pro 2019,WinSDK 10.0.18362,Python 3.9.4。执行时:
python3 -c "import pymod"
我将在具有 NULL 访问权限的发布模式下获得异常。在调试 Python 中,我获得了更多信息。
我的CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pymod_minimal_repo_example)
find_package(Python3 COMPONENTS Interpreter Development)
add_library(pymod SHARED)
target_sources(pymod PRIVATE pymodmodule.cpp)
set_target_properties(pymod PROPERTIES SUFFIX ".pyd")
target_compile_options(pymod PRIVATE /Zi)
target_link_options(pymod PRIVATE /DEBUG:FULL)
target_link_libraries(pymod PRIVATE ${Python3_LIBRARIES})
target_include_directories(pymod PRIVATE ${Python3_INCLUDE_DIRS})
根据此 python 参考:https://docs.python.org/3.9/extending/extending.html#a-simple-example 我创建了以下内容:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static struct PyModuleDef pymodmodule = {
PyModuleDef_HEAD_INIT, // m_base
"pymod", // m_name
NULL, // m_doc
-1, // m_size - submod not support must be static struct
NULL, // m_methods - no functions present
NULL, // m_slots - must be NULL
NULL, // m_traverse - not needed
NULL, // m_clear - not needed
NULL // m_free - not needed
};
PyMODINIT_FUNC PyInit_pymod(void) {
return PyModule_Create(&pymodmodule);
}
它是一个功能上无效的模块,什么都不做,但仍然 运行。请注意,定义 m_methods 会产生相同的失败。
发生故障时,控制台输出如下:
E:\projects\pymod\build\Debug>python -c "import pymod"
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
WinDbg jit 调试器随后发现了问题。部分调用堆栈显示我的 PyInit_pymod 被调用,并且在创建 python 模块时,它级联失败:
0:000> k
# Child-SP RetAddr Call Site
00 000000dc`abfed4a8 00007fff`71d51385 KERNELBASE!wil::details::DebugBreak+0x2
01 000000dc`abfed4b0 00007fff`71d511a8 python39_d!fatal_error_exit+0x15 [D:\a\s\Python\pylifecycle.c @ 2201]
02 000000dc`abfed4e0 00007fff`71d4ea98 python39_d!fatal_error+0x1b8 [D:\a\s\Python\pylifecycle.c @ 2286]
03 000000dc`abfed540 00007fff`71cbe730 python39_d!_Py_FatalErrorFunc+0x38 [D:\a\s\Python\pylifecycle.c @ 2302]
04 000000dc`abfed580 00007fff`71aa8044 python39_d!_Py_FatalError_TstateNULL+0x10 [D:\a\s\Python\ceval.c @ 251]
05 000000dc`abfed5b0 00007fff`71aa6cf2 python39_d!_PyInterpreterState_GET+0x34 [D:\a\s\Include\internal\pycore_pystate.h @ 105]
06 000000dc`abfed5f0 00007fff`d0be13e7 python39_d!PyModule_Create2+0x12 [D:\a\s\Objects\moduleobject.c @ 168]
>>>> 07 000000dc`abfed620 00007fff`751165dc pymod!PyInit_pymod+0x27 [E:\projects\pymod\pymodmodule.cpp @ 19]
08 000000dc`abfed660 00007fff`751167ee python39!_PyImport_LoadDynamicModuleWithSpec+0x104 [C:\A\s\Python\importdl.c @ 165]
09 000000dc`abfed6d0 00007fff`75116749 python39!_imp_create_dynamic_impl+0x86 [C:\A\s\Python\import.c @ 2299]
0a 000000dc`abfed700 00007fff`750cb94b python39!_imp_create_dynamic+0x39 [C:\A\s\Python\clinic\import.c.h @ 330]
0b 000000dc`abfed730 00007fff`750ad500 python39!cfunction_vectorcall_FASTCALL+0x9b [C:\A\s\Objects\methodobject.c @ 426]
0c 000000dc`abfed7a0 00007fff`750ad2ef python39!PyVectorcall_Call+0x5c [C:\A\s\Objects\call.c @ 248]
0d 000000dc`abfed800 00007fff`750ad418 python39!_PyObject_Call+0x4f [C:\A\s\Objects\call.c @ 287]
0e (Inline Function) --------`-------- python39!PyObject_Call+0xc [C:\A\s\Objects\call.c @ 293]
0f 000000dc`abfed830 00007fff`7508c65f python39!do_call_core+0xb8 [C:\A\s\Python\ceval.c @ 5092]
10 000000dc`abfed880 00007fff`75083963 python39!_PyEval_EvalFrameDefault+0x5d6f [C:\A\s\Python\ceval.c @ 3581]
11 (Inline Function) --------`-------- python39!_PyEval_EvalFrame+0x13 [C:\A\s\Include\internal\pycore_ceval.h @ 40]
12 000000dc`abfedbb0 00007fff`750855a7 python39!_PyEval_EvalCode+0x2b3 [C:\A\s\Python\ceval.c @ 4327]
13 000000dc`abfedc80 00007fff`7508823d python39!_PyFunction_Vectorcall+0x257 [C:\A\s\Objects\call.c @ 396]
14 000000dc`abfedd80 00007fff`7508812f python39!_PyEval_EvalFrameDefault+0x194d [C:\A\s\Python\ceval.c @ 3487]
15 000000dc`abfee0b0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x183f [C:\A\s\Python\ceval.c @ 3504]
16 000000dc`abfee3e0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
17 000000dc`abfee710 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
18 000000dc`abfeea40 00007fff`750854c4 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
我找不到关于控制台消息的任何信息,也找不到 int3.我已经尝试完全清除 reinstall/update of Python.
任何人都可以提供一些帮助或知道原因吗?
编辑:修改 PyModule_pymod 功能以显示 Pre 和 Post msg 到控制台。调试构建异常,发布似乎不是:
PyMODINIT_FUNC PyInit_pymod(void) {
printf("Pre-PyModule_Create\n");
PyObject *obj = PyModule_Create(&pymodmodule);
printf("Post-PyModule_Create\n");
return obj;
}
发布:
E:\projects\pymod\build\Release>python -c "import pymod"
Pre-PyModule_Create
Post-PyModule_Create
调试:
E:\projects\pymod\build\Debug>python -c "import pymod"
Pre-PyModule_Create
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
我 运行 遇到了和你一样的问题,在调试 TLS 结构时,我注意到 Visual Studio 加载了 python310.dll 而不是 python310_d.dll。
总而言之,当你定义_DEBUG宏时,Python.h会使用python310_d.lib,所以你需要运行 Python的调试版本:
python_d -c "import pymod"
我在使用 pybind11 时没有遇到这个问题,这让我更加困惑。事实证明,pybind11 在包含 Python.h 时取消定义 _DEBUG 宏,因此它始终使用 python310.lib 而不是 python310_d.lib,即使是调试构建也是如此。
因为我在 Visual Studio 中没有看到使用 python_d 解释器的选项,所以我最终使用发布库来使用以下代码调试构建:
#if defined(_MSC_VER) && defined(_DEBUG)
#undef _DEBUG
#include <Python.h>
#define _DEBUG 1
#else
#include <Python.h>
#endif
作为旁注,当您 link 反对 python310_d.dll 时,您必须将调试模块命名为 pymod_d.pyd 而不是 pymod.pyd.
我创建了一个我遇到的问题的最小重现,试图创建一个基于 C++ 的 Python3 模块。构建环境为CMake,Visual Studio Pro 2019,WinSDK 10.0.18362,Python 3.9.4。执行时:
python3 -c "import pymod"
我将在具有 NULL 访问权限的发布模式下获得异常。在调试 Python 中,我获得了更多信息。
我的CMakeLists.txt
cmake_minimum_required(VERSION 3.15)
project(pymod_minimal_repo_example)
find_package(Python3 COMPONENTS Interpreter Development)
add_library(pymod SHARED)
target_sources(pymod PRIVATE pymodmodule.cpp)
set_target_properties(pymod PROPERTIES SUFFIX ".pyd")
target_compile_options(pymod PRIVATE /Zi)
target_link_options(pymod PRIVATE /DEBUG:FULL)
target_link_libraries(pymod PRIVATE ${Python3_LIBRARIES})
target_include_directories(pymod PRIVATE ${Python3_INCLUDE_DIRS})
根据此 python 参考:https://docs.python.org/3.9/extending/extending.html#a-simple-example 我创建了以下内容:
#define PY_SSIZE_T_CLEAN
#include <Python.h>
static struct PyModuleDef pymodmodule = {
PyModuleDef_HEAD_INIT, // m_base
"pymod", // m_name
NULL, // m_doc
-1, // m_size - submod not support must be static struct
NULL, // m_methods - no functions present
NULL, // m_slots - must be NULL
NULL, // m_traverse - not needed
NULL, // m_clear - not needed
NULL // m_free - not needed
};
PyMODINIT_FUNC PyInit_pymod(void) {
return PyModule_Create(&pymodmodule);
}
它是一个功能上无效的模块,什么都不做,但仍然 运行。请注意,定义 m_methods 会产生相同的失败。
发生故障时,控制台输出如下:
E:\projects\pymod\build\Debug>python -c "import pymod"
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
WinDbg jit 调试器随后发现了问题。部分调用堆栈显示我的 PyInit_pymod 被调用,并且在创建 python 模块时,它级联失败:
0:000> k
# Child-SP RetAddr Call Site
00 000000dc`abfed4a8 00007fff`71d51385 KERNELBASE!wil::details::DebugBreak+0x2
01 000000dc`abfed4b0 00007fff`71d511a8 python39_d!fatal_error_exit+0x15 [D:\a\s\Python\pylifecycle.c @ 2201]
02 000000dc`abfed4e0 00007fff`71d4ea98 python39_d!fatal_error+0x1b8 [D:\a\s\Python\pylifecycle.c @ 2286]
03 000000dc`abfed540 00007fff`71cbe730 python39_d!_Py_FatalErrorFunc+0x38 [D:\a\s\Python\pylifecycle.c @ 2302]
04 000000dc`abfed580 00007fff`71aa8044 python39_d!_Py_FatalError_TstateNULL+0x10 [D:\a\s\Python\ceval.c @ 251]
05 000000dc`abfed5b0 00007fff`71aa6cf2 python39_d!_PyInterpreterState_GET+0x34 [D:\a\s\Include\internal\pycore_pystate.h @ 105]
06 000000dc`abfed5f0 00007fff`d0be13e7 python39_d!PyModule_Create2+0x12 [D:\a\s\Objects\moduleobject.c @ 168]
>>>> 07 000000dc`abfed620 00007fff`751165dc pymod!PyInit_pymod+0x27 [E:\projects\pymod\pymodmodule.cpp @ 19]
08 000000dc`abfed660 00007fff`751167ee python39!_PyImport_LoadDynamicModuleWithSpec+0x104 [C:\A\s\Python\importdl.c @ 165]
09 000000dc`abfed6d0 00007fff`75116749 python39!_imp_create_dynamic_impl+0x86 [C:\A\s\Python\import.c @ 2299]
0a 000000dc`abfed700 00007fff`750cb94b python39!_imp_create_dynamic+0x39 [C:\A\s\Python\clinic\import.c.h @ 330]
0b 000000dc`abfed730 00007fff`750ad500 python39!cfunction_vectorcall_FASTCALL+0x9b [C:\A\s\Objects\methodobject.c @ 426]
0c 000000dc`abfed7a0 00007fff`750ad2ef python39!PyVectorcall_Call+0x5c [C:\A\s\Objects\call.c @ 248]
0d 000000dc`abfed800 00007fff`750ad418 python39!_PyObject_Call+0x4f [C:\A\s\Objects\call.c @ 287]
0e (Inline Function) --------`-------- python39!PyObject_Call+0xc [C:\A\s\Objects\call.c @ 293]
0f 000000dc`abfed830 00007fff`7508c65f python39!do_call_core+0xb8 [C:\A\s\Python\ceval.c @ 5092]
10 000000dc`abfed880 00007fff`75083963 python39!_PyEval_EvalFrameDefault+0x5d6f [C:\A\s\Python\ceval.c @ 3581]
11 (Inline Function) --------`-------- python39!_PyEval_EvalFrame+0x13 [C:\A\s\Include\internal\pycore_ceval.h @ 40]
12 000000dc`abfedbb0 00007fff`750855a7 python39!_PyEval_EvalCode+0x2b3 [C:\A\s\Python\ceval.c @ 4327]
13 000000dc`abfedc80 00007fff`7508823d python39!_PyFunction_Vectorcall+0x257 [C:\A\s\Objects\call.c @ 396]
14 000000dc`abfedd80 00007fff`7508812f python39!_PyEval_EvalFrameDefault+0x194d [C:\A\s\Python\ceval.c @ 3487]
15 000000dc`abfee0b0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x183f [C:\A\s\Python\ceval.c @ 3504]
16 000000dc`abfee3e0 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
17 000000dc`abfee710 00007fff`750888e5 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
18 000000dc`abfeea40 00007fff`750854c4 python39!_PyEval_EvalFrameDefault+0x1ff5 [C:\A\s\Python\ceval.c @ 3518]
我找不到关于控制台消息的任何信息,也找不到 int3.我已经尝试完全清除 reinstall/update of Python.
任何人都可以提供一些帮助或知道原因吗?
编辑:修改 PyModule_pymod 功能以显示 Pre 和 Post msg 到控制台。调试构建异常,发布似乎不是:
PyMODINIT_FUNC PyInit_pymod(void) {
printf("Pre-PyModule_Create\n");
PyObject *obj = PyModule_Create(&pymodmodule);
printf("Post-PyModule_Create\n");
return obj;
}
发布:
E:\projects\pymod\build\Release>python -c "import pymod"
Pre-PyModule_Create
Post-PyModule_Create
调试:
E:\projects\pymod\build\Debug>python -c "import pymod"
Pre-PyModule_Create
Fatal Python error: _PyInterpreterState_GET: the function must be called with the GIL held, but the GIL is released (the current Python thread state is NULL)
Python runtime state: unknown
我 运行 遇到了和你一样的问题,在调试 TLS 结构时,我注意到 Visual Studio 加载了 python310.dll 而不是 python310_d.dll。
总而言之,当你定义_DEBUG宏时,Python.h会使用python310_d.lib,所以你需要运行 Python的调试版本:
python_d -c "import pymod"
我在使用 pybind11 时没有遇到这个问题,这让我更加困惑。事实证明,pybind11 在包含 Python.h 时取消定义 _DEBUG 宏,因此它始终使用 python310.lib 而不是 python310_d.lib,即使是调试构建也是如此。
因为我在 Visual Studio 中没有看到使用 python_d 解释器的选项,所以我最终使用发布库来使用以下代码调试构建:
#if defined(_MSC_VER) && defined(_DEBUG)
#undef _DEBUG
#include <Python.h>
#define _DEBUG 1
#else
#include <Python.h>
#endif
作为旁注,当您 link 反对 python310_d.dll 时,您必须将调试模块命名为 pymod_d.pyd 而不是 pymod.pyd.