Skip to content

Commit b5022ba

Browse files
committed
iterative coro-walk
1 parent ef51563 commit b5022ba

2 files changed

Lines changed: 57 additions & 63 deletions

File tree

Modules/_remote_debugging/_remote_debugging.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -725,13 +725,6 @@ extern int parse_task(
725725
PyObject *render_to
726726
);
727727

728-
extern int parse_coro_chain(
729-
RemoteUnwinderObject *unwinder,
730-
uintptr_t coro_address,
731-
PyObject *render_to,
732-
size_t depth
733-
);
734-
735728
extern int parse_async_frame_chain(
736729
RemoteUnwinderObject *unwinder,
737730
PyObject *calls,

Modules/_remote_debugging/asyncio.c

Lines changed: 57 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,14 @@ parse_task_name(
238238
* ============================================================================ */
239239

240240
static int
241-
handle_yield_from_frame(
241+
get_awaited_coro_address(
242242
RemoteUnwinderObject *unwinder,
243243
uintptr_t gi_iframe_addr,
244244
uintptr_t gen_type_addr,
245-
PyObject *render_to,
246-
size_t depth
245+
uintptr_t *next_coro
247246
) {
247+
*next_coro = 0;
248+
248249
// Read the entire interpreter frame at once
249250
char iframe[SIZEOF_INTERP_FRAME];
250251
int err = _Py_RemoteDebug_PagedReadRemoteMemory(
@@ -300,80 +301,80 @@ handle_yield_from_frame(
300301
doesn't match the type of whatever it points to
301302
in its cr_await.
302303
*/
303-
err = parse_coro_chain(unwinder, gi_await_addr, render_to,
304-
depth + 1);
305-
if (err) {
306-
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain in yield_from");
307-
return -1;
308-
}
304+
*next_coro = gi_await_addr;
309305
}
310306
}
311307
}
312308

313309
return 0;
314310
}
315311

316-
int
312+
static int
317313
parse_coro_chain(
318314
RemoteUnwinderObject *unwinder,
319315
uintptr_t coro_address,
320-
PyObject *render_to,
321-
size_t depth
316+
PyObject *render_to
322317
) {
323318
assert((void*)coro_address != NULL);
324319

325-
if (depth >= MAX_FRAME_CHAIN_DEPTH) {
326-
PyErr_SetString(PyExc_RuntimeError,
327-
"Too many coroutine frames (possible infinite loop)");
328-
set_exception_cause(unwinder, PyExc_RuntimeError,
329-
"Coroutine chain depth limit exceeded");
330-
return -1;
331-
}
320+
for (size_t depth = 0; (void*)coro_address != NULL; depth++) {
321+
if (depth >= MAX_FRAME_CHAIN_DEPTH) {
322+
PyErr_SetString(PyExc_RuntimeError,
323+
"Too many coroutine frames (possible infinite loop)");
324+
set_exception_cause(unwinder, PyExc_RuntimeError,
325+
"Coroutine chain depth limit exceeded");
326+
return -1;
327+
}
332328

333-
// Read the entire generator object at once
334-
char gen_object[SIZEOF_GEN_OBJ];
335-
int err = _Py_RemoteDebug_PagedReadRemoteMemory(
336-
&unwinder->handle,
337-
coro_address,
338-
SIZEOF_GEN_OBJ,
339-
gen_object);
340-
if (err < 0) {
341-
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read generator object in coro chain");
342-
return -1;
343-
}
329+
// Read the entire generator object at once
330+
char gen_object[SIZEOF_GEN_OBJ];
331+
int err = _Py_RemoteDebug_PagedReadRemoteMemory(
332+
&unwinder->handle,
333+
coro_address,
334+
SIZEOF_GEN_OBJ,
335+
gen_object);
336+
if (err < 0) {
337+
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to read generator object in coro chain");
338+
return -1;
339+
}
344340

345-
int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state);
346-
if (frame_state == FRAME_CLEARED) {
347-
return 0;
348-
}
341+
int8_t frame_state = GET_MEMBER(int8_t, gen_object, unwinder->debug_offsets.gen_object.gi_frame_state);
342+
if (frame_state == FRAME_CLEARED) {
343+
return 0;
344+
}
349345

350-
uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type);
346+
uintptr_t gen_type_addr = GET_MEMBER(uintptr_t, gen_object, unwinder->debug_offsets.pyobject.ob_type);
351347

352-
PyObject* name = NULL;
348+
PyObject* name = NULL;
353349

354-
// Parse the previous frame using the gi_iframe from local copy
355-
uintptr_t prev_frame;
356-
uintptr_t gi_iframe_addr = coro_address + (uintptr_t)unwinder->debug_offsets.gen_object.gi_iframe;
357-
uintptr_t address_of_code_object = 0;
358-
if (parse_frame_object(unwinder, &name, gi_iframe_addr, &address_of_code_object, &prev_frame) < 0) {
359-
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in coro chain");
360-
return -1;
361-
}
350+
// Parse the previous frame using the gi_iframe from local copy
351+
uintptr_t prev_frame;
352+
uintptr_t gi_iframe_addr = coro_address + (uintptr_t)unwinder->debug_offsets.gen_object.gi_iframe;
353+
uintptr_t address_of_code_object = 0;
354+
if (parse_frame_object(unwinder, &name, gi_iframe_addr, &address_of_code_object, &prev_frame) < 0) {
355+
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse frame object in coro chain");
356+
return -1;
357+
}
362358

363-
if (!name) {
364-
return 0;
365-
}
359+
if (!name) {
360+
return 0;
361+
}
366362

367-
if (PyList_Append(render_to, name)) {
363+
if (PyList_Append(render_to, name)) {
364+
Py_DECREF(name);
365+
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to coro chain");
366+
return -1;
367+
}
368368
Py_DECREF(name);
369-
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append frame to coro chain");
370-
return -1;
371-
}
372-
Py_DECREF(name);
373369

374-
if (frame_state == FRAME_SUSPENDED_YIELD_FROM) {
375-
return handle_yield_from_frame(unwinder, gi_iframe_addr, gen_type_addr,
376-
render_to, depth);
370+
if (frame_state != FRAME_SUSPENDED_YIELD_FROM) {
371+
return 0;
372+
}
373+
374+
if (get_awaited_coro_address(unwinder, gi_iframe_addr, gen_type_addr,
375+
&coro_address) < 0) {
376+
return -1;
377+
}
377378
}
378379

379380
return 0;
@@ -419,7 +420,7 @@ create_task_result(
419420
coro_addr = GET_MEMBER_NO_TAG(uintptr_t, task_obj, unwinder->async_debug_offsets.asyncio_task_object.task_coro);
420421

421422
if ((void*)coro_addr != NULL) {
422-
if (parse_coro_chain(unwinder, coro_addr, call_stack, 0) < 0) {
423+
if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) {
423424
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain");
424425
goto error;
425426
}

0 commit comments

Comments
 (0)