aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_interpchannelsmodule.c26
-rw-r--r--Modules/_interpqueuesmodule.c11
-rw-r--r--Modules/_interpretersmodule.c90
-rw-r--r--Modules/_lsprof.c24
-rw-r--r--Modules/_pickle.c9
-rw-r--r--Modules/_remote_debugging_module.c339
-rw-r--r--Modules/_sqlite/module.c39
-rw-r--r--Modules/_testinternalcapi.c4
-rw-r--r--Modules/clinic/_lsprof.c.h35
9 files changed, 418 insertions, 159 deletions
diff --git a/Modules/_interpchannelsmodule.c b/Modules/_interpchannelsmodule.c
index ea2e5f99dfa..ee5e2b005e0 100644
--- a/Modules/_interpchannelsmodule.c
+++ b/Modules/_interpchannelsmodule.c
@@ -220,6 +220,22 @@ wait_for_lock(PyThread_type_lock mutex, PY_TIMEOUT_T timeout)
return 0;
}
+static int
+ensure_highlevel_module_loaded(void)
+{
+ PyObject *highlevel =
+ PyImport_ImportModule("concurrent.interpreters._channels");
+ if (highlevel == NULL) {
+ PyErr_Clear();
+ highlevel = PyImport_ImportModule("test.support.channels");
+ if (highlevel == NULL) {
+ return -1;
+ }
+ }
+ Py_DECREF(highlevel);
+ return 0;
+}
+
/* module state *************************************************************/
@@ -2742,15 +2758,9 @@ _get_current_channelend_type(int end)
}
if (cls == NULL) {
// Force the module to be loaded, to register the type.
- PyObject *highlevel = PyImport_ImportModule("interpreters.channels");
- if (highlevel == NULL) {
- PyErr_Clear();
- highlevel = PyImport_ImportModule("test.support.interpreters.channels");
- if (highlevel == NULL) {
- return NULL;
- }
+ if (ensure_highlevel_module_loaded() < 0) {
+ return NULL;
}
- Py_DECREF(highlevel);
if (end == CHANNEL_SEND) {
cls = state->send_channel_type;
}
diff --git a/Modules/_interpqueuesmodule.c b/Modules/_interpqueuesmodule.c
index 71d8fd8716c..e22709d5119 100644
--- a/Modules/_interpqueuesmodule.c
+++ b/Modules/_interpqueuesmodule.c
@@ -136,13 +136,10 @@ idarg_int64_converter(PyObject *arg, void *ptr)
static int
ensure_highlevel_module_loaded(void)
{
- PyObject *highlevel = PyImport_ImportModule("interpreters.queues");
+ PyObject *highlevel =
+ PyImport_ImportModule("concurrent.interpreters._queues");
if (highlevel == NULL) {
- PyErr_Clear();
- highlevel = PyImport_ImportModule("test.support.interpreters.queues");
- if (highlevel == NULL) {
- return -1;
- }
+ return -1;
}
Py_DECREF(highlevel);
return 0;
@@ -299,7 +296,7 @@ add_QueueError(PyObject *mod)
{
module_state *state = get_module_state(mod);
-#define PREFIX "test.support.interpreters."
+#define PREFIX "concurrent.interpreters."
#define ADD_EXCTYPE(NAME, BASE, DOC) \
assert(state->NAME == NULL); \
if (add_exctype(mod, &state->NAME, PREFIX #NAME, DOC, BASE) < 0) { \
diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c
index 037e9544543..fdfb3e6dd34 100644
--- a/Modules/_interpretersmodule.c
+++ b/Modules/_interpretersmodule.c
@@ -80,21 +80,11 @@ is_notshareable_raised(PyThreadState *tstate)
}
static void
-unwrap_not_shareable(PyThreadState *tstate)
+unwrap_not_shareable(PyThreadState *tstate, _PyXI_failure *failure)
{
- if (!is_notshareable_raised(tstate)) {
- return;
- }
- PyObject *exc = _PyErr_GetRaisedException(tstate);
- PyObject *cause = PyException_GetCause(exc);
- if (cause != NULL) {
- Py_DECREF(exc);
- exc = cause;
+ if (_PyXI_UnwrapNotShareableError(tstate, failure) < 0) {
+ _PyErr_Clear(tstate);
}
- else {
- assert(PyException_GetContext(exc) == NULL);
- }
- _PyErr_SetRaisedException(tstate, exc);
}
@@ -532,13 +522,30 @@ _interp_call_pack(PyThreadState *tstate, struct interp_call *call,
return 0;
}
+static void
+wrap_notshareable(PyThreadState *tstate, const char *label)
+{
+ if (!is_notshareable_raised(tstate)) {
+ return;
+ }
+ assert(label != NULL && strlen(label) > 0);
+ PyObject *cause = _PyErr_GetRaisedException(tstate);
+ _PyXIData_FormatNotShareableError(tstate, "%s not shareable", label);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ PyException_SetCause(exc, cause);
+ _PyErr_SetRaisedException(tstate, exc);
+}
+
static int
_interp_call_unpack(struct interp_call *call,
PyObject **p_func, PyObject **p_args, PyObject **p_kwargs)
{
+ PyThreadState *tstate = PyThreadState_Get();
+
// Unpack the func.
PyObject *func = _PyXIData_NewObject(call->func);
if (func == NULL) {
+ wrap_notshareable(tstate, "func");
return -1;
}
// Unpack the args.
@@ -553,6 +560,7 @@ _interp_call_unpack(struct interp_call *call,
else {
args = _PyXIData_NewObject(call->args);
if (args == NULL) {
+ wrap_notshareable(tstate, "args");
Py_DECREF(func);
return -1;
}
@@ -563,6 +571,7 @@ _interp_call_unpack(struct interp_call *call,
if (call->kwargs != NULL) {
kwargs = _PyXIData_NewObject(call->kwargs);
if (kwargs == NULL) {
+ wrap_notshareable(tstate, "kwargs");
Py_DECREF(func);
Py_DECREF(args);
return -1;
@@ -577,7 +586,7 @@ _interp_call_unpack(struct interp_call *call,
static int
_make_call(struct interp_call *call,
- PyObject **p_result, _PyXI_errcode *p_errcode)
+ PyObject **p_result, _PyXI_failure *failure)
{
assert(call != NULL && call->func != NULL);
PyThreadState *tstate = _PyThreadState_GET();
@@ -588,12 +597,10 @@ _make_call(struct interp_call *call,
assert(func == NULL);
assert(args == NULL);
assert(kwargs == NULL);
- *p_errcode = is_notshareable_raised(tstate)
- ? _PyXI_ERR_NOT_SHAREABLE
- : _PyXI_ERR_OTHER;
+ _PyXI_InitFailure(failure, _PyXI_ERR_OTHER, NULL);
+ unwrap_not_shareable(tstate, failure);
return -1;
}
- *p_errcode = _PyXI_ERR_NO_ERROR;
// Make the call.
PyObject *resobj = PyObject_Call(func, args, kwargs);
@@ -608,17 +615,17 @@ _make_call(struct interp_call *call,
}
static int
-_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_errcode *p_errcode)
+_run_script(_PyXIData_t *script, PyObject *ns, _PyXI_failure *failure)
{
PyObject *code = _PyXIData_NewObject(script);
if (code == NULL) {
- *p_errcode = _PyXI_ERR_NOT_SHAREABLE;
+ _PyXI_InitFailure(failure, _PyXI_ERR_NOT_SHAREABLE, NULL);
return -1;
}
PyObject *result = PyEval_EvalCode(code, ns, ns);
Py_DECREF(code);
if (result == NULL) {
- *p_errcode = _PyXI_ERR_UNCAUGHT_EXCEPTION;
+ _PyXI_InitFailure(failure, _PyXI_ERR_UNCAUGHT_EXCEPTION, NULL);
return -1;
}
assert(result == Py_None);
@@ -644,8 +651,14 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
PyObject *shareables, struct run_result *runres)
{
assert(!_PyErr_Occurred(tstate));
+ int res = -1;
+ _PyXI_failure *failure = _PyXI_NewFailure();
+ if (failure == NULL) {
+ return -1;
+ }
_PyXI_session *session = _PyXI_NewSession();
if (session == NULL) {
+ _PyXI_FreeFailure(failure);
return -1;
}
_PyXI_session_result result = {0};
@@ -655,43 +668,44 @@ _run_in_interpreter(PyThreadState *tstate, PyInterpreterState *interp,
// If an error occured at this step, it means that interp
// was not prepared and switched.
_PyXI_FreeSession(session);
+ _PyXI_FreeFailure(failure);
assert(result.excinfo == NULL);
return -1;
}
// Run in the interpreter.
- int res = -1;
- _PyXI_errcode errcode = _PyXI_ERR_NO_ERROR;
if (script != NULL) {
assert(call == NULL);
- PyObject *mainns = _PyXI_GetMainNamespace(session, &errcode);
+ PyObject *mainns = _PyXI_GetMainNamespace(session, failure);
if (mainns == NULL) {
goto finally;
}
- res = _run_script(script, mainns, &errcode);
+ res = _run_script(script, mainns, failure);
}
else {
assert(call != NULL);
PyObject *resobj;
- res = _make_call(call, &resobj, &errcode);
+ res = _make_call(call, &resobj, failure);
if (res == 0) {
- res = _PyXI_Preserve(session, "resobj", resobj, &errcode);
+ res = _PyXI_Preserve(session, "resobj", resobj, failure);
Py_DECREF(resobj);
if (res < 0) {
goto finally;
}
}
}
- int exitres;
finally:
// Clean up and switch back.
- exitres = _PyXI_Exit(session, errcode, &result);
+ (void)res;
+ int exitres = _PyXI_Exit(session, failure, &result);
assert(res == 0 || exitres != 0);
_PyXI_FreeSession(session);
+ _PyXI_FreeFailure(failure);
res = exitres;
if (_PyErr_Occurred(tstate)) {
+ // It's a directly propagated exception.
assert(res < 0);
}
else if (res < 0) {
@@ -1064,7 +1078,7 @@ interp_set___main___attrs(PyObject *self, PyObject *args, PyObject *kwargs)
// Clean up and switch back.
assert(!PyErr_Occurred());
- int res = _PyXI_Exit(session, _PyXI_ERR_NO_ERROR, NULL);
+ int res = _PyXI_Exit(session, NULL, NULL);
_PyXI_FreeSession(session);
assert(res == 0);
if (res < 0) {
@@ -1124,7 +1138,7 @@ interp_exec(PyObject *self, PyObject *args, PyObject *kwds)
// global variables. They will be resolved against __main__.
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
- unwrap_not_shareable(tstate);
+ unwrap_not_shareable(tstate, NULL);
return NULL;
}
@@ -1188,7 +1202,7 @@ interp_run_string(PyObject *self, PyObject *args, PyObject *kwds)
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, script, &xidata) < 0) {
- unwrap_not_shareable(tstate);
+ unwrap_not_shareable(tstate, NULL);
return NULL;
}
@@ -1251,7 +1265,7 @@ interp_run_func(PyObject *self, PyObject *args, PyObject *kwds)
_PyXIData_t xidata = {0};
if (_PyCode_GetScriptXIData(tstate, code, &xidata) < 0) {
- unwrap_not_shareable(tstate);
+ unwrap_not_shareable(tstate, NULL);
return NULL;
}
@@ -1542,16 +1556,16 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
}
PyObject *captured = NULL;
- _PyXI_excinfo info = {0};
- if (_PyXI_InitExcInfo(&info, exc) < 0) {
+ _PyXI_excinfo *info = _PyXI_NewExcInfo(exc);
+ if (info == NULL) {
goto finally;
}
- captured = _PyXI_ExcInfoAsObject(&info);
+ captured = _PyXI_ExcInfoAsObject(info);
if (captured == NULL) {
goto finally;
}
- PyObject *formatted = _PyXI_FormatExcInfo(&info);
+ PyObject *formatted = _PyXI_FormatExcInfo(info);
if (formatted == NULL) {
Py_CLEAR(captured);
goto finally;
@@ -1564,7 +1578,7 @@ capture_exception(PyObject *self, PyObject *args, PyObject *kwds)
}
finally:
- _PyXI_ClearExcInfo(&info);
+ _PyXI_FreeExcInfo(info);
if (exc != exc_arg) {
if (PyErr_Occurred()) {
PyErr_SetRaisedException(exc);
diff --git a/Modules/_lsprof.c b/Modules/_lsprof.c
index bbad5eb6903..d0074b2a0d1 100644
--- a/Modules/_lsprof.c
+++ b/Modules/_lsprof.c
@@ -632,6 +632,27 @@ _lsprof_Profiler__pystart_callback_impl(ProfilerObject *self, PyObject *code,
}
/*[clinic input]
+_lsprof.Profiler._pythrow_callback
+
+ code: object
+ instruction_offset: object
+ exception: object
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code,
+ PyObject *instruction_offset,
+ PyObject *exception)
+/*[clinic end generated code: output=0a32988919dfb94c input=fd728fc2c074f5e6]*/
+{
+ ptrace_enter_call((PyObject*)self, (void *)code, code);
+
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
_lsprof.Profiler._pyreturn_callback
code: object
@@ -747,7 +768,7 @@ static const struct {
} callback_table[] = {
{PY_MONITORING_EVENT_PY_START, "_pystart_callback"},
{PY_MONITORING_EVENT_PY_RESUME, "_pystart_callback"},
- {PY_MONITORING_EVENT_PY_THROW, "_pystart_callback"},
+ {PY_MONITORING_EVENT_PY_THROW, "_pythrow_callback"},
{PY_MONITORING_EVENT_PY_RETURN, "_pyreturn_callback"},
{PY_MONITORING_EVENT_PY_YIELD, "_pyreturn_callback"},
{PY_MONITORING_EVENT_PY_UNWIND, "_pyreturn_callback"},
@@ -1002,6 +1023,7 @@ static PyMethodDef profiler_methods[] = {
_LSPROF_PROFILER_DISABLE_METHODDEF
_LSPROF_PROFILER_CLEAR_METHODDEF
_LSPROF_PROFILER__PYSTART_CALLBACK_METHODDEF
+ _LSPROF_PROFILER__PYTHROW_CALLBACK_METHODDEF
_LSPROF_PROFILER__PYRETURN_CALLBACK_METHODDEF
_LSPROF_PROFILER__CCALL_CALLBACK_METHODDEF
_LSPROF_PROFILER__CRETURN_CALLBACK_METHODDEF
diff --git a/Modules/_pickle.c b/Modules/_pickle.c
index 86d8b38620c..cf3ceb43fb3 100644
--- a/Modules/_pickle.c
+++ b/Modules/_pickle.c
@@ -5543,17 +5543,16 @@ static int
load_counted_binstring(PickleState *st, UnpicklerObject *self, int nbytes)
{
PyObject *obj;
- Py_ssize_t size;
+ long size;
char *s;
if (_Unpickler_Read(self, st, &s, nbytes) < 0)
return -1;
- size = calc_binsize(s, nbytes);
+ size = calc_binint(s, nbytes);
if (size < 0) {
- PyErr_Format(st->UnpicklingError,
- "BINSTRING exceeds system's maximum size of %zd bytes",
- PY_SSIZE_T_MAX);
+ PyErr_SetString(st->UnpicklingError,
+ "BINSTRING pickle has negative byte count");
return -1;
}
diff --git a/Modules/_remote_debugging_module.c b/Modules/_remote_debugging_module.c
index ea58f38006e..19f12c3b02e 100644
--- a/Modules/_remote_debugging_module.c
+++ b/Modules/_remote_debugging_module.c
@@ -97,6 +97,101 @@ struct _Py_AsyncioModuleDebugOffsets {
} asyncio_thread_state;
};
+/* ============================================================================
+ * STRUCTSEQ TYPE DEFINITIONS
+ * ============================================================================ */
+
+// TaskInfo structseq type - replaces 4-tuple (task_id, task_name, coroutine_stack, awaited_by)
+static PyStructSequence_Field TaskInfo_fields[] = {
+ {"task_id", "Task ID (memory address)"},
+ {"task_name", "Task name"},
+ {"coroutine_stack", "Coroutine call stack"},
+ {"awaited_by", "Tasks awaiting this task"},
+ {NULL}
+};
+
+static PyStructSequence_Desc TaskInfo_desc = {
+ "_remote_debugging.TaskInfo",
+ "Information about an asyncio task",
+ TaskInfo_fields,
+ 4
+};
+
+// FrameInfo structseq type - replaces 3-tuple (filename, lineno, funcname)
+static PyStructSequence_Field FrameInfo_fields[] = {
+ {"filename", "Source code filename"},
+ {"lineno", "Line number"},
+ {"funcname", "Function name"},
+ {NULL}
+};
+
+static PyStructSequence_Desc FrameInfo_desc = {
+ "_remote_debugging.FrameInfo",
+ "Information about a frame",
+ FrameInfo_fields,
+ 3
+};
+
+// CoroInfo structseq type - replaces 2-tuple (call_stack, task_name)
+static PyStructSequence_Field CoroInfo_fields[] = {
+ {"call_stack", "Coroutine call stack"},
+ {"task_name", "Task name"},
+ {NULL}
+};
+
+static PyStructSequence_Desc CoroInfo_desc = {
+ "_remote_debugging.CoroInfo",
+ "Information about a coroutine",
+ CoroInfo_fields,
+ 2
+};
+
+// ThreadInfo structseq type - replaces 2-tuple (thread_id, frame_info)
+static PyStructSequence_Field ThreadInfo_fields[] = {
+ {"thread_id", "Thread ID"},
+ {"frame_info", "Frame information"},
+ {NULL}
+};
+
+static PyStructSequence_Desc ThreadInfo_desc = {
+ "_remote_debugging.ThreadInfo",
+ "Information about a thread",
+ ThreadInfo_fields,
+ 2
+};
+
+// AwaitedInfo structseq type - replaces 2-tuple (tid, awaited_by_list)
+static PyStructSequence_Field AwaitedInfo_fields[] = {
+ {"thread_id", "Thread ID"},
+ {"awaited_by", "List of tasks awaited by this thread"},
+ {NULL}
+};
+
+static PyStructSequence_Desc AwaitedInfo_desc = {
+ "_remote_debugging.AwaitedInfo",
+ "Information about what a thread is awaiting",
+ AwaitedInfo_fields,
+ 2
+};
+
+typedef struct {
+ PyObject *func_name;
+ PyObject *file_name;
+ int first_lineno;
+ PyObject *linetable; // bytes
+ uintptr_t addr_code_adaptive;
+} CachedCodeMetadata;
+
+typedef struct {
+ /* Types */
+ PyTypeObject *RemoteDebugging_Type;
+ PyTypeObject *TaskInfo_Type;
+ PyTypeObject *FrameInfo_Type;
+ PyTypeObject *CoroInfo_Type;
+ PyTypeObject *ThreadInfo_Type;
+ PyTypeObject *AwaitedInfo_Type;
+} RemoteDebuggingState;
+
typedef struct {
PyObject_HEAD
proc_handle_t handle;
@@ -109,6 +204,7 @@ typedef struct {
uint64_t code_object_generation;
_Py_hashtable_t *code_object_cache;
int debug;
+ RemoteDebuggingState *cached_state; // Cached module state
#ifdef Py_GIL_DISABLED
// TLBC cache invalidation tracking
uint32_t tlbc_generation; // Track TLBC index pool changes
@@ -116,19 +212,6 @@ typedef struct {
#endif
} RemoteUnwinderObject;
-typedef struct {
- PyObject *func_name;
- PyObject *file_name;
- int first_lineno;
- PyObject *linetable; // bytes
- uintptr_t addr_code_adaptive;
-} CachedCodeMetadata;
-
-typedef struct {
- /* Types */
- PyTypeObject *RemoteDebugging_Type;
-} RemoteDebuggingState;
-
typedef struct
{
int lineno;
@@ -218,6 +301,24 @@ RemoteDebugging_GetState(PyObject *module)
return (RemoteDebuggingState *)state;
}
+static inline RemoteDebuggingState *
+RemoteDebugging_GetStateFromType(PyTypeObject *type)
+{
+ PyObject *module = PyType_GetModule(type);
+ assert(module != NULL);
+ return RemoteDebugging_GetState(module);
+}
+
+static inline RemoteDebuggingState *
+RemoteDebugging_GetStateFromObject(PyObject *obj)
+{
+ RemoteUnwinderObject *unwinder = (RemoteUnwinderObject *)obj;
+ if (unwinder->cached_state == NULL) {
+ unwinder->cached_state = RemoteDebugging_GetStateFromType(Py_TYPE(obj));
+ }
+ return unwinder->cached_state;
+}
+
static inline int
RemoteDebugging_InitState(RemoteDebuggingState *st)
{
@@ -854,24 +955,14 @@ create_task_result(
char task_obj[SIZEOF_TASK_OBJ];
uintptr_t coro_addr;
- result = PyList_New(0);
- if (result == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create task result list");
- goto error;
- }
-
+ // Create call_stack first since it's the first tuple element
call_stack = PyList_New(0);
if (call_stack == NULL) {
set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create call stack list");
goto error;
}
- if (PyList_Append(result, call_stack)) {
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append call stack to task result");
- goto error;
- }
- Py_CLEAR(call_stack);
-
+ // Create task name/address for second tuple element
if (recurse_task) {
tn = parse_task_name(unwinder, task_address);
} else {
@@ -882,12 +973,6 @@ create_task_result(
goto error;
}
- if (PyList_Append(result, tn)) {
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task name to result");
- goto error;
- }
- Py_CLEAR(tn);
-
// Parse coroutine chain
if (_Py_RemoteDebug_PagedReadRemoteMemory(&unwinder->handle, task_address,
unwinder->async_debug_offsets.asyncio_task_object.size,
@@ -900,31 +985,29 @@ create_task_result(
coro_addr &= ~Py_TAG_BITS;
if ((void*)coro_addr != NULL) {
- call_stack = PyList_New(0);
- if (call_stack == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coro call stack list");
- goto error;
- }
-
if (parse_coro_chain(unwinder, coro_addr, call_stack) < 0) {
- Py_DECREF(call_stack);
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse coroutine chain");
goto error;
}
if (PyList_Reverse(call_stack)) {
- Py_DECREF(call_stack);
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to reverse call stack");
goto error;
}
+ }
- if (PyList_SetItem(result, 0, call_stack) < 0) {
- Py_DECREF(call_stack);
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to set call stack in result");
- goto error;
- }
+ // Create final CoroInfo result
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->CoroInfo_Type);
+ if (result == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create CoroInfo");
+ goto error;
}
+ // PyStructSequence_SetItem steals references, so we don't need to DECREF on success
+ PyStructSequence_SetItem(result, 0, call_stack); // This steals the reference
+ PyStructSequence_SetItem(result, 1, tn); // This steals the reference
+
return result;
error:
@@ -943,7 +1026,6 @@ parse_task(
) {
char is_task;
PyObject* result = NULL;
- PyObject* awaited_by = NULL;
int err;
err = read_char(
@@ -962,48 +1044,37 @@ parse_task(
goto error;
}
} else {
- result = PyList_New(0);
+ // Create an empty CoroInfo for non-task objects
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->CoroInfo_Type);
if (result == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty task result");
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty CoroInfo");
goto error;
}
- }
-
- if (PyList_Append(render_to, result)) {
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list");
- goto error;
- }
-
- if (recurse_task) {
- awaited_by = PyList_New(0);
- if (awaited_by == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by list");
+ PyObject *empty_list = PyList_New(0);
+ if (empty_list == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create empty list");
goto error;
}
-
- if (PyList_Append(result, awaited_by)) {
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by to result");
+ PyObject *task_name = PyLong_FromUnsignedLongLong(task_address);
+ if (task_name == NULL) {
+ Py_DECREF(empty_list);
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task name");
goto error;
}
- Py_DECREF(awaited_by);
+ PyStructSequence_SetItem(result, 0, empty_list); // This steals the reference
+ PyStructSequence_SetItem(result, 1, task_name); // This steals the reference
+ }
- /* awaited_by is borrowed from 'result' to simplify cleanup */
- if (parse_task_awaited_by(unwinder, task_address, awaited_by, 1) < 0) {
- // Clear the pointer so the cleanup doesn't try to decref it since
- // it's borrowed from 'result' and will be decrefed when result is
- // deleted.
- awaited_by = NULL;
- set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task awaited_by relationships");
- goto error;
- }
+ if (PyList_Append(render_to, result)) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append task result to render list");
+ goto error;
}
Py_DECREF(result);
-
return 0;
error:
Py_XDECREF(result);
- Py_XDECREF(awaited_by);
return -1;
}
@@ -1161,6 +1232,7 @@ process_single_task_node(
PyObject *current_awaited_by = NULL;
PyObject *task_id = NULL;
PyObject *result_item = NULL;
+ PyObject *coroutine_stack = NULL;
tn = parse_task_name(unwinder, task_addr);
if (tn == NULL) {
@@ -1174,25 +1246,40 @@ process_single_task_node(
goto error;
}
+ // Extract the coroutine stack for this task
+ coroutine_stack = PyList_New(0);
+ if (coroutine_stack == NULL) {
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create coroutine stack list in single task node");
+ goto error;
+ }
+
+ if (parse_task(unwinder, task_addr, coroutine_stack, 0) < 0) {
+ set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse task coroutine stack in single task node");
+ goto error;
+ }
+
task_id = PyLong_FromUnsignedLongLong(task_addr);
if (task_id == NULL) {
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to create task ID in single task node");
goto error;
}
- result_item = PyTuple_New(3);
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result_item = PyStructSequence_New(state->TaskInfo_Type);
if (result_item == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create result tuple in single task node");
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create TaskInfo in single task node");
goto error;
}
- PyTuple_SET_ITEM(result_item, 0, task_id); // steals ref
- PyTuple_SET_ITEM(result_item, 1, tn); // steals ref
- PyTuple_SET_ITEM(result_item, 2, current_awaited_by); // steals ref
+ PyStructSequence_SetItem(result_item, 0, task_id); // steals ref
+ PyStructSequence_SetItem(result_item, 1, tn); // steals ref
+ PyStructSequence_SetItem(result_item, 2, coroutine_stack); // steals ref
+ PyStructSequence_SetItem(result_item, 3, current_awaited_by); // steals ref
// References transferred to tuple
task_id = NULL;
tn = NULL;
+ coroutine_stack = NULL;
current_awaited_by = NULL;
if (PyList_Append(result, result_item)) {
@@ -1203,9 +1290,11 @@ process_single_task_node(
Py_DECREF(result_item);
// Get back current_awaited_by reference for parse_task_awaited_by
- current_awaited_by = PyTuple_GET_ITEM(result_item, 2);
+ current_awaited_by = PyStructSequence_GetItem(result_item, 3);
if (parse_task_awaited_by(unwinder, task_addr, current_awaited_by, 0) < 0) {
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to parse awaited_by in single task node");
+ // No cleanup needed here since all references were transferred to result_item
+ // and result_item was already added to result list and decreffed
return -1;
}
@@ -1216,6 +1305,7 @@ error:
Py_XDECREF(current_awaited_by);
Py_XDECREF(task_id);
Py_XDECREF(result_item);
+ Py_XDECREF(coroutine_stack);
return -1;
}
@@ -1554,17 +1644,18 @@ done_tlbc:
goto error;
}
- tuple = PyTuple_New(3);
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ tuple = PyStructSequence_New(state->FrameInfo_Type);
if (!tuple) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create result tuple for code object");
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create FrameInfo for code object");
goto error;
}
Py_INCREF(meta->func_name);
Py_INCREF(meta->file_name);
- PyTuple_SET_ITEM(tuple, 0, meta->file_name);
- PyTuple_SET_ITEM(tuple, 1, lineno);
- PyTuple_SET_ITEM(tuple, 2, meta->func_name);
+ PyStructSequence_SetItem(tuple, 0, meta->file_name);
+ PyStructSequence_SetItem(tuple, 1, lineno);
+ PyStructSequence_SetItem(tuple, 2, meta->func_name);
*result = tuple;
return 0;
@@ -2212,23 +2303,24 @@ append_awaited_by(
return -1;
}
- PyObject *result_item = PyTuple_New(2);
- if (result_item == NULL) {
+ PyObject* awaited_by_for_thread = PyList_New(0);
+ if (awaited_by_for_thread == NULL) {
Py_DECREF(tid_py);
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by result tuple");
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list");
return -1;
}
- PyObject* awaited_by_for_thread = PyList_New(0);
- if (awaited_by_for_thread == NULL) {
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ PyObject *result_item = PyStructSequence_New(state->AwaitedInfo_Type);
+ if (result_item == NULL) {
Py_DECREF(tid_py);
- Py_DECREF(result_item);
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create awaited_by thread list");
+ Py_DECREF(awaited_by_for_thread);
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create AwaitedInfo");
return -1;
}
- PyTuple_SET_ITEM(result_item, 0, tid_py); // steals ref
- PyTuple_SET_ITEM(result_item, 1, awaited_by_for_thread); // steals ref
+ PyStructSequence_SetItem(result_item, 0, tid_py); // steals ref
+ PyStructSequence_SetItem(result_item, 1, awaited_by_for_thread); // steals ref
if (PyList_Append(result, result_item)) {
Py_DECREF(result_item);
set_exception_cause(unwinder, PyExc_RuntimeError, "Failed to append awaited_by result item");
@@ -2352,14 +2444,15 @@ unwind_stack_for_thread(
goto error;
}
- result = PyTuple_New(2);
+ RemoteDebuggingState *state = RemoteDebugging_GetStateFromObject((PyObject*)unwinder);
+ result = PyStructSequence_New(state->ThreadInfo_Type);
if (result == NULL) {
- set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create thread unwind result tuple");
+ set_exception_cause(unwinder, PyExc_MemoryError, "Failed to create ThreadInfo");
goto error;
}
- PyTuple_SET_ITEM(result, 0, thread_id); // Steals reference
- PyTuple_SET_ITEM(result, 1, frame_info); // Steals reference
+ PyStructSequence_SetItem(result, 0, thread_id); // Steals reference
+ PyStructSequence_SetItem(result, 1, frame_info); // Steals reference
cleanup_stack_chunks(&chunks);
return result;
@@ -2414,6 +2507,7 @@ _remote_debugging_RemoteUnwinder___init___impl(RemoteUnwinderObject *self,
/*[clinic end generated code: output=3982f2a7eba49334 input=48a762566b828e91]*/
{
self->debug = debug;
+ self->cached_state = NULL;
if (_Py_RemoteDebug_InitProcHandle(&self->handle, pid) < 0) {
set_exception_cause(self, PyExc_RuntimeError, "Failed to initialize process handle");
return -1;
@@ -2860,6 +2954,47 @@ _remote_debugging_exec(PyObject *m)
if (PyModule_AddType(m, st->RemoteDebugging_Type) < 0) {
return -1;
}
+
+ // Initialize structseq types
+ st->TaskInfo_Type = PyStructSequence_NewType(&TaskInfo_desc);
+ if (st->TaskInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->TaskInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->FrameInfo_Type = PyStructSequence_NewType(&FrameInfo_desc);
+ if (st->FrameInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->FrameInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->CoroInfo_Type = PyStructSequence_NewType(&CoroInfo_desc);
+ if (st->CoroInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->CoroInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->ThreadInfo_Type = PyStructSequence_NewType(&ThreadInfo_desc);
+ if (st->ThreadInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->ThreadInfo_Type) < 0) {
+ return -1;
+ }
+
+ st->AwaitedInfo_Type = PyStructSequence_NewType(&AwaitedInfo_desc);
+ if (st->AwaitedInfo_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddType(m, st->AwaitedInfo_Type) < 0) {
+ return -1;
+ }
#ifdef Py_GIL_DISABLED
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
#endif
@@ -2878,6 +3013,11 @@ remote_debugging_traverse(PyObject *mod, visitproc visit, void *arg)
{
RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
Py_VISIT(state->RemoteDebugging_Type);
+ Py_VISIT(state->TaskInfo_Type);
+ Py_VISIT(state->FrameInfo_Type);
+ Py_VISIT(state->CoroInfo_Type);
+ Py_VISIT(state->ThreadInfo_Type);
+ Py_VISIT(state->AwaitedInfo_Type);
return 0;
}
@@ -2886,6 +3026,11 @@ remote_debugging_clear(PyObject *mod)
{
RemoteDebuggingState *state = RemoteDebugging_GetState(mod);
Py_CLEAR(state->RemoteDebugging_Type);
+ Py_CLEAR(state->TaskInfo_Type);
+ Py_CLEAR(state->FrameInfo_Type);
+ Py_CLEAR(state->CoroInfo_Type);
+ Py_CLEAR(state->ThreadInfo_Type);
+ Py_CLEAR(state->AwaitedInfo_Type);
return 0;
}
diff --git a/Modules/_sqlite/module.c b/Modules/_sqlite/module.c
index 909ddd1f990..5464fd1227a 100644
--- a/Modules/_sqlite/module.c
+++ b/Modules/_sqlite/module.c
@@ -32,6 +32,7 @@
#include "microprotocols.h"
#include "row.h"
#include "blob.h"
+#include "util.h"
#if SQLITE_VERSION_NUMBER < 3015002
#error "SQLite 3.15.2 or higher required"
@@ -405,6 +406,40 @@ pysqlite_error_name(int rc)
}
static int
+add_keyword_tuple(PyObject *module)
+{
+#if SQLITE_VERSION_NUMBER >= 3024000
+ int count = sqlite3_keyword_count();
+ PyObject *keywords = PyTuple_New(count);
+ if (keywords == NULL) {
+ return -1;
+ }
+ for (int i = 0; i < count; i++) {
+ const char *keyword;
+ int size;
+ int result = sqlite3_keyword_name(i, &keyword, &size);
+ if (result != SQLITE_OK) {
+ pysqlite_state *state = pysqlite_get_state(module);
+ set_error_from_code(state, result);
+ goto error;
+ }
+ PyObject *kwd = PyUnicode_FromStringAndSize(keyword, size);
+ if (!kwd) {
+ goto error;
+ }
+ PyTuple_SET_ITEM(keywords, i, kwd);
+ }
+ return PyModule_Add(module, "SQLITE_KEYWORDS", keywords);
+
+error:
+ Py_DECREF(keywords);
+ return -1;
+#else
+ return 0;
+#endif
+}
+
+static int
add_integer_constants(PyObject *module) {
#define ADD_INT(ival) \
do { \
@@ -702,6 +737,10 @@ module_exec(PyObject *module)
goto error;
}
+ if (add_keyword_tuple(module) < 0) {
+ goto error;
+ }
+
if (PyModule_AddStringConstant(module, "sqlite_version", sqlite3_libversion())) {
goto error;
}
diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c
index 845c218e679..804cb4e4d1c 100644
--- a/Modules/_testinternalcapi.c
+++ b/Modules/_testinternalcapi.c
@@ -1788,9 +1788,9 @@ finally:
/* To run some code in a sub-interpreter.
-Generally you can use test.support.interpreters,
+Generally you can use the interpreters module,
but we keep this helper as a distinct implementation.
-That's especially important for testing test.support.interpreters.
+That's especially important for testing the interpreters module.
*/
static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
diff --git a/Modules/clinic/_lsprof.c.h b/Modules/clinic/_lsprof.c.h
index 2918a6bc7ab..c426cd6fe02 100644
--- a/Modules/clinic/_lsprof.c.h
+++ b/Modules/clinic/_lsprof.c.h
@@ -82,6 +82,39 @@ exit:
return return_value;
}
+PyDoc_STRVAR(_lsprof_Profiler__pythrow_callback__doc__,
+"_pythrow_callback($self, code, instruction_offset, exception, /)\n"
+"--\n"
+"\n");
+
+#define _LSPROF_PROFILER__PYTHROW_CALLBACK_METHODDEF \
+ {"_pythrow_callback", _PyCFunction_CAST(_lsprof_Profiler__pythrow_callback), METH_FASTCALL, _lsprof_Profiler__pythrow_callback__doc__},
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback_impl(ProfilerObject *self, PyObject *code,
+ PyObject *instruction_offset,
+ PyObject *exception);
+
+static PyObject *
+_lsprof_Profiler__pythrow_callback(PyObject *self, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *code;
+ PyObject *instruction_offset;
+ PyObject *exception;
+
+ if (!_PyArg_CheckPositional("_pythrow_callback", nargs, 3, 3)) {
+ goto exit;
+ }
+ code = args[0];
+ instruction_offset = args[1];
+ exception = args[2];
+ return_value = _lsprof_Profiler__pythrow_callback_impl((ProfilerObject *)self, code, instruction_offset, exception);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(_lsprof_Profiler__pyreturn_callback__doc__,
"_pyreturn_callback($self, code, instruction_offset, retval, /)\n"
"--\n"
@@ -411,4 +444,4 @@ skip_optional_pos:
exit:
return return_value;
}
-/*[clinic end generated code: output=fe231309776df7a7 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=9e46985561166c37 input=a9049054013a1b77]*/