Как избежать ошибки сегментации при вызове скриптов Python в проекте Qt - PullRequest
0 голосов
/ 28 марта 2019

Я пытаюсь вызвать функцию в Python под C ++.

Это моя попытка:

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();
}
}

Проблема в том, что моя программа на C ++ аварийно завершает работу, если в скрипте python есть ошибки import.В этом случае я подозреваю, что я пытаюсь использовать неверную версию PyQt4.

Это модуль: ( exportarXLS.py )

#!/usr/bin/python3

from PyQt4 import QtCore, QtGui, QtSql

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

Теперь мойвопрос:

Теперь я начинаю исследовать шаги по разработке функции для загрузки плагинов Python, и мне интересно, как бы избежать сбоя, если кто-то захочет добавить скрипт с неправильным import

Я пытаюсь заключить проблемную строку в блок try/catch, но она не работает.

РЕДАКТИРОВАТЬ:

Я забыл сказать, что это происходит только в моем QtПроект Если я попытаюсь запустить свою функцию из этого, я могу получить ошибки при загрузке модулей, но это не приводит к сбою.Я редактировал титул

Ответы [ 3 ]

1 голос
/ 28 марта 2019

Лучше всего решить проблему, выяснив причину SEGV, поскольку состояние вашего приложения может быть серьезно повреждено при его запуске.

Если вы хотите попытаться поймать SEGV в полуструктурированном виде, вы можете использовать что-то вроде примера кода, который использует sigsetjmp и siglongjmp:

#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();
}
1 голос
/ 28 марта 2019

Эта проблема звучит знакомо, и я даже могу воспроизвести ее с вашим кодом:

Если вы вызываете myFunction () более одного раза, происходит то, что вы импортируете свои модули более одного раза.Согласно Документам это может вызвать проблемы:

"Некоторые расширения могут работать некорректно, если их процедура инициализации вызывается более одного раза; это может произойти, если приложение вызывает Py_Initialize () и Py_Finalize () moreчем один раз. "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.

1 голос
/ 28 марта 2019

Решение для утиной ленты:

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

Я думаю, что этот вид решения следует использовать только в отладке

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...