mirror of
https://github.com/python/cpython.git
synced 2025-10-23 07:02:24 +00:00
bpo-45637: Store the frame pointer in the cframe (GH-29267)
* Rename 'frame' to 'current_frame'
This commit is contained in:
parent
0a68b3603f
commit
f291404a80
10 changed files with 42 additions and 41 deletions
|
@ -46,6 +46,8 @@ typedef struct _cframe {
|
||||||
* accessed outside of their lifetime.
|
* accessed outside of their lifetime.
|
||||||
*/
|
*/
|
||||||
int use_tracing;
|
int use_tracing;
|
||||||
|
/* Pointer to the currently executing frame (it can be NULL) */
|
||||||
|
struct _interpreter_frame *current_frame;
|
||||||
struct _cframe *previous;
|
struct _cframe *previous;
|
||||||
} CFrame;
|
} CFrame;
|
||||||
|
|
||||||
|
@ -77,8 +79,6 @@ struct _ts {
|
||||||
struct _ts *next;
|
struct _ts *next;
|
||||||
PyInterpreterState *interp;
|
PyInterpreterState *interp;
|
||||||
|
|
||||||
/* Borrowed reference to the current frame (it can be NULL) */
|
|
||||||
struct _interpreter_frame *frame;
|
|
||||||
int recursion_depth;
|
int recursion_depth;
|
||||||
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
|
int recursion_headroom; /* Allow 50 more calls to handle any errors. */
|
||||||
int stackcheck_counter;
|
int stackcheck_counter;
|
||||||
|
|
|
@ -396,7 +396,7 @@ traceback_get_frames(traceback_t *traceback)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InterpreterFrame *pyframe = tstate->frame;
|
InterpreterFrame *pyframe = tstate->cframe->current_frame;
|
||||||
for (; pyframe != NULL;) {
|
for (; pyframe != NULL;) {
|
||||||
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
|
if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
|
||||||
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
|
tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
|
||||||
|
|
|
@ -1839,7 +1839,7 @@ _is_running(PyInterpreterState *interp)
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
InterpreterFrame *frame = tstate->frame;
|
InterpreterFrame *frame = tstate->cframe->current_frame;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1788,7 +1788,7 @@ _PyErr_CheckSignalsTstate(PyThreadState *tstate)
|
||||||
*/
|
*/
|
||||||
_Py_atomic_store(&is_tripped, 0);
|
_Py_atomic_store(&is_tripped, 0);
|
||||||
|
|
||||||
InterpreterFrame *frame = tstate->frame;
|
InterpreterFrame *frame = tstate->cframe->current_frame;
|
||||||
signal_state_t *state = &signal_global_state;
|
signal_state_t *state = &signal_global_state;
|
||||||
for (int i = 1; i < NSIG; i++) {
|
for (int i = 1; i < NSIG; i++) {
|
||||||
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
|
if (!_Py_atomic_load_relaxed(&Handlers[i].tripped)) {
|
||||||
|
|
|
@ -193,7 +193,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
||||||
Py_INCREF(result);
|
Py_INCREF(result);
|
||||||
_PyFrame_StackPush(frame, result);
|
_PyFrame_StackPush(frame, result);
|
||||||
|
|
||||||
frame->previous = tstate->frame;
|
frame->previous = tstate->cframe->current_frame;
|
||||||
|
|
||||||
gen->gi_exc_state.previous_item = tstate->exc_info;
|
gen->gi_exc_state.previous_item = tstate->exc_info;
|
||||||
tstate->exc_info = &gen->gi_exc_state;
|
tstate->exc_info = &gen->gi_exc_state;
|
||||||
|
@ -207,7 +207,7 @@ gen_send_ex2(PyGenObject *gen, PyObject *arg, PyObject **presult,
|
||||||
tstate->exc_info = gen->gi_exc_state.previous_item;
|
tstate->exc_info = gen->gi_exc_state.previous_item;
|
||||||
gen->gi_exc_state.previous_item = NULL;
|
gen->gi_exc_state.previous_item = NULL;
|
||||||
|
|
||||||
assert(tstate->frame == frame->previous);
|
assert(tstate->cframe->current_frame == frame->previous);
|
||||||
/* Don't keep the reference to previous any longer than necessary. It
|
/* Don't keep the reference to previous any longer than necessary. It
|
||||||
* may keep a chain of frames alive or it could create a reference
|
* may keep a chain of frames alive or it could create a reference
|
||||||
* cycle. */
|
* cycle. */
|
||||||
|
@ -435,9 +435,9 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
||||||
will be reported correctly to the user. */
|
will be reported correctly to the user. */
|
||||||
/* XXX We should probably be updating the current frame
|
/* XXX We should probably be updating the current frame
|
||||||
somewhere in ceval.c. */
|
somewhere in ceval.c. */
|
||||||
InterpreterFrame *prev = tstate->frame;
|
InterpreterFrame *prev = tstate->cframe->current_frame;
|
||||||
frame->previous = prev;
|
frame->previous = prev;
|
||||||
tstate->frame = frame;
|
tstate->cframe->current_frame = frame;
|
||||||
/* Close the generator that we are currently iterating with
|
/* Close the generator that we are currently iterating with
|
||||||
'yield from' or awaiting on with 'await'. */
|
'yield from' or awaiting on with 'await'. */
|
||||||
PyFrameState state = gen->gi_xframe->f_state;
|
PyFrameState state = gen->gi_xframe->f_state;
|
||||||
|
@ -445,7 +445,7 @@ _gen_throw(PyGenObject *gen, int close_on_genexit,
|
||||||
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
|
ret = _gen_throw((PyGenObject *)yf, close_on_genexit,
|
||||||
typ, val, tb);
|
typ, val, tb);
|
||||||
gen->gi_xframe->f_state = state;
|
gen->gi_xframe->f_state = state;
|
||||||
tstate->frame = prev;
|
tstate->cframe->current_frame = prev;
|
||||||
frame->previous = NULL;
|
frame->previous = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* `yf` is an iterator or a coroutine-like object. */
|
/* `yf` is an iterator or a coroutine-like object. */
|
||||||
|
|
|
@ -1561,8 +1561,9 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, InterpreterFrame *frame, int thr
|
||||||
tstate->cframe = &cframe;
|
tstate->cframe = &cframe;
|
||||||
|
|
||||||
assert(frame->depth == 0);
|
assert(frame->depth == 0);
|
||||||
/* push frame */
|
/* Push frame */
|
||||||
tstate->frame = frame;
|
frame->previous = prev_cframe->current_frame;
|
||||||
|
cframe.current_frame = frame;
|
||||||
|
|
||||||
start_frame:
|
start_frame:
|
||||||
if (_Py_EnterRecursiveCall(tstate, "")) {
|
if (_Py_EnterRecursiveCall(tstate, "")) {
|
||||||
|
@ -1570,7 +1571,8 @@ start_frame:
|
||||||
goto exit_eval_frame;
|
goto exit_eval_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(frame == tstate->frame);
|
assert(tstate->cframe == &cframe);
|
||||||
|
assert(frame == cframe.current_frame);
|
||||||
|
|
||||||
if (cframe.use_tracing) {
|
if (cframe.use_tracing) {
|
||||||
if (trace_function_entry(tstate, frame)) {
|
if (trace_function_entry(tstate, frame)) {
|
||||||
|
@ -4641,8 +4643,9 @@ check_eval_breaker:
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||||
|
new_frame->previous = frame;
|
||||||
|
cframe.current_frame = frame = new_frame;
|
||||||
new_frame->depth = frame->depth + 1;
|
new_frame->depth = frame->depth + 1;
|
||||||
tstate->frame = frame = new_frame;
|
|
||||||
goto start_frame;
|
goto start_frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4723,9 +4726,9 @@ check_eval_breaker:
|
||||||
STACK_SHRINK(1);
|
STACK_SHRINK(1);
|
||||||
Py_DECREF(func);
|
Py_DECREF(func);
|
||||||
_PyFrame_SetStackPointer(frame, stack_pointer);
|
_PyFrame_SetStackPointer(frame, stack_pointer);
|
||||||
new_frame->previous = tstate->frame;
|
new_frame->previous = frame;
|
||||||
|
frame = cframe.current_frame = new_frame;
|
||||||
new_frame->depth = frame->depth + 1;
|
new_frame->depth = frame->depth + 1;
|
||||||
tstate->frame = frame = new_frame;
|
|
||||||
goto start_frame;
|
goto start_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5258,11 +5261,12 @@ exit_eval_frame:
|
||||||
_Py_LeaveRecursiveCall(tstate);
|
_Py_LeaveRecursiveCall(tstate);
|
||||||
|
|
||||||
if (frame->depth) {
|
if (frame->depth) {
|
||||||
_PyFrame_StackPush(frame->previous, retval);
|
cframe.current_frame = frame->previous;
|
||||||
|
_PyFrame_StackPush(cframe.current_frame, retval);
|
||||||
if (_PyEvalFrameClearAndPop(tstate, frame)) {
|
if (_PyEvalFrameClearAndPop(tstate, frame)) {
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
}
|
}
|
||||||
frame = tstate->frame;
|
frame = cframe.current_frame;
|
||||||
if (retval == NULL) {
|
if (retval == NULL) {
|
||||||
assert(_PyErr_Occurred(tstate));
|
assert(_PyErr_Occurred(tstate));
|
||||||
throwflag = 1;
|
throwflag = 1;
|
||||||
|
@ -5270,11 +5274,11 @@ exit_eval_frame:
|
||||||
retval = NULL;
|
retval = NULL;
|
||||||
goto resume_frame;
|
goto resume_frame;
|
||||||
}
|
}
|
||||||
tstate->frame = frame->previous;
|
|
||||||
|
|
||||||
/* Restore previous cframe */
|
/* Restore previous cframe. */
|
||||||
tstate->cframe = cframe.previous;
|
tstate->cframe = cframe.previous;
|
||||||
tstate->cframe->use_tracing = cframe.use_tracing;
|
tstate->cframe->use_tracing = cframe.use_tracing;
|
||||||
|
assert(tstate->cframe->current_frame == frame->previous);
|
||||||
return _Py_CheckFunctionResult(tstate, NULL, retval, __func__);
|
return _Py_CheckFunctionResult(tstate, NULL, retval, __func__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5891,8 +5895,6 @@ _PyEvalFramePushAndInit(PyThreadState *tstate, PyFrameConstructor *con,
|
||||||
_PyFrame_Clear(frame, 0);
|
_PyFrame_Clear(frame, 0);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
frame->previous = tstate->frame;
|
|
||||||
tstate->frame = frame;
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5906,7 +5908,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, InterpreterFrame * frame)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
--tstate->recursion_depth;
|
--tstate->recursion_depth;
|
||||||
tstate->frame = frame->previous;
|
|
||||||
_PyThreadState_PopFrame(tstate, frame);
|
_PyThreadState_PopFrame(tstate, frame);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -6518,17 +6519,17 @@ InterpreterFrame *
|
||||||
_PyEval_GetFrame(void)
|
_PyEval_GetFrame(void)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
return tstate->frame;
|
return tstate->cframe->current_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyFrameObject *
|
PyFrameObject *
|
||||||
PyEval_GetFrame(void)
|
PyEval_GetFrame(void)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
if (tstate->frame == NULL) {
|
if (tstate->cframe->current_frame == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyFrameObject *f = _PyFrame_GetFrameObject(tstate->frame);
|
PyFrameObject *f = _PyFrame_GetFrameObject(tstate->cframe->current_frame);
|
||||||
if (f == NULL) {
|
if (f == NULL) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
@ -6538,7 +6539,7 @@ PyEval_GetFrame(void)
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyEval_GetBuiltins(PyThreadState *tstate)
|
_PyEval_GetBuiltins(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
InterpreterFrame *frame = tstate->frame;
|
InterpreterFrame *frame = tstate->cframe->current_frame;
|
||||||
if (frame != NULL) {
|
if (frame != NULL) {
|
||||||
return frame->f_builtins;
|
return frame->f_builtins;
|
||||||
}
|
}
|
||||||
|
@ -6571,7 +6572,7 @@ PyObject *
|
||||||
PyEval_GetLocals(void)
|
PyEval_GetLocals(void)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
InterpreterFrame *current_frame = tstate->frame;
|
InterpreterFrame *current_frame = tstate->cframe->current_frame;
|
||||||
if (current_frame == NULL) {
|
if (current_frame == NULL) {
|
||||||
_PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
|
_PyErr_SetString(tstate, PyExc_SystemError, "frame does not exist");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -6590,7 +6591,7 @@ PyObject *
|
||||||
PyEval_GetGlobals(void)
|
PyEval_GetGlobals(void)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
InterpreterFrame *current_frame = tstate->frame;
|
InterpreterFrame *current_frame = tstate->cframe->current_frame;
|
||||||
if (current_frame == NULL) {
|
if (current_frame == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -6601,7 +6602,7 @@ int
|
||||||
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
|
PyEval_MergeCompilerFlags(PyCompilerFlags *cf)
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
InterpreterFrame *current_frame = tstate->frame;
|
InterpreterFrame *current_frame = tstate->cframe->current_frame;
|
||||||
int result = cf->cf_flags != 0;
|
int result = cf->cf_flags != 0;
|
||||||
|
|
||||||
if (current_frame != NULL) {
|
if (current_frame != NULL) {
|
||||||
|
@ -6651,7 +6652,7 @@ PyEval_GetFuncDesc(PyObject *func)
|
||||||
#define C_TRACE(x, call) \
|
#define C_TRACE(x, call) \
|
||||||
if (use_tracing && tstate->c_profilefunc) { \
|
if (use_tracing && tstate->c_profilefunc) { \
|
||||||
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
|
if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
|
||||||
tstate, tstate->frame, \
|
tstate, tstate->cframe->current_frame, \
|
||||||
PyTrace_C_CALL, func)) { \
|
PyTrace_C_CALL, func)) { \
|
||||||
x = NULL; \
|
x = NULL; \
|
||||||
} \
|
} \
|
||||||
|
@ -6661,13 +6662,13 @@ if (use_tracing && tstate->c_profilefunc) { \
|
||||||
if (x == NULL) { \
|
if (x == NULL) { \
|
||||||
call_trace_protected(tstate->c_profilefunc, \
|
call_trace_protected(tstate->c_profilefunc, \
|
||||||
tstate->c_profileobj, \
|
tstate->c_profileobj, \
|
||||||
tstate, tstate->frame, \
|
tstate, tstate->cframe->current_frame, \
|
||||||
PyTrace_C_EXCEPTION, func); \
|
PyTrace_C_EXCEPTION, func); \
|
||||||
/* XXX should pass (type, value, tb) */ \
|
/* XXX should pass (type, value, tb) */ \
|
||||||
} else { \
|
} else { \
|
||||||
if (call_trace(tstate->c_profilefunc, \
|
if (call_trace(tstate->c_profilefunc, \
|
||||||
tstate->c_profileobj, \
|
tstate->c_profileobj, \
|
||||||
tstate, tstate->frame, \
|
tstate, tstate->cframe->current_frame, \
|
||||||
PyTrace_C_RETURN, func)) { \
|
PyTrace_C_RETURN, func)) { \
|
||||||
Py_DECREF(x); \
|
Py_DECREF(x); \
|
||||||
x = NULL; \
|
x = NULL; \
|
||||||
|
|
|
@ -2031,7 +2031,7 @@ Py_EndInterpreter(PyThreadState *tstate)
|
||||||
if (tstate != _PyThreadState_GET()) {
|
if (tstate != _PyThreadState_GET()) {
|
||||||
Py_FatalError("thread is not current");
|
Py_FatalError("thread is not current");
|
||||||
}
|
}
|
||||||
if (tstate->frame != NULL) {
|
if (tstate->cframe->current_frame != NULL) {
|
||||||
Py_FatalError("thread still has a frame");
|
Py_FatalError("thread still has a frame");
|
||||||
}
|
}
|
||||||
interp->finalizing = 1;
|
interp->finalizing = 1;
|
||||||
|
|
|
@ -636,12 +636,12 @@ new_threadstate(PyInterpreterState *interp, int init)
|
||||||
|
|
||||||
tstate->interp = interp;
|
tstate->interp = interp;
|
||||||
|
|
||||||
tstate->frame = NULL;
|
|
||||||
tstate->recursion_depth = 0;
|
tstate->recursion_depth = 0;
|
||||||
tstate->recursion_headroom = 0;
|
tstate->recursion_headroom = 0;
|
||||||
tstate->stackcheck_counter = 0;
|
tstate->stackcheck_counter = 0;
|
||||||
tstate->tracing = 0;
|
tstate->tracing = 0;
|
||||||
tstate->root_cframe.use_tracing = 0;
|
tstate->root_cframe.use_tracing = 0;
|
||||||
|
tstate->root_cframe.current_frame = NULL;
|
||||||
tstate->cframe = &tstate->root_cframe;
|
tstate->cframe = &tstate->root_cframe;
|
||||||
tstate->gilstate_counter = 0;
|
tstate->gilstate_counter = 0;
|
||||||
tstate->async_exc = NULL;
|
tstate->async_exc = NULL;
|
||||||
|
@ -861,7 +861,7 @@ PyThreadState_Clear(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose;
|
int verbose = _PyInterpreterState_GetConfig(tstate->interp)->verbose;
|
||||||
|
|
||||||
if (verbose && tstate->frame != NULL) {
|
if (verbose && tstate->cframe->current_frame != NULL) {
|
||||||
/* bpo-20526: After the main thread calls
|
/* bpo-20526: After the main thread calls
|
||||||
_PyRuntimeState_SetFinalizing() in Py_FinalizeEx(), threads must
|
_PyRuntimeState_SetFinalizing() in Py_FinalizeEx(), threads must
|
||||||
exit when trying to take the GIL. If a thread exit in the middle of
|
exit when trying to take the GIL. If a thread exit in the middle of
|
||||||
|
@ -1134,10 +1134,10 @@ PyFrameObject*
|
||||||
PyThreadState_GetFrame(PyThreadState *tstate)
|
PyThreadState_GetFrame(PyThreadState *tstate)
|
||||||
{
|
{
|
||||||
assert(tstate != NULL);
|
assert(tstate != NULL);
|
||||||
if (tstate->frame == NULL) {
|
if (tstate->cframe->current_frame == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->frame);
|
PyFrameObject *frame = _PyFrame_GetFrameObject(tstate->cframe->current_frame);
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
}
|
}
|
||||||
|
@ -1277,7 +1277,7 @@ _PyThread_CurrentFrames(void)
|
||||||
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
for (i = runtime->interpreters.head; i != NULL; i = i->next) {
|
||||||
PyThreadState *t;
|
PyThreadState *t;
|
||||||
for (t = i->tstate_head; t != NULL; t = t->next) {
|
for (t = i->tstate_head; t != NULL; t = t->next) {
|
||||||
InterpreterFrame *frame = t->frame;
|
InterpreterFrame *frame = t->cframe->current_frame;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1813,7 +1813,7 @@ sys__getframe_impl(PyObject *module, int depth)
|
||||||
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
|
/*[clinic end generated code: output=d438776c04d59804 input=c1be8a6464b11ee5]*/
|
||||||
{
|
{
|
||||||
PyThreadState *tstate = _PyThreadState_GET();
|
PyThreadState *tstate = _PyThreadState_GET();
|
||||||
InterpreterFrame *frame = tstate->frame;
|
InterpreterFrame *frame = tstate->cframe->current_frame;
|
||||||
|
|
||||||
if (_PySys_Audit(tstate, "sys._getframe", NULL) < 0) {
|
if (_PySys_Audit(tstate, "sys._getframe", NULL) < 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
|
@ -1082,7 +1082,7 @@ dump_traceback(int fd, PyThreadState *tstate, int write_header)
|
||||||
PUTS(fd, "Stack (most recent call first):\n");
|
PUTS(fd, "Stack (most recent call first):\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
frame = tstate->frame;
|
frame = tstate->cframe->current_frame;
|
||||||
if (frame == NULL) {
|
if (frame == NULL) {
|
||||||
PUTS(fd, " <no Python frame>\n");
|
PUTS(fd, " <no Python frame>\n");
|
||||||
return;
|
return;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue