obs-scripting: Fix issues between runtime and compile-time versions
Calling `PyEval_InitThreads` has been deprecated in Python 3.7 and the function itself will be removed in Python 3.11. The current check guards this function behind a version check that only happens at compile time. This in turn leads to crashes when run on Python 3.6, as the necessary initialization for `PyEval_ReleaseThread` did not take place. This commit ensures the manual initialization takes place based on the runtime version of Python and avoids loading the associated symbols on Python 3.9 or later.master
parent
be68403fa4
commit
24a123119a
|
@ -42,7 +42,7 @@
|
|||
#define PY_MAJOR_VERSION_MAX 3
|
||||
#define PY_MINOR_VERSION_MAX 10
|
||||
|
||||
bool import_python(const char *python_path)
|
||||
bool import_python(const char *python_path, python_version_t *python_version)
|
||||
{
|
||||
struct dstr lib_path;
|
||||
bool success = false;
|
||||
|
@ -51,6 +51,12 @@ bool import_python(const char *python_path)
|
|||
if (!python_path)
|
||||
python_path = "";
|
||||
|
||||
if (!python_version) {
|
||||
blog(LOG_DEBUG,
|
||||
"[Python] Invalid python_version pointer provided.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dstr_init_copy(&lib_path, python_path);
|
||||
dstr_replace(&lib_path, "\\", "/");
|
||||
if (!dstr_is_empty(&lib_path)) {
|
||||
|
@ -96,6 +102,9 @@ bool import_python(const char *python_path)
|
|||
goto fail;
|
||||
}
|
||||
|
||||
python_version->major = PY_MAJOR_VERSION_MAX;
|
||||
python_version->minor = minor_version;
|
||||
|
||||
#define IMPORT_FUNC(x) \
|
||||
do { \
|
||||
Import_##x = os_dlsym(lib, #x); \
|
||||
|
@ -133,8 +142,12 @@ bool import_python(const char *python_path)
|
|||
IMPORT_FUNC(Py_Initialize);
|
||||
IMPORT_FUNC(Py_Finalize);
|
||||
IMPORT_FUNC(Py_IsInitialized);
|
||||
IMPORT_FUNC(PyEval_InitThreads);
|
||||
IMPORT_FUNC(PyEval_ThreadsInitialized);
|
||||
|
||||
if (python_version->major == 3 && python_version->minor < 7) {
|
||||
IMPORT_FUNC(PyEval_InitThreads);
|
||||
IMPORT_FUNC(PyEval_ThreadsInitialized);
|
||||
}
|
||||
|
||||
IMPORT_FUNC(PyEval_ReleaseThread);
|
||||
IMPORT_FUNC(PySys_SetArgv);
|
||||
IMPORT_FUNC(PyImport_ImportModule);
|
||||
|
@ -148,9 +161,10 @@ bool import_python(const char *python_path)
|
|||
IMPORT_FUNC(PyDict_GetItemString);
|
||||
IMPORT_FUNC(PyDict_SetItemString);
|
||||
IMPORT_FUNC(PyCFunction_NewEx);
|
||||
#if PY_VERSION_HEX > 0x030900b0
|
||||
IMPORT_FUNC(PyCMethod_New);
|
||||
#endif
|
||||
|
||||
if (python_version->major == 3 && python_version->minor >= 9)
|
||||
IMPORT_FUNC(PyCMethod_New);
|
||||
|
||||
IMPORT_FUNC(PyModule_GetDict);
|
||||
IMPORT_FUNC(PyModule_GetNameObject);
|
||||
IMPORT_FUNC(PyModule_AddObject);
|
||||
|
@ -181,14 +195,12 @@ bool import_python(const char *python_path)
|
|||
IMPORT_FUNC(PyArg_VaParse);
|
||||
IMPORT_FUNC(_Py_NoneStruct);
|
||||
IMPORT_FUNC(PyTuple_New);
|
||||
|
||||
if (python_version->major == 3 && python_version->minor >= 9) {
|
||||
IMPORT_FUNC(PyType_GetFlags);
|
||||
}
|
||||
#if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
|
||||
IMPORT_FUNC(_Py_Dealloc);
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030900b0
|
||||
IMPORT_FUNC(PyType_GetFlags);
|
||||
#endif
|
||||
|
||||
#undef IMPORT_FUNC
|
||||
success = true;
|
||||
|
||||
|
|
|
@ -50,6 +50,11 @@
|
|||
#define PY_EXTERN extern
|
||||
#endif
|
||||
|
||||
typedef struct python_version {
|
||||
int major;
|
||||
int minor;
|
||||
} python_version_t;
|
||||
|
||||
PY_EXTERN int (*Import_PyType_Ready)(PyTypeObject *);
|
||||
PY_EXTERN PyObject *(*Import_PyObject_GenericGetAttr)(PyObject *, PyObject *);
|
||||
PY_EXTERN int (*Import_PyObject_IsTrue)(PyObject *);
|
||||
|
@ -99,10 +104,8 @@ PY_EXTERN int (*Import_PyDict_SetItemString)(PyObject *dp, const char *key,
|
|||
PyObject *item);
|
||||
PY_EXTERN PyObject *(*Import_PyCFunction_NewEx)(PyMethodDef *, PyObject *,
|
||||
PyObject *);
|
||||
#if PY_VERSION_HEX > 0x030900b0
|
||||
PY_EXTERN PyObject *(*Import_PyCMethod_New)(PyMethodDef *, PyObject *,
|
||||
PyObject *, PyTypeObject *);
|
||||
#endif
|
||||
PY_EXTERN PyObject *(*Import_PyModule_GetDict)(PyObject *);
|
||||
PY_EXTERN PyObject *(*Import_PyModule_GetNameObject)(PyObject *);
|
||||
PY_EXTERN int (*Import_PyModule_AddObject)(PyObject *, const char *,
|
||||
|
@ -139,23 +142,17 @@ PY_EXTERN PyObject *(*Import_PyLong_FromUnsignedLongLong)(unsigned long long);
|
|||
PY_EXTERN int (*Import_PyArg_VaParse)(PyObject *, const char *, va_list);
|
||||
PY_EXTERN PyObject(*Import__Py_NoneStruct);
|
||||
PY_EXTERN PyObject *(*Import_PyTuple_New)(Py_ssize_t size);
|
||||
#if PY_VERSION_HEX >= 0x030900b0
|
||||
PY_EXTERN int (*Import_PyType_GetFlags)(PyTypeObject *o);
|
||||
#endif
|
||||
#if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
|
||||
PY_EXTERN void (*Import__Py_Dealloc)(PyObject *obj);
|
||||
#endif
|
||||
|
||||
extern bool import_python(const char *python_path);
|
||||
extern bool import_python(const char *python_path,
|
||||
python_version_t *python_version);
|
||||
|
||||
#ifndef NO_REDEFS
|
||||
#define PyType_Ready Import_PyType_Ready
|
||||
#if PY_VERSION_HEX >= 0x030900b0
|
||||
#define PyType_GetFlags Import_PyType_GetFlags
|
||||
#endif
|
||||
#if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
|
||||
#define _Py_Dealloc Import__Py_Dealloc
|
||||
#endif
|
||||
#define PyObject_GenericGetAttr Import_PyObject_GenericGetAttr
|
||||
#define PyObject_IsTrue Import_PyObject_IsTrue
|
||||
#define Py_DecRef Import_Py_DecRef
|
||||
|
@ -231,6 +228,9 @@ extern bool import_python(const char *python_path);
|
|||
#define PyArg_VaParse Import_PyArg_VaParse
|
||||
#define _Py_NoneStruct (*Import__Py_NoneStruct)
|
||||
#define PyTuple_New Import_PyTuple_New
|
||||
#if defined(Py_DEBUG) || PY_VERSION_HEX >= 0x030900b0
|
||||
#define _Py_Dealloc Import__Py_Dealloc
|
||||
#endif
|
||||
#if PY_VERSION_HEX >= 0x030800f0
|
||||
static inline void Import__Py_DECREF(const char *filename, int lineno,
|
||||
PyObject *op)
|
||||
|
@ -262,7 +262,6 @@ static inline void Import__Py_XDECREF(PyObject *op)
|
|||
#undef Py_XDECREF
|
||||
#define Py_XDECREF(op) Import__Py_XDECREF(_PyObject_CAST(op))
|
||||
#endif // PY_VERSION_HEX >= 0x030800f0
|
||||
|
||||
#if PY_VERSION_HEX >= 0x030900b0
|
||||
static inline int Import_PyType_HasFeature(PyTypeObject *type,
|
||||
unsigned long feature)
|
||||
|
|
|
@ -49,6 +49,7 @@ sys.stderr = stderr_logger()\n";
|
|||
|
||||
#if RUNTIME_LINK
|
||||
static wchar_t home_path[1024] = {0};
|
||||
static python_version_t python_version = {0};
|
||||
#endif
|
||||
|
||||
DARRAY(char *) python_paths;
|
||||
|
@ -1615,12 +1616,7 @@ bool obs_scripting_load_python(const char *python_path)
|
|||
|
||||
/* Use external python on windows and mac */
|
||||
#if RUNTIME_LINK
|
||||
#if 0
|
||||
struct dstr old_path = {0};
|
||||
struct dstr new_path = {0};
|
||||
#endif
|
||||
|
||||
if (!import_python(python_path))
|
||||
if (!import_python(python_path, &python_version))
|
||||
return false;
|
||||
|
||||
if (python_path && *python_path) {
|
||||
|
@ -1634,11 +1630,6 @@ bool obs_scripting_load_python(const char *python_path)
|
|||
|
||||
os_utf8_to_wcs(python_path, 0, home_path, 1024);
|
||||
Py_SetPythonHome(home_path);
|
||||
#endif
|
||||
#if 0
|
||||
dstr_copy(&old_path, getenv("PATH"));
|
||||
_putenv("PYTHONPATH=");
|
||||
_putenv("PATH=");
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
|
@ -1649,24 +1640,17 @@ bool obs_scripting_load_python(const char *python_path)
|
|||
if (!Py_IsInitialized())
|
||||
return false;
|
||||
|
||||
#if 0
|
||||
#ifdef _DEBUG
|
||||
if (pythondir && *pythondir) {
|
||||
dstr_printf(&new_path, "PATH=%s", old_path.array);
|
||||
_putenv(new_path.array);
|
||||
#if RUNTIME_LINK
|
||||
if (python_version.major == 3 && python_version.minor < 7) {
|
||||
#elif PY_VERSION_HEX < 0x030700b0
|
||||
if (true) {
|
||||
#else
|
||||
if (false) {
|
||||
#endif
|
||||
PyEval_InitThreads();
|
||||
if (!PyEval_ThreadsInitialized())
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
bfree(pythondir);
|
||||
dstr_free(&new_path);
|
||||
dstr_free(&old_path);
|
||||
#endif
|
||||
|
||||
#if PY_VERSION_HEX < 0x03070000
|
||||
PyEval_InitThreads();
|
||||
if (!PyEval_ThreadsInitialized())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
/* ---------------------------------------------- */
|
||||
/* Must set arguments for guis to work */
|
||||
|
|
Loading…
Reference in New Issue