Цель этой программы (или, по крайней мере, той части, о которой идет речь), состоит в том, чтобы импортировать мой модуль / программу на python, чтобы можно было использовать функции из C. Это делается путем первого вызова import name
с помощью imp
и load_source
, затем с помощью возвращенного объекта python вызвать мой модуль python для загрузки с import module
.
Проблема возникает при многократном вызове функции call_symbolic_trace
.В первый раз, когда она была вызвана, программа работает, как и ожидалось, но после этого она приводит к segfault.
Я точно определил, что segfault происходит в строке 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
, поэтому я не знаю, что является причиной этой проблемы.