New submission from Sergei Lebedev <slebe...@google.com>:
tl;dr Passing a Python function as a freefunc to _PyEval_RequestCodeExtraIndex leads to double-free. In general, I think that freefunc should not be allowed to call other Python functions. --- test_code.CoExtra registers a new co_extra slot with a ctypes-wrapped freefunc # All defined in globals(). LAST_FREED = None def myfree(ptr): global LAST_FREED LAST_FREED = ptr FREE_FUNC = freefunc(myfree) FREE_INDEX = RequestCodeExtraIndex(FREE_FUNC) Imagine that we have registered another co_extra slot FOO_INDEX of type Foo and a freefunc FreeFoo. Furthermore, assume that * FOO_INDEX < FREE_INDEX * FOO_INDEX is set on any executed code object including myfree. Consider what happens when we collect the globals() of the test_code module. myfree is referenced by globals() and FREE_FUNC. If FREE_FUNC is DECREF'd first, then by the time we get to myfree it has a refcount of 1 and DECREF'ing it leads to a code_dealloc call. Recall that the code object corresponding to myfree has two co_extra slots: * FOO_INDEX pointing to some Foo*, and * FREE_INDEX with a value of NULL. So, code_dealloc will first call FreeFoo (because FOO_INDEX < FREE_INDEX) and then the ctypes wrapper of myfree. The following sequence of calls looks roughly like this _CallPythonObject ... PyEval_EvalCodeEx _PyEval_EvalCodeWithName frame_dealloc code_dealloc # ! The argument of the last code_dealloc call is *the same* myfree code object (!). This means that code_dealloc will attempt to call FreeFoo on an already free'd pointer leading to a crash. ---------- components: Tests messages: 360117 nosy: slebedev priority: normal severity: normal status: open title: test_code.CoExtra leads to double-free when ce_size >1 type: crash versions: Python 3.6, Python 3.7, Python 3.8, Python 3.9 _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue39358> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com