Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-76785: Move _Py_excinfo Functions Out of the Internal C-API #111715

Merged
merged 2 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Include/internal/pycore_crossinterp.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,17 @@ extern void _PyXI_Fini(PyInterpreterState *interp);
/* short-term data sharing */
/***************************/

// Ultimately we'd like to preserve enough information about the
// exception and traceback that we could re-constitute (or at least
// simulate, a la traceback.TracebackException), and even chain, a copy
// of the exception in the calling interpreter.

typedef struct _excinfo {
const char *type;
const char *msg;
} _Py_excinfo;


typedef enum error_code {
_PyXI_ERR_NO_ERROR = 0,
_PyXI_ERR_UNCAUGHT_EXCEPTION = -1,
Expand Down
24 changes: 0 additions & 24 deletions Include/internal/pycore_pyerrors.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,30 +68,6 @@ extern PyStatus _PyErr_InitTypes(PyInterpreterState *);
extern void _PyErr_FiniTypes(PyInterpreterState *);


/* exception snapshots */

// Ultimately we'd like to preserve enough information about the
// exception and traceback that we could re-constitute (or at least
// simulate, a la traceback.TracebackException), and even chain, a copy
// of the exception in the calling interpreter.

typedef struct _excinfo {
const char *type;
const char *msg;
} _Py_excinfo;

extern void _Py_excinfo_Clear(_Py_excinfo *info);
extern int _Py_excinfo_Copy(_Py_excinfo *dest, _Py_excinfo *src);
extern const char * _Py_excinfo_InitFromException(
_Py_excinfo *info,
PyObject *exc);
extern void _Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype);
extern const char * _Py_excinfo_AsUTF8(
_Py_excinfo *info,
char *buf,
size_t bufsize);


/* other API */

static inline PyObject* _PyErr_Occurred(PyThreadState *tstate)
Expand Down
123 changes: 123 additions & 0 deletions Python/crossinterp.c
Original file line number Diff line number Diff line change
Expand Up @@ -800,6 +800,17 @@ _xidregistry_fini(struct _xidregistry *registry)
/* convenience utilities */
/*************************/

static const char *
_copy_raw_string(const char *str)
{
char *copied = PyMem_RawMalloc(strlen(str)+1);
if (copied == NULL) {
return NULL;
}
strcpy(copied, str);
return copied;
}

static const char *
_copy_string_obj_raw(PyObject *strobj)
{
Expand Down Expand Up @@ -835,6 +846,118 @@ _release_xid_data(_PyCrossInterpreterData *data, int rawfree)
}


/* exception snapshots */

static int
_exc_type_name_as_utf8(PyObject *exc, const char **p_typename)
{
// XXX Use PyObject_GetAttrString(Py_TYPE(exc), '__name__')?
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
if (nameobj == NULL) {
assert(PyErr_Occurred());
*p_typename = "unable to format exception type name";
return -1;
}
const char *name = PyUnicode_AsUTF8(nameobj);
if (name == NULL) {
assert(PyErr_Occurred());
Py_DECREF(nameobj);
*p_typename = "unable to encode exception type name";
return -1;
}
name = _copy_raw_string(name);
Py_DECREF(nameobj);
if (name == NULL) {
*p_typename = "out of memory copying exception type name";
return -1;
}
*p_typename = name;
return 0;
}

static int
_exc_msg_as_utf8(PyObject *exc, const char **p_msg)
{
PyObject *msgobj = PyObject_Str(exc);
if (msgobj == NULL) {
assert(PyErr_Occurred());
*p_msg = "unable to format exception message";
return -1;
}
const char *msg = PyUnicode_AsUTF8(msgobj);
if (msg == NULL) {
assert(PyErr_Occurred());
Py_DECREF(msgobj);
*p_msg = "unable to encode exception message";
return -1;
}
msg = _copy_raw_string(msg);
Py_DECREF(msgobj);
if (msg == NULL) {
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
*p_msg = "out of memory copying exception message";
return -1;
}
*p_msg = msg;
return 0;
}

static void
_Py_excinfo_Clear(_Py_excinfo *info)
{
if (info->type != NULL) {
PyMem_RawFree((void *)info->type);
}
if (info->msg != NULL) {
PyMem_RawFree((void *)info->msg);
}
*info = (_Py_excinfo){ NULL };
}

static const char *
_Py_excinfo_InitFromException(_Py_excinfo *info, PyObject *exc)
{
assert(exc != NULL);

// Extract the exception type name.
const char *typename = NULL;
if (_exc_type_name_as_utf8(exc, &typename) < 0) {
assert(typename != NULL);
return typename;
}

// Extract the exception message.
const char *msg = NULL;
if (_exc_msg_as_utf8(exc, &msg) < 0) {
assert(msg != NULL);
return msg;
}

info->type = typename;
info->msg = msg;
return NULL;
}

static void
_Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype)
{
if (info->type != NULL) {
if (info->msg != NULL) {
PyErr_Format(exctype, "%s: %s", info->type, info->msg);
}
else {
PyErr_SetString(exctype, info->type);
}
}
else if (info->msg != NULL) {
PyErr_SetString(exctype, info->msg);
}
else {
PyErr_SetNone(exctype);
}
}


/***************************/
/* short-term data sharing */
/***************************/
Expand Down
175 changes: 0 additions & 175 deletions Python/errors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1934,178 +1934,3 @@ PyErr_ProgramTextObject(PyObject *filename, int lineno)
{
return _PyErr_ProgramDecodedTextObject(filename, lineno, NULL);
}


/***********************/
/* exception snapshots */
/***********************/

static const char *
_copy_raw_string(const char *str)
{
char *copied = PyMem_RawMalloc(strlen(str)+1);
if (copied == NULL) {
return NULL;
}
strcpy(copied, str);
return copied;
}

static int
_exc_type_name_as_utf8(PyObject *exc, const char **p_typename)
{
// XXX Use PyObject_GetAttrString(Py_TYPE(exc), '__name__')?
PyObject *nameobj = PyUnicode_FromString(Py_TYPE(exc)->tp_name);
if (nameobj == NULL) {
assert(PyErr_Occurred());
*p_typename = "unable to format exception type name";
return -1;
}
const char *name = PyUnicode_AsUTF8(nameobj);
if (name == NULL) {
assert(PyErr_Occurred());
Py_DECREF(nameobj);
*p_typename = "unable to encode exception type name";
return -1;
}
name = _copy_raw_string(name);
Py_DECREF(nameobj);
if (name == NULL) {
*p_typename = "out of memory copying exception type name";
return -1;
}
*p_typename = name;
return 0;
}

static int
_exc_msg_as_utf8(PyObject *exc, const char **p_msg)
{
PyObject *msgobj = PyObject_Str(exc);
if (msgobj == NULL) {
assert(PyErr_Occurred());
*p_msg = "unable to format exception message";
return -1;
}
const char *msg = PyUnicode_AsUTF8(msgobj);
if (msg == NULL) {
assert(PyErr_Occurred());
Py_DECREF(msgobj);
*p_msg = "unable to encode exception message";
return -1;
}
msg = _copy_raw_string(msg);
Py_DECREF(msgobj);
if (msg == NULL) {
assert(PyErr_ExceptionMatches(PyExc_MemoryError));
*p_msg = "out of memory copying exception message";
return -1;
}
*p_msg = msg;
return 0;
}

void
_Py_excinfo_Clear(_Py_excinfo *info)
{
if (info->type != NULL) {
PyMem_RawFree((void *)info->type);
}
if (info->msg != NULL) {
PyMem_RawFree((void *)info->msg);
}
*info = (_Py_excinfo){ NULL };
}

int
_Py_excinfo_Copy(_Py_excinfo *dest, _Py_excinfo *src)
{
// XXX Clear dest first?

if (src->type == NULL) {
dest->type = NULL;
}
else {
dest->type = _copy_raw_string(src->type);
if (dest->type == NULL) {
return -1;
}
}

if (src->msg == NULL) {
dest->msg = NULL;
}
else {
dest->msg = _copy_raw_string(src->msg);
if (dest->msg == NULL) {
return -1;
}
}

return 0;
}

const char *
_Py_excinfo_InitFromException(_Py_excinfo *info, PyObject *exc)
{
assert(exc != NULL);

// Extract the exception type name.
const char *typename = NULL;
if (_exc_type_name_as_utf8(exc, &typename) < 0) {
assert(typename != NULL);
return typename;
}

// Extract the exception message.
const char *msg = NULL;
if (_exc_msg_as_utf8(exc, &msg) < 0) {
assert(msg != NULL);
return msg;
}

info->type = typename;
info->msg = msg;
return NULL;
}

void
_Py_excinfo_Apply(_Py_excinfo *info, PyObject *exctype)
{
if (info->type != NULL) {
if (info->msg != NULL) {
PyErr_Format(exctype, "%s: %s", info->type, info->msg);
}
else {
PyErr_SetString(exctype, info->type);
}
}
else if (info->msg != NULL) {
PyErr_SetString(exctype, info->msg);
}
else {
PyErr_SetNone(exctype);
}
}

const char *
_Py_excinfo_AsUTF8(_Py_excinfo *info, char *buf, size_t bufsize)
{
// XXX Dynamically allocate if no buf provided?
assert(buf != NULL);
if (info->type != NULL) {
if (info->msg != NULL) {
snprintf(buf, bufsize, "%s: %s", info->type, info->msg);
return buf;
}
else {
return info->type;
}
}
else if (info->msg != NULL) {
return info->msg;
}
else {
return NULL;
}
}
Loading