mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			316 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			316 lines
		
	
	
	
		
			8.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#include "parts.h"
 | 
						|
 | 
						|
static PyObject *
 | 
						|
err_set_raised(PyObject *self, PyObject *exc)
 | 
						|
{
 | 
						|
    Py_INCREF(exc);
 | 
						|
    PyErr_SetRaisedException(exc);
 | 
						|
    assert(PyErr_Occurred());
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
err_restore(PyObject *self, PyObject *args) {
 | 
						|
    PyObject *type = NULL, *value = NULL, *traceback = NULL;
 | 
						|
    switch(PyTuple_Size(args)) {
 | 
						|
        case 3:
 | 
						|
            traceback = PyTuple_GetItem(args, 2);
 | 
						|
            Py_INCREF(traceback);
 | 
						|
            /* fall through */
 | 
						|
        case 2:
 | 
						|
            value = PyTuple_GetItem(args, 1);
 | 
						|
            Py_INCREF(value);
 | 
						|
            /* fall through */
 | 
						|
        case 1:
 | 
						|
            type = PyTuple_GetItem(args, 0);
 | 
						|
            Py_INCREF(type);
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            PyErr_SetString(PyExc_TypeError,
 | 
						|
                        "wrong number of arguments");
 | 
						|
            return NULL;
 | 
						|
    }
 | 
						|
    PyErr_Restore(type, value, traceback);
 | 
						|
    assert(PyErr_Occurred());
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* To test the format of exceptions as printed out. */
 | 
						|
static PyObject *
 | 
						|
exception_print(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *exc;
 | 
						|
    int legacy = 0;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "O|i:exception_print", &exc, &legacy)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (legacy) {
 | 
						|
        PyObject *tb = NULL;
 | 
						|
        if (PyExceptionInstance_Check(exc)) {
 | 
						|
            tb = PyException_GetTraceback(exc);
 | 
						|
        }
 | 
						|
        PyErr_Display((PyObject *) Py_TYPE(exc), exc, tb);
 | 
						|
        Py_XDECREF(tb);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        PyErr_DisplayException(exc);
 | 
						|
    }
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
/* Test PyErr_NewExceptionWithDoc (also exercise PyErr_NewException).
 | 
						|
   Run via Lib/test/test_exceptions.py */
 | 
						|
static PyObject *
 | 
						|
make_exception_with_doc(PyObject *self, PyObject *args, PyObject *kwargs)
 | 
						|
{
 | 
						|
    const char *name;
 | 
						|
    const char *doc = NULL;
 | 
						|
    PyObject *base = NULL;
 | 
						|
    PyObject *dict = NULL;
 | 
						|
 | 
						|
    static char *kwlist[] = {"name", "doc", "base", "dict", NULL};
 | 
						|
 | 
						|
    if (!PyArg_ParseTupleAndKeywords(args, kwargs,
 | 
						|
                                     "s|sOO:make_exception_with_doc", kwlist,
 | 
						|
                                     &name, &doc, &base, &dict))
 | 
						|
    {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    return PyErr_NewExceptionWithDoc(name, doc, base, dict);
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
exc_set_object(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *exc;
 | 
						|
    PyObject *obj;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    PyErr_SetObject(exc, obj);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
exc_set_object_fetch(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *exc;
 | 
						|
    PyObject *obj;
 | 
						|
    PyObject *type;
 | 
						|
    PyObject *value;
 | 
						|
    PyObject *tb;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "OO:exc_set_object", &exc, &obj)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    PyErr_SetObject(exc, obj);
 | 
						|
    PyErr_Fetch(&type, &value, &tb);
 | 
						|
    Py_XDECREF(type);
 | 
						|
    Py_XDECREF(tb);
 | 
						|
    return value;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
raise_exception(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *exc;
 | 
						|
    int num_args;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "Oi:raise_exception", &exc, &num_args)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    PyObject *exc_args = PyTuple_New(num_args);
 | 
						|
    if (exc_args == NULL) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    for (int i = 0; i < num_args; ++i) {
 | 
						|
        PyObject *v = PyLong_FromLong(i);
 | 
						|
        if (v == NULL) {
 | 
						|
            Py_DECREF(exc_args);
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
        PyTuple_SET_ITEM(exc_args, i, v);
 | 
						|
    }
 | 
						|
    PyErr_SetObject(exc, exc_args);
 | 
						|
    Py_DECREF(exc_args);
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
 | 
						|
/* reliably raise a MemoryError */
 | 
						|
static PyObject *
 | 
						|
raise_memoryerror(PyObject *self, PyObject *Py_UNUSED(ignored))
 | 
						|
{
 | 
						|
    return PyErr_NoMemory();
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
test_fatal_error(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    char *message;
 | 
						|
    int release_gil = 0;
 | 
						|
    if (!PyArg_ParseTuple(args, "y|i:fatal_error", &message, &release_gil)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    if (release_gil) {
 | 
						|
        Py_BEGIN_ALLOW_THREADS
 | 
						|
        Py_FatalError(message);
 | 
						|
        Py_END_ALLOW_THREADS
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        Py_FatalError(message);
 | 
						|
    }
 | 
						|
    // Py_FatalError() does not return, but exits the process.
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
test_set_exc_info(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *new_type, *new_value, *new_tb;
 | 
						|
    PyObject *type, *value, *tb;
 | 
						|
    if (!PyArg_ParseTuple(args, "OOO:test_set_exc_info",
 | 
						|
                          &new_type, &new_value, &new_tb))
 | 
						|
    {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    PyErr_GetExcInfo(&type, &value, &tb);
 | 
						|
 | 
						|
    Py_INCREF(new_type);
 | 
						|
    Py_INCREF(new_value);
 | 
						|
    Py_INCREF(new_tb);
 | 
						|
    PyErr_SetExcInfo(new_type, new_value, new_tb);
 | 
						|
 | 
						|
    PyObject *orig_exc = PyTuple_Pack(3,
 | 
						|
            type  ? type  : Py_None,
 | 
						|
            value ? value : Py_None,
 | 
						|
            tb    ? tb    : Py_None);
 | 
						|
    Py_XDECREF(type);
 | 
						|
    Py_XDECREF(value);
 | 
						|
    Py_XDECREF(tb);
 | 
						|
    return orig_exc;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
test_set_exception(PyObject *self, PyObject *new_exc)
 | 
						|
{
 | 
						|
    PyObject *exc = PyErr_GetHandledException();
 | 
						|
    assert(PyExceptionInstance_Check(exc) || exc == NULL);
 | 
						|
 | 
						|
    PyErr_SetHandledException(new_exc);
 | 
						|
    return exc;
 | 
						|
}
 | 
						|
 | 
						|
static PyObject *
 | 
						|
test_write_unraisable_exc(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *exc, *err_msg, *obj;
 | 
						|
    if (!PyArg_ParseTuple(args, "OOO", &exc, &err_msg, &obj)) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    const char *err_msg_utf8;
 | 
						|
    if (err_msg != Py_None) {
 | 
						|
        err_msg_utf8 = PyUnicode_AsUTF8(err_msg);
 | 
						|
        if (err_msg_utf8 == NULL) {
 | 
						|
            return NULL;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
        err_msg_utf8 = NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    PyErr_SetObject((PyObject *)Py_TYPE(exc), exc);
 | 
						|
    _PyErr_WriteUnraisableMsg(err_msg_utf8, obj);
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
/* To test the format of tracebacks as printed out. */
 | 
						|
static PyObject *
 | 
						|
traceback_print(PyObject *self, PyObject *args)
 | 
						|
{
 | 
						|
    PyObject *file;
 | 
						|
    PyObject *traceback;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "OO:traceback_print",
 | 
						|
                            &traceback, &file))
 | 
						|
    {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PyTraceBack_Print(traceback, file) < 0) {
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    Py_RETURN_NONE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 * Define the PyRecurdingInfinitelyError_Type
 | 
						|
 */
 | 
						|
 | 
						|
static PyTypeObject PyRecursingInfinitelyError_Type;
 | 
						|
 | 
						|
static int
 | 
						|
recurse_infinitely_error_init(PyObject *self, PyObject *args, PyObject *kwds)
 | 
						|
{
 | 
						|
    PyObject *type = (PyObject *)&PyRecursingInfinitelyError_Type;
 | 
						|
 | 
						|
    /* Instantiating this exception starts infinite recursion. */
 | 
						|
    Py_INCREF(type);
 | 
						|
    PyErr_SetObject(type, NULL);
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
static PyTypeObject PyRecursingInfinitelyError_Type = {
 | 
						|
    .tp_name = "RecursingInfinitelyError",
 | 
						|
    .tp_basicsize = sizeof(PyBaseExceptionObject),
 | 
						|
    .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
 | 
						|
    .tp_doc = PyDoc_STR("Instantiating this exception starts infinite recursion."),
 | 
						|
    .tp_init = (initproc)recurse_infinitely_error_init,
 | 
						|
};
 | 
						|
 | 
						|
static PyMethodDef test_methods[] = {
 | 
						|
    {"err_restore",             err_restore,                     METH_VARARGS},
 | 
						|
    {"err_set_raised",          err_set_raised,                  METH_O},
 | 
						|
    {"exception_print",         exception_print,                 METH_VARARGS},
 | 
						|
    {"fatal_error",             test_fatal_error,                METH_VARARGS,
 | 
						|
     PyDoc_STR("fatal_error(message, release_gil=False): call Py_FatalError(message)")},
 | 
						|
    {"make_exception_with_doc", _PyCFunction_CAST(make_exception_with_doc),
 | 
						|
     METH_VARARGS | METH_KEYWORDS},
 | 
						|
    {"exc_set_object",          exc_set_object,                  METH_VARARGS},
 | 
						|
    {"exc_set_object_fetch",    exc_set_object_fetch,            METH_VARARGS},
 | 
						|
    {"raise_exception",         raise_exception,                 METH_VARARGS},
 | 
						|
    {"raise_memoryerror",       raise_memoryerror,               METH_NOARGS},
 | 
						|
    {"set_exc_info",            test_set_exc_info,               METH_VARARGS},
 | 
						|
    {"set_exception",           test_set_exception,              METH_O},
 | 
						|
    {"traceback_print",         traceback_print,                 METH_VARARGS},
 | 
						|
    {"write_unraisable_exc",    test_write_unraisable_exc,       METH_VARARGS},
 | 
						|
    {NULL},
 | 
						|
};
 | 
						|
 | 
						|
int
 | 
						|
_PyTestCapi_Init_Exceptions(PyObject *mod)
 | 
						|
{
 | 
						|
    PyRecursingInfinitelyError_Type.tp_base = (PyTypeObject *)PyExc_Exception;
 | 
						|
    if (PyType_Ready(&PyRecursingInfinitelyError_Type) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (PyModule_AddObjectRef(mod, "RecursingInfinitelyError",
 | 
						|
                              (PyObject *)&PyRecursingInfinitelyError_Type) < 0)
 | 
						|
    {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (PyModule_AddFunctions(mod, test_methods) < 0) {
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 |