该程序(或至少是被询问部分)的目标是导入我的python模块/程序,以便可以从C中使用这些功能。这是通过首先调用import name
来完成的imp
和load_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
取消引用了,所以我不知道是什么引起了这个问题。