Skip to content

Commit

Permalink
python: Handle os._exit() properly
Browse files Browse the repository at this point in the history
When os._exit() is invoked in the target python program, uftrace can't
write the symbol and dbginfo files because it doesn't invoke the
destructor.

This patch fixes the problem by hooking os._exit and invoke the
destructor manually then call _exit().

Fixed: namhyung#1685
Signed-off-by: Honggyu Kim <[email protected]>
  • Loading branch information
honggyukim committed Jun 6, 2023
1 parent 3f4a92b commit 953cef1
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 0 deletions.
18 changes: 18 additions & 0 deletions python/trace-python.c
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,14 @@ static void (*cygprof_exit)(unsigned long child, unsigned long parent);
/* main trace function to be called from python interpreter */
static PyObject *uftrace_trace_python(PyObject *self, PyObject *args);

/* hooking function of os._exit() for proper cleanup */
static PyObject *uftrace_trace_python_exit(PyObject *self, PyObject *obj);

static __attribute__((used)) PyMethodDef uftrace_py_methods[] = {
{ "trace", uftrace_trace_python, METH_VARARGS,
PyDoc_STR("trace python function with uftrace.") },
{ "exit", uftrace_trace_python_exit, METH_O,
PyDoc_STR("exit the target program with cleanup.") },
{ NULL, NULL, 0, NULL },
};

Expand Down Expand Up @@ -1017,6 +1022,14 @@ static void __attribute__((destructor)) uftrace_trace_python_finish(void)
free(main_dir);
}

static PyObject *uftrace_trace_python_exit(PyObject *self, PyObject *obj)
{
int n = PyLong_AsLong(obj);
uftrace_trace_python_finish();
_exit(n);
return NULL;
}

#else /* UNIT_TEST */

static PyObject *uftrace_trace_python(PyObject *self, PyObject *args)
Expand All @@ -1028,6 +1041,11 @@ static PyObject *uftrace_trace_python(PyObject *self, PyObject *args)
return NULL;
}

static PyObject *uftrace_trace_python_exit(PyObject *self, PyObject *obj)
{
return NULL;
}

TEST_CASE(python_symtab)
{
char buf[32];
Expand Down
8 changes: 8 additions & 0 deletions python/uftrace.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@
# UFTRACE_PYMAIN must be set before importing uftrace_python
import uftrace_python

# Symbol and debug files are finally written at uftrace_trace_python_finish()
# when program exits, but os._exit() terminates the program immediately so there
# is no chance to write symbol and debug files at the destructor.
# The os._exit() is hooked here to prevent this problem.
def os_exit(n):
uftrace_python.exit(n)
os._exit = os_exit

new_globals = globals()
new_globals["__file__"] = pathname
sys.path.insert(0, os.path.dirname(pathname))
Expand Down

0 comments on commit 953cef1

Please sign in to comment.