Skip to content

Commit d4426e8

Browse files
gh-76785: Move _Py_excinfo Functions Out of the Internal C-API (gh-111715)
I added _Py_excinfo to the internal API (and added its functions in Python/errors.c) in gh-111530 (9322ce9). Since then I've had a nagging sense that I should have added the type and functions in its own PR. While I do plan on using _Py_excinfo outside crossinterp.c very soon (see gh-111572/gh-111573), I'd still feel more comfortable if the _Py_excinfo stuff went in as its own PR. Hence, here we are. (FWIW, I may combine that with gh-111572, which I may, in turn, combine with gh-111573. We'll see.)
1 parent 836e0a7 commit d4426e8

File tree

4 files changed

+134
-199
lines changed

4 files changed

+134
-199
lines changed

Include/internal/pycore_crossinterp.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,17 @@ extern void _PyXI_Fini(PyInterpreterState *interp);
164164
/* short-term data sharing */
165165
/***************************/
166166

167+
// Ultimately we'd like to preserve enough information about the
168+
// exception and traceback that we could re-constitute (or at least
169+
// simulate, a la traceback.TracebackException), and even chain, a copy
170+
// of the exception in the calling interpreter.
171+
172+
typedef struct _excinfo {
173+
const char *type;
174+
const char *msg;
175+
} _Py_excinfo;
176+
177+
167178
typedef enum error_code {
168179
_PyXI_ERR_NO_ERROR = 0,
169180
_PyXI_ERR_UNCAUGHT_EXCEPTION = -1,

Include/internal/pycore_pyerrors.h

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -68,30 +68,6 @@ extern PyStatus _PyErr_InitTypes(PyInterpreterState *);
6868
extern void _PyErr_FiniTypes(PyInterpreterState *);
6969

7070

71-
/* exception snapshots */
72-
73-
// Ultimately we'd like to preserve enough information about the
74-
// exception and traceback that we could re-constitute (or at least
75-
// simulate, a la traceback.TracebackException), and even chain, a copy
76-
// of the exception in the calling interpreter.
77-
78-
typedef struct _excinfo {
79-
const char *type;
80-
const char *msg;
81-
} _Py_excinfo;
82-
83-
extern void _Py_excinfo_Clear(_Py_excinfo *info);
84-
extern int _Py_excinfo_Copy(_Py_excinfo *dest, _Py_excinfo *src);
85-
extern const char * _Py_excinfo_InitFromException(
86-
_Py_excinfo *info,
87-
PyObject *exc);
88-
extern void _Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype);
89-
extern const char * _Py_excinfo_AsUTF8(
90-
_Py_excinfo *info,
91-
char *buf,
92-
size_t bufsize);
93-
94-
9571
/* other API */
9672

9773
static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)

Python/crossinterp.c

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,17 @@ _xidregistry_fini(struct _xidregistry *registry)
800800
/* convenience utilities */
801801
/*************************/
802802

803+
static const char *
804+
_copy_raw_string(const char *str)
805+
{
806+
char *copied = PyMem_RawMalloc(strlen(str)+1);
807+
if (copied == NULL) {
808+
return NULL;
809+
}
810+
strcpy(copied, str);
811+
return copied;
812+
}
813+
803814
static const char *
804815
_copy_string_obj_raw(PyObject *strobj)
805816
{
@@ -835,6 +846,118 @@ _release_xid_data(_PyCrossInterpreterData *data, int rawfree)
835846
}
836847

837848

849+
/* exception snapshots */
850+
851+
static int
852+
_exc_type_name_as_utf8(PyObject *exc, const char **p_typename)
853+
{
854+
// XXX Use PyObject_GetAttrString(Py_TYPE(exc), '__name__')?
855+
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
856+
if (nameobj == NULL) {
857+
assert(PyErr_Occurred());
858+
*p_typename = "unable to format exception type name";
859+
return -1;
860+
}
861+
const char *name = PyUnicode_AsUTF8(nameobj);
862+
if (name == NULL) {
863+
assert(PyErr_Occurred());
864+
Py_DECREF(nameobj);
865+
*p_typename = "unable to encode exception type name";
866+
return -1;
867+
}
868+
name = _copy_raw_string(name);
869+
Py_DECREF(nameobj);
870+
if (name == NULL) {
871+
*p_typename = "out of memory copying exception type name";
872+
return -1;
873+
}
874+
*p_typename = name;
875+
return 0;
876+
}
877+
878+
static int
879+
_exc_msg_as_utf8(PyObject *exc, const char **p_msg)
880+
{
881+
PyObject *msgobj = PyObject_Str(exc);
882+
if (msgobj == NULL) {
883+
assert(PyErr_Occurred());
884+
*p_msg = "unable to format exception message";
885+
return -1;
886+
}
887+
const char *msg = PyUnicode_AsUTF8(msgobj);
888+
if (msg == NULL) {
889+
assert(PyErr_Occurred());
890+
Py_DECREF(msgobj);
891+
*p_msg = "unable to encode exception message";
892+
return -1;
893+
}
894+
msg = _copy_raw_string(msg);
895+
Py_DECREF(msgobj);
896+
if (msg == NULL) {
897+
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
898+
*p_msg = "out of memory copying exception message";
899+
return -1;
900+
}
901+
*p_msg = msg;
902+
return 0;
903+
}
904+
905+
static void
906+
_Py_excinfo_Clear(_Py_excinfo *info)
907+
{
908+
if (info->type != NULL) {
909+
PyMem_RawFree((void *)info->type);
910+
}
911+
if (info->msg != NULL) {
912+
PyMem_RawFree((void *)info->msg);
913+
}
914+
*info = (_Py_excinfo){ NULL };
915+
}
916+
917+
static const char *
918+
_Py_excinfo_InitFromException(_Py_excinfo *info, PyObject *exc)
919+
{
920+
assert(exc != NULL);
921+
922+
// Extract the exception type name.
923+
const char *typename = NULL;
924+
if (_exc_type_name_as_utf8(exc, &typename) < 0) {
925+
assert(typename != NULL);
926+
return typename;
927+
}
928+
929+
// Extract the exception message.
930+
const char *msg = NULL;
931+
if (_exc_msg_as_utf8(exc, &msg) < 0) {
932+
assert(msg != NULL);
933+
return msg;
934+
}
935+
936+
info->type = typename;
937+
info->msg = msg;
938+
return NULL;
939+
}
940+
941+
static void
942+
_Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype)
943+
{
944+
if (info->type != NULL) {
945+
if (info->msg != NULL) {
946+
PyErr_Format(exctype, "%s: %s", info->type, info->msg);
947+
}
948+
else {
949+
PyErr_SetString(exctype, info->type);
950+
}
951+
}
952+
else if (info->msg != NULL) {
953+
PyErr_SetString(exctype, info->msg);
954+
}
955+
else {
956+
PyErr_SetNone(exctype);
957+
}
958+
}
959+
960+
838961
/***************************/
839962
/* short-term data sharing */
840963
/***************************/

Python/errors.c

Lines changed: 0 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -1934,178 +1934,3 @@ PyErr_ProgramTextObject(PyObject *filename, int lineno)
19341934
{
19351935
return _PyErr_ProgramDecodedTextObject(filename, lineno, NULL);
19361936
}
1937-
1938-
1939-
/***********************/
1940-
/* exception snapshots */
1941-
/***********************/
1942-
1943-
static const char *
1944-
_copy_raw_string(const char *str)
1945-
{
1946-
char *copied = PyMem_RawMalloc(strlen(str)+1);
1947-
if (copied == NULL) {
1948-
return NULL;
1949-
}
1950-
strcpy(copied, str);
1951-
return copied;
1952-
}
1953-
1954-
static int
1955-
_exc_type_name_as_utf8(PyObject *exc, const char **p_typename)
1956-
{
1957-
// XXX Use PyObject_GetAttrString(Py_TYPE(exc), '__name__')?
1958-
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
1959-
if (nameobj == NULL) {
1960-
assert(PyErr_Occurred());
1961-
*p_typename = "unable to format exception type name";
1962-
return -1;
1963-
}
1964-
const char *name = PyUnicode_AsUTF8(nameobj);
1965-
if (name == NULL) {
1966-
assert(PyErr_Occurred());
1967-
Py_DECREF(nameobj);
1968-
*p_typename = "unable to encode exception type name";
1969-
return -1;
1970-
}
1971-
name = _copy_raw_string(name);
1972-
Py_DECREF(nameobj);
1973-
if (name == NULL) {
1974-
*p_typename = "out of memory copying exception type name";
1975-
return -1;
1976-
}
1977-
*p_typename = name;
1978-
return 0;
1979-
}
1980-
1981-
static int
1982-
_exc_msg_as_utf8(PyObject *exc, const char **p_msg)
1983-
{
1984-
PyObject *msgobj = PyObject_Str(exc);
1985-
if (msgobj == NULL) {
1986-
assert(PyErr_Occurred());
1987-
*p_msg = "unable to format exception message";
1988-
return -1;
1989-
}
1990-
const char *msg = PyUnicode_AsUTF8(msgobj);
1991-
if (msg == NULL) {
1992-
assert(PyErr_Occurred());
1993-
Py_DECREF(msgobj);
1994-
*p_msg = "unable to encode exception message";
1995-
return -1;
1996-
}
1997-
msg = _copy_raw_string(msg);
1998-
Py_DECREF(msgobj);
1999-
if (msg == NULL) {
2000-
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
2001-
*p_msg = "out of memory copying exception message";
2002-
return -1;
2003-
}
2004-
*p_msg = msg;
2005-
return 0;
2006-
}
2007-
2008-
void
2009-
_Py_excinfo_Clear(_Py_excinfo *info)
2010-
{
2011-
if (info->type != NULL) {
2012-
PyMem_RawFree((void *)info->type);
2013-
}
2014-
if (info->msg != NULL) {
2015-
PyMem_RawFree((void *)info->msg);
2016-
}
2017-
*info = (_Py_excinfo){ NULL };
2018-
}
2019-
2020-
int
2021-
_Py_excinfo_Copy(_Py_excinfo *dest, _Py_excinfo *src)
2022-
{
2023-
// XXX Clear dest first?
2024-
2025-
if (src->type == NULL) {
2026-
dest->type = NULL;
2027-
}
2028-
else {
2029-
dest->type = _copy_raw_string(src->type);
2030-
if (dest->type == NULL) {
2031-
return -1;
2032-
}
2033-
}
2034-
2035-
if (src->msg == NULL) {
2036-
dest->msg = NULL;
2037-
}
2038-
else {
2039-
dest->msg = _copy_raw_string(src->msg);
2040-
if (dest->msg == NULL) {
2041-
return -1;
2042-
}
2043-
}
2044-
2045-
return 0;
2046-
}
2047-
2048-
const char *
2049-
_Py_excinfo_InitFromException(_Py_excinfo *info, PyObject *exc)
2050-
{
2051-
assert(exc != NULL);
2052-
2053-
// Extract the exception type name.
2054-
const char *typename = NULL;
2055-
if (_exc_type_name_as_utf8(exc, &typename) < 0) {
2056-
assert(typename != NULL);
2057-
return typename;
2058-
}
2059-
2060-
// Extract the exception message.
2061-
const char *msg = NULL;
2062-
if (_exc_msg_as_utf8(exc, &msg) < 0) {
2063-
assert(msg != NULL);
2064-
return msg;
2065-
}
2066-
2067-
info->type = typename;
2068-
info->msg = msg;
2069-
return NULL;
2070-
}
2071-
2072-
void
2073-
_Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype)
2074-
{
2075-
if (info->type != NULL) {
2076-
if (info->msg != NULL) {
2077-
PyErr_Format(exctype, "%s: %s", info->type, info->msg);
2078-
}
2079-
else {
2080-
PyErr_SetString(exctype, info->type);
2081-
}
2082-
}
2083-
else if (info->msg != NULL) {
2084-
PyErr_SetString(exctype, info->msg);
2085-
}
2086-
else {
2087-
PyErr_SetNone(exctype);
2088-
}
2089-
}
2090-
2091-
const char *
2092-
_Py_excinfo_AsUTF8(_Py_excinfo *info, char *buf, size_t bufsize)
2093-
{
2094-
// XXX Dynamically allocate if no buf provided?
2095-
assert(buf != NULL);
2096-
if (info->type != NULL) {
2097-
if (info->msg != NULL) {
2098-
snprintf(buf, bufsize, "%s: %s", info->type, info->msg);
2099-
return buf;
2100-
}
2101-
else {
2102-
return info->type;
2103-
}
2104-
}
2105-
else if (info->msg != NULL) {
2106-
return info->msg;
2107-
}
2108-
else {
2109-
return NULL;
2110-
}
2111-
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy