"在 Qt 项目中调用Python脚本时如何避免出现分段错误"

2024-09-25 02:27:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图在C++环境下调用Python中的函数。你知道吗

这是我的尝试:

void myFuncion()
{
    PyObject* fExportar = nullptr;
    PyObject* modulo = nullptr;
    PyObject* pName = nullptr;
    const char *scriptDirectoryName = "path/of/my/pyfile";
    Py_Initialize();
    PyObject *sysPath = PySys_GetObject("path");
    PyObject *path = PyUnicode_FromString(scriptDirectoryName);
    int result = PyList_Insert(sysPath, 0, path);
    if (result == 0 )//0 if ok, -1 if error
    {
        pName = PyUnicode_FromString("exportarXLS");//exportarXLS.py
        modulo = PyImport_Import(pName);
        Py_DECREF(path);
        if (modulo)
        {           
                fExportar = PyObject_GetAttrString(modulo, "exportar");//it crahs here
                Py_DECREF(modulo);                
                if (fExportar)
                {
                     //call the function
                }
            }        
    }
    else
    {
        PyErr_Print();
    }
    Py_Finalize();
}
}
问题是,如果Python脚本有错误的^ {< CD1>},我的C++程序崩溃。在本例中,我怀疑我试图使用无效的PyQt4版本。你知道吗

这是模块:(导出xls.py

#!/usr/bin/python3

from PyQt4 import QtCore, QtGui, QtSql

def exportar():
    print ("hello, I am probing")

现在我的问题是:

现在我想探索一下为加载python插件开发函数的步骤,我想知道如果有人想用错误的import添加脚本,我该如何避免崩溃

我也尝试过将有问题的行括在try/catch块中,但它不起作用。你知道吗

编辑:

我忘了说这只发生在我的Qt项目中 如果我试图运行我的函数,我可以得到错误加载模块,但它不会崩溃。 我已经编辑了标题


Tags: path函数pyif错误resultpyobjectmodulo
3条回答

鸭胶带解决方案:

void signal_handler(int signal)
{
  std::cout << "Usefull information" std::endl; 
  exit(1);
}
...
std::signal(SIGSEGV, signal_handler);

文件:https://en.cppreference.com/w/cpp/utility/program/signal

我认为这种解决方案应该只在调试中使用

最好通过找出SEGV的根本原因来处理这个问题,因为您的应用程序的状态可能会被触发而严重损坏。你知道吗

如果您想尝试以半结构化的方式捕获SEGV,那么可以使用类似于示例代码的代码,它使用^{}^{}

#include <python3.7m/Python.h> // That's my python
#include <setjmp.h>
#include <signal.h>

static sigjmp_buf env;

static void
catch_segv(int func)
{
    siglongjmp(env, 1);
}

int myFunction()
{
    PyObject* fExportar = nullptr;
    PyObject* modulo = nullptr;
    PyObject* pName = nullptr;
    const char *scriptDirectoryName = "."; // NOTE: I changed the path for me
    Py_InitializeEx(1); // NOTE: skip signal handlers being registered - for embedding
    PyObject *sysPath = PySys_GetObject("path");
    PyObject *path = PyUnicode_FromString(scriptDirectoryName);
    int result = PyList_Insert(sysPath, 0, path);
    if (result == 0 )//0 if ok, -1 if error
    {
        pName = PyUnicode_FromString("beep");//exportarXLS.py
        modulo = PyImport_Import(pName);
        Py_DECREF(path);
        if (modulo)
        {
            // redirect segv handler here:
            sig_t old = signal(SIGSEGV, catch_segv);
            // record an environment to return to with siglongjmp
            if (sigsetjmp(env, 1)) { // returns 0 on setting up, 1 when called with siglongjmp(env, 1)
                // handler called
                Py_Finalize();
                signal(SIGSEGV, old); // restore old handler
                return 1; // return to caller
            } else {
                // this triggers a segv (for the test)
                (reinterpret_cast<sig_t>(0))(1);
                fExportar = PyObject_GetAttrString(modulo, "beep");//it crahs here
                Py_DECREF(modulo);
                if (fExportar)
                {
                     //call the function
                }
            }
            signal(SIGSEGV, old); // restore old handler
        }
    }
    else
    {
        PyErr_Print();
    }
    Py_Finalize();
    return 0; // return success.
}

int main(int argc, char **argv)
{
    return myFunction();
}

这个问题听起来很熟悉,我甚至可以用你的代码重现它:

如果多次调用myFunction(),则会发生多次导入模块的情况。根据文件,这可能会导致以下问题:

"Some extensions may not work properly if their initialization routine is called more than once; this can happen if an application calls Py_Initialize() and Py_Finalize() more than once." https://docs.python.org/2/c-api/init.html

因此,如果应用程序中存在这种情况,解决方法是只初始化Python解释器一次:

#include <iostream>
#include <Python/Python.h>

void myFuncion()
{
    PyObject* fExportar = nullptr;
    PyObject* modulo = nullptr;
    PyObject* pName = nullptr;
    const char *scriptDirectoryName = "path/of/my/pyfile";

    PyObject *sysPath = PySys_GetObject("path");
    PyObject *path = PyUnicode_FromString(scriptDirectoryName);
    int result = PyList_Insert(sysPath, 0, path);
    if (result == 0 )//0 if ok, -1 if error
    {
        pName = PyUnicode_FromString("exportarXLS");//exportarXLS.py
        modulo = PyImport_Import(pName);
        Py_DECREF(path);
        if (modulo)
        {           
                fExportar = PyObject_GetAttrString(modulo, "exportar");//it crahs here
                Py_DECREF(modulo);                
                if (fExportar)
                {
                     //call the function
                }
            }        
    }
    else
    {
        PyErr_Print();
    }

}

int main(int argc, const char * argv[]) {

    Py_Initialize();

    myFuncion();
    myFuncion();

    // what ever

    Py_Finalize();

    return 0;
}

编辑:“我甚至可以复制它”意味着我可以让它崩溃,在另一行,虽然,通过导入numpy。你知道吗

相关问题 更多 >