From 8852ad4208e34825f74e24945edb5bcf055d94fe Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 29 Apr 2020 01:28:13 +0200 Subject: [PATCH] bpo-40429: PyFrame_GetCode() now returns a strong reference (GH-19773) --- Doc/c-api/reflection.rst | 7 ++++--- Doc/whatsnew/3.9.rst | 3 +-- Modules/_lsprof.c | 7 ++++++- Modules/_tracemalloc.c | 19 +++++++++---------- Objects/frameobject.c | 1 + Objects/typeobject.c | 4 ++-- Python/_warnings.c | 6 +++++- Python/import.c | 1 + Python/traceback.c | 13 ++++++------- 9 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Doc/c-api/reflection.rst b/Doc/c-api/reflection.rst index 594c1ec7943..21d98786091 100644 --- a/Doc/c-api/reflection.rst +++ b/Doc/c-api/reflection.rst @@ -33,10 +33,11 @@ Reflection .. c:function:: int PyFrame_GetCode(PyFrameObject *frame) - Return a borrowed reference to the *frame* code. - The frame code cannot be ``NULL``. + Get the *frame* code. - *frame* must not be ``NULL``. + Return a strong reference. + + *frame* must not be ``NULL``. The result (frame code) cannot be ``NULL``. .. versionadded:: 3.9 diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index e3751fa1680..cb3afd59357 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -537,8 +537,7 @@ Optimizations Build and C API Changes ======================= -* New :c:func:`PyFrame_GetCode` function: return a borrowed reference to the - frame code. +* New :c:func:`PyFrame_GetCode` function: get a frame code. (Contributed by Victor Stinner in :issue:`40421`.) * Add :c:func:`PyFrame_GetLineNumber` to the limited C API. diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c index 39cf6e126d6..5e53d839640 100644 --- a/Modules/_lsprof.c +++ b/Modules/_lsprof.c @@ -390,14 +390,19 @@ profiler_callback(PyObject *self, PyFrameObject *frame, int what, { PyCodeObject *code = PyFrame_GetCode(frame); ptrace_enter_call(self, (void *)code, (PyObject *)code); + Py_DECREF(code); break; } /* the 'frame' of a called function is about to finish (either normally or with an exception) */ case PyTrace_RETURN: - ptrace_leave_call(self, (void *)PyFrame_GetCode(frame)); + { + PyCodeObject *code = PyFrame_GetCode(frame); + ptrace_leave_call(self, (void *)code); + Py_DECREF(code); break; + } /* case PyTrace_EXCEPTION: If the exception results in the function exiting, a diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index b2a00030216..24628a907f2 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -335,26 +335,24 @@ hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey, static void tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame) { - PyCodeObject *code; - PyObject *filename; - _Py_hashtable_entry_t *entry; - int lineno; - frame->filename = unknown_filename; - lineno = PyFrame_GetLineNumber(pyframe); - if (lineno < 0) + int lineno = PyFrame_GetLineNumber(pyframe); + if (lineno < 0) { lineno = 0; + } frame->lineno = (unsigned int)lineno; - code = PyFrame_GetCode(pyframe); - if (code->co_filename == NULL) { + PyCodeObject *code = PyFrame_GetCode(pyframe); + PyObject *filename = code->co_filename; + Py_DECREF(code); + + if (filename == NULL) { #ifdef TRACE_DEBUG tracemalloc_error("failed to get the filename of the code object"); #endif return; } - filename = code->co_filename; assert(filename != NULL); if (filename == NULL) return; @@ -375,6 +373,7 @@ tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame) } /* intern the filename */ + _Py_hashtable_entry_t *entry; entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename); if (entry != NULL) { _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index 6b3559ee962..533186bc046 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -1237,5 +1237,6 @@ PyFrame_GetCode(PyFrameObject *frame) assert(frame != NULL); PyCodeObject *code = frame->f_code; assert(code != NULL); + Py_INCREF(code); return code; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index f65f05386cb..8f9ab5c0bae 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -8031,7 +8031,6 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds) /* Call super(), without args -- fill in from __class__ and first local variable on the stack. */ PyFrameObject *f; - PyCodeObject *co; Py_ssize_t i, n; f = PyThreadState_GetFrame(_PyThreadState_GET()); if (f == NULL) { @@ -8039,7 +8038,8 @@ super_init(PyObject *self, PyObject *args, PyObject *kwds) "super(): no current frame"); return -1; } - co = PyFrame_GetCode(f); + PyCodeObject *co = PyFrame_GetCode(f); + Py_DECREF(co); // use a borrowed reference if (co->co_argcount == 0) { PyErr_SetString(PyExc_RuntimeError, "super(): no arguments"); diff --git a/Python/_warnings.c b/Python/_warnings.c index 7a620dc5431..7c15ce0ef89 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -785,6 +785,8 @@ is_internal_frame(PyFrameObject *frame) PyCodeObject *code = PyFrame_GetCode(frame); PyObject *filename = code->co_filename; + Py_DECREF(code); + if (filename == NULL) { return 0; } @@ -850,7 +852,9 @@ setup_context(Py_ssize_t stack_level, PyObject **filename, int *lineno, } else { globals = f->f_globals; - *filename = PyFrame_GetCode(f)->co_filename; + PyCodeObject *code = PyFrame_GetCode(f); + *filename = code->co_filename; + Py_DECREF(code); Py_INCREF(*filename); *lineno = PyFrame_GetLineNumber(f); } diff --git a/Python/import.c b/Python/import.c index 9142ebba40d..8c94e0ec546 100644 --- a/Python/import.c +++ b/Python/import.c @@ -1557,6 +1557,7 @@ remove_importlib_frames(PyThreadState *tstate) else { prev_link = (PyObject **) &traceback->tb_next; } + Py_DECREF(code); tb = next; } done: diff --git a/Python/traceback.c b/Python/traceback.c index 1ea6cbada96..438a2c4fce7 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -581,6 +581,7 @@ tb_printinternal(PyTracebackObject *tb, PyObject *f, long limit) err = PyErr_CheckSignals(); } } + Py_DECREF(code); tb = tb->tb_next; } if (err == 0 && cnt > TB_RECURSIVE_CUTOFF) { @@ -752,12 +753,9 @@ _Py_DumpASCII(int fd, PyObject *text) static void dump_frame(int fd, PyFrameObject *frame) { - PyCodeObject *code; - int lineno; - - code = PyFrame_GetCode(frame); + PyCodeObject *code = PyFrame_GetCode(frame); PUTS(fd, " File "); - if (code != NULL && code->co_filename != NULL + if (code->co_filename != NULL && PyUnicode_Check(code->co_filename)) { PUTS(fd, "\""); @@ -768,7 +766,7 @@ dump_frame(int fd, PyFrameObject *frame) } /* PyFrame_GetLineNumber() was introduced in Python 2.7.0 and 3.2.0 */ - lineno = PyCode_Addr2Line(code, frame->f_lasti); + int lineno = PyCode_Addr2Line(code, frame->f_lasti); PUTS(fd, ", line "); if (lineno >= 0) { _Py_DumpDecimal(fd, (unsigned long)lineno); @@ -778,7 +776,7 @@ dump_frame(int fd, PyFrameObject *frame) } PUTS(fd, " in "); - if (code != NULL && code->co_name != NULL + if (code->co_name != NULL && PyUnicode_Check(code->co_name)) { _Py_DumpASCII(fd, code->co_name); } @@ -787,6 +785,7 @@ dump_frame(int fd, PyFrameObject *frame) } PUTS(fd, "\n"); + Py_DECREF(code); } static void