从C导入python模块的多次调用会导致SEGFAULT

时间:2019-04-29 14:57:27

标签: python c cpython

该程序(或至少是被询问部分)的目标是导入我的python模块/程序,以便可以从C中使用这些功能。这是通过首先调用import name来完成的impload_source,然后使用返回的python对象调用要用import module加载的python模块。

多次调用call_symbolic_trace函数时,会出现问题。最初调用它时,该程序按预期运行,但是此后,它会导致段错误。

我已经确定了段故障发生在module = PyObject_CallObject(fcn, imp_args);函数的import_module行。

PyObject *import_name(const char *module_name, const char *fcn_name)
{
    PyObject *module = PyImport_Import(PyUnicode_FromString(module_name));
    return PyObject_GetAttrString(module, fcn_name);
}


PyObject *import_module(PyObject *fcn)
{
    int r;
    char *dir;
    PyObject *imp_args, *module;
    char exe_filename[BUFSIZ], path[BUFSIZ];

    r = readlink("/proc/self/exe", exe_filename, BUFSIZ);
    if (r < 0) {
        perror("readlink failed");
        exit(EXIT_FAILURE);
    } else if (r >= BUFSIZ) {
        fprintf(stderr, "Needed more bytes but buffer is %d bytes\n", BUFSIZ);
        exit(EXIT_FAILURE);
    }

    exe_filename[r] = '\0';
    dir = dirname(exe_filename);
    r = snprintf(path, BUFSIZ,
                 "%s/../src/symbolic_trace/symbolic_class_python3.py", dir);

    if (r < 0) {
        perror("snprintf failed");
        exit(EXIT_FAILURE);
    } else if (r >= BUFSIZ) {
        fprintf(stderr, "Needed %d bytes but buffer is %d bytes\n", r, BUFSIZ);
        exit(EXIT_FAILURE);
    }

    PyGILState_STATE module_state;
    module_state = PyGILState_Ensure();

    if (!PyCallable_Check(fcn)) {
        fprintf(stderr, "import_module: expected a callable\n");
        goto fail;
    }

    imp_args = Py_BuildValue("(ss)", "symbolic_class_python3", path);
    module = PyObject_CallObject(fcn, imp_args);
    Py_XDECREF(imp_args);

    if (PyErr_Occurred()) {
        printf("filepath: %s\n", path);
        printf("exe: %s\n", exe_filename);
        printf("dir: %s\n", dir);
        PyErr_Print();
        puts("import error occurred");
        goto fail;
    }

    PyGILState_Release(module_state);
    return module;

fail:
    Py_XDECREF(module);
    PyGILState_Release(module_state);
    abort();
}


void call_symbolic_trace(elf *e, graph *g)
{
    PyObject *imp_fcn = import_name("imp", "load_source");
    PyObject *tracer = import_module(imp_fcn);
    <mode code>
    Py_XDECREF(imp_fcn);
    Py_XDECREF(tracer);
}

使用GDB进行回溯会产生如下所示的内容,我无法以此为依据。

0x00007ffff712c710 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7153130 in _PyLong_New () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7155f5a in PyLong_FromLong () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7279774 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff727938f in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7279e02 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff727a6eb in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff713b029 in PyCFunction_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff72471c5 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff72d7cbc in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7245f49 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7247649 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7247649 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff7247649 in PyEval_EvalFrameEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff72d7cbc in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff72d7d93 in PyEval_EvalCodeEx () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff715fac8 in ?? () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff721455e in PyObject_Call () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00007ffff72d6947 in PyEval_CallObjectWithKeywords () from /usr/lib/x86_64-linux-gnu/libpython3.5m.so.1.0
0x00000000004040b1 in import_module (fcn=0x7ffff5bd9488) at src/symbolic_trace/symbolic_trace.c:62
0x0000000000405ea4 in call_symbolic_trace (e=0x66c250, g=0x6e7760, bbs=0x7fffffffdd10, root=0x13110f0, sl=0x7fffffffdd00, targets=0x7fffffffdbe0) at src/symbolic_trace/symbolic_trace.c:552

我无法理解为什么初始调用导入模块会成功进行,但是任何后续重复导入模块过程的调用将为SEGFAULT。通过我的C代码,我几乎肯定所有的python对象都被Py_XDECREF取消引用了,所以我不知道是什么引起了这个问题。

0 个答案:

没有答案