diff options
author | Guido van Rossum <guido@python.org> | 2020-05-14 19:01:14 -0700 |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 2020-05-14 19:01:14 -0700 |
commit | f93a54c48fc1644012aa0d4ee3887c1d121ac40e (patch) | |
tree | 189c841245d15318e5895638105bdbc532cbcdf5 /Modules | |
parent | 31641ff0e4b18c8d002d019f4506f0e8fb446983 (diff) | |
parent | 16ab07063cb564c1937714bd39d6915172f005b5 (diff) | |
download | cpython-git-fix-traceback-syntax-error.tar.gz |
Merge branch 'master' into fix-traceback-syntax-errorfix-traceback-syntax-error
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_io/textio.c | 2 | ||||
-rw-r--r-- | Modules/_testinternalcapi.c | 92 | ||||
-rw-r--r-- | Modules/_xxsubinterpretersmodule.c | 1147 | ||||
-rw-r--r-- | Modules/clinic/posixmodule.c.h | 91 | ||||
-rw-r--r-- | Modules/posixmodule.c | 178 |
5 files changed, 346 insertions, 1164 deletions
diff --git a/Modules/_io/textio.c b/Modules/_io/textio.c index 1abc9ca6f2..f2c72ebd51 100644 --- a/Modules/_io/textio.c +++ b/Modules/_io/textio.c @@ -1007,7 +1007,7 @@ io_check_errors(PyObject *errors) /* Avoid calling PyCodec_LookupError() before the codec registry is ready: before_PyUnicode_InitEncodings() is called. */ - if (!interp->fs_codec.encoding) { + if (!interp->unicode.fs_codec.encoding) { return 0; } diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index 1b7563cb20..5f217dcb89 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -14,6 +14,7 @@ #include "Python.h" #include "pycore_byteswap.h" // _Py_bswap32() #include "pycore_initconfig.h" // _Py_GetConfigsAsDict() +#include "pycore_hashtable.h" // _Py_hashtable_new() #include "pycore_gc.h" // PyGC_Head @@ -62,10 +63,101 @@ test_bswap(PyObject *self, PyObject *Py_UNUSED(args)) } +#define TO_PTR(ch) ((void*)(uintptr_t)ch) +#define FROM_PTR(ptr) ((uintptr_t)ptr) +#define VALUE(key) (1 + ((int)(key) - 'a')) + +static Py_uhash_t +hash_char(const void *key) +{ + char ch = (char)FROM_PTR(key); + return ch; +} + + +static int +hashtable_cb(_Py_hashtable_t *table, + const void *key_ptr, const void *value_ptr, + void *user_data) +{ + int *count = (int *)user_data; + char key = (char)FROM_PTR(key_ptr); + int value = (int)FROM_PTR(value_ptr); + assert(value == VALUE(key)); + *count += 1; + return 0; +} + + +static PyObject* +test_hashtable(PyObject *self, PyObject *Py_UNUSED(args)) +{ + _Py_hashtable_t *table = _Py_hashtable_new(hash_char, + _Py_hashtable_compare_direct); + if (table == NULL) { + return PyErr_NoMemory(); + } + + // Using an newly allocated table must not crash + assert(table->nentries == 0); + assert(table->nbuckets > 0); + assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL); + + // Test _Py_hashtable_set() + char key; + for (key='a'; key <= 'z'; key++) { + int value = VALUE(key); + if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) { + _Py_hashtable_destroy(table); + return PyErr_NoMemory(); + } + } + assert(table->nentries == 26); + assert(table->nbuckets > table->nentries); + + // Test _Py_hashtable_get_entry() + for (key='a'; key <= 'z'; key++) { + _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key)); + assert(entry != NULL); + assert(entry->key = TO_PTR(key)); + assert(entry->value = TO_PTR(VALUE(key))); + } + + // Test _Py_hashtable_get() + for (key='a'; key <= 'z'; key++) { + void *value_ptr = _Py_hashtable_get(table, TO_PTR(key)); + assert((int)FROM_PTR(value_ptr) == VALUE(key)); + } + + // Test _Py_hashtable_steal() + key = 'p'; + void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key)); + assert((int)FROM_PTR(value_ptr) == VALUE(key)); + assert(table->nentries == 25); + assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL); + + // Test _Py_hashtable_foreach() + int count = 0; + int res = _Py_hashtable_foreach(table, hashtable_cb, &count); + assert(res == 0); + assert(count == 25); + + // Test _Py_hashtable_clear() + _Py_hashtable_clear(table); + assert(table->nentries == 0); + assert(table->nbuckets > 0); + assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL); + + _Py_hashtable_destroy(table); + Py_RETURN_NONE; +} + + static PyMethodDef TestMethods[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, {"test_bswap", test_bswap, METH_NOARGS}, + {"test_hashtable", test_hashtable, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c index 18dd8918e7..8a6fce9e0b 100644 --- a/Modules/_xxsubinterpretersmodule.c +++ b/Modules/_xxsubinterpretersmodule.c @@ -1,4 +1,5 @@ -/* _interpreters module */ + +/* interpreters module */ /* low-level access to interpreter primitives */ #include "Python.h" @@ -6,927 +7,35 @@ #include "interpreteridobject.h" -// XXX Emit a warning? -#define IGNORE_FAILURE(msg) \ - fprintf(stderr, " -----\nRunFailedError: %s\n", msg); \ - PyErr_PrintEx(0); \ - fprintf(stderr, " -----\n"); \ - PyErr_Clear(); - -typedef void (*_deallocfunc)(void *); - -static PyInterpreterState * -_get_current(void) -{ - // _PyInterpreterState_Get() aborts if lookup fails, so don't need - // to check the result for NULL. - return _PyInterpreterState_Get(); -} - - -/* string utils *************************************************************/ - -// PyMem_Free() must be used to dealocate the resulting string. static char * -_strdup_and_size(const char *data, Py_ssize_t *psize, _deallocfunc *dealloc) -{ - if (data == NULL) { - if (psize != NULL) { - *psize = 0; - } - if (dealloc != NULL) { - *dealloc = NULL; - } - return ""; - } - - Py_ssize_t size; - if (psize == NULL) { - size = strlen(data); - } else { - size = *psize; - if (size == 0) { - size = strlen(data); - *psize = size; // The size "return" value. - } - } - char *copied = PyMem_Malloc(size+1); - if (copied == NULL) { - PyErr_NoMemory(); - return NULL; - } - if (dealloc != NULL) { - *dealloc = PyMem_Free; - } - memcpy(copied, data, size+1); - return copied; -} - -static const char * -_pyobj_get_str_and_size(PyObject *obj, Py_ssize_t *psize) -{ - if (PyUnicode_Check(obj)) { - return PyUnicode_AsUTF8AndSize(obj, psize); - } else { - const char *data = NULL; - PyBytes_AsStringAndSize(obj, (char **)&data, psize); - return data; - } -} - -/* "raw" strings */ - -typedef struct _rawstring { - Py_ssize_t size; - const char *data; - _deallocfunc dealloc; -} _rawstring; - -static void -_rawstring_init(_rawstring *raw) -{ - raw->size = 0; - raw->data = NULL; - raw->dealloc = NULL; -} - -static _rawstring * -_rawstring_new(void) -{ - _rawstring *raw = PyMem_NEW(_rawstring, 1); - if (raw == NULL) { - PyErr_NoMemory(); - return NULL; - } - _rawstring_init(raw); - return raw; -} - -static void -_rawstring_clear(_rawstring *raw) -{ - if (raw->data != NULL && raw->dealloc != NULL) { - (*raw->dealloc)((void *)raw->data); - } - _rawstring_init(raw); -} - -static void -_rawstring_free(_rawstring *raw) -{ - _rawstring_clear(raw); - PyMem_Free(raw); -} - -static int -_rawstring_is_clear(_rawstring *raw) -{ - return raw->size == 0 && raw->data == NULL && raw->dealloc == NULL; -} - -//static void -//_rawstring_move(_rawstring *raw, _rawstring *src) -//{ -// raw->size = src->size; -// raw->data = src->data; -// raw->dealloc = src->dealloc; -// _rawstring_init(src); -//} - -static void -_rawstring_proxy(_rawstring *raw, const char *str) +_copy_raw_string(PyObject *strobj) { + const char *str = PyUnicode_AsUTF8(strobj); if (str == NULL) { - str = ""; - } - raw->size = strlen(str); - raw->data = str; - raw->dealloc = NULL; -} - -static int -_rawstring_buffer(_rawstring *raw, Py_ssize_t size) -{ - raw->data = PyMem_Malloc(size+1); - if (raw->data == NULL) { - PyErr_NoMemory(); - return -1; - } - raw->size = size; - raw->dealloc = PyMem_Free; - return 0; -} - -static int -_rawstring_strcpy(_rawstring *raw, const char *str, Py_ssize_t size) -{ - _deallocfunc dealloc = NULL; - const char *copied = _strdup_and_size(str, &size, &dealloc); - if (copied == NULL) { - return -1; - } - - raw->size = size; - raw->dealloc = dealloc; - raw->data = copied; - return 0; -} - -static int -_rawstring_from_pyobj(_rawstring *raw, PyObject *obj) -{ - Py_ssize_t size = 0; - const char *data = _pyobj_get_str_and_size(obj, &size); - if (PyErr_Occurred()) { - return -1; - } - if (_rawstring_strcpy(raw, data, size) != 0) { - return -1; - } - return 0; -} - -static int -_rawstring_from_pyobj_attr(_rawstring *raw, PyObject *obj, const char *attr) -{ - int res = -1; - PyObject *valueobj = PyObject_GetAttrString(obj, attr); - if (valueobj == NULL) { - goto done; - } - if (!PyUnicode_Check(valueobj)) { - // XXX PyObject_Str()? Repr()? - goto done; - } - const char *valuestr = PyUnicode_AsUTF8(valueobj); - if (valuestr == NULL) { - if (PyErr_Occurred()) { - goto done; - } - } else if (_rawstring_strcpy(raw, valuestr, 0) != 0) { - _rawstring_clear(raw); - goto done; - } - res = 0; - -done: - Py_XDECREF(valueobj); - return res; -} - -static PyObject * -_rawstring_as_pybytes(_rawstring *raw) -{ - return PyBytes_FromStringAndSize(raw->data, raw->size); -} - - -/* object utils *************************************************************/ - -static void -_pyobj_identify_type(PyObject *obj, _rawstring *modname, _rawstring *clsname) -{ - PyObject *objtype = (PyObject *)Py_TYPE(obj); - - // Try __module__ and __name__. - if (_rawstring_from_pyobj_attr(modname, objtype, "__module__") != 0) { - // Fall back to the previous values in "modname". - IGNORE_FAILURE("bad __module__"); - } - if (_rawstring_from_pyobj_attr(clsname, objtype, "__name__") != 0) { - // Fall back to the previous values in "clsname". - IGNORE_FAILURE("bad __name__"); - } - - // XXX Fall back to __qualname__? - // XXX Fall back to tp_name? -} - -static PyObject * -_pyobj_get_class(const char *modname, const char *clsname) -{ - assert(clsname != NULL); - if (modname == NULL) { - modname = "builtins"; - } - - PyObject *module = PyImport_ImportModule(modname); - if (module == NULL) { - return NULL; - } - PyObject *cls = PyObject_GetAttrString(module, clsname); - Py_DECREF(module); - return cls; -} - -static PyObject * -_pyobj_create(const char *modname, const char *clsname, PyObject *arg) -{ - PyObject *cls = _pyobj_get_class(modname, clsname); - if (cls == NULL) { return NULL; } - PyObject *obj = NULL; - if (arg == NULL) { - obj = _PyObject_CallNoArg(cls); - } else { - obj = PyObject_CallFunction(cls, "O", arg); - } - Py_DECREF(cls); - return obj; -} - - -/* object snapshots */ - -typedef struct _objsnapshot { - // If modname is NULL then try "builtins" and "__main__". - _rawstring modname; - // clsname is required. - _rawstring clsname; - - // The rest are optional. - - // The serialized exception. - _rawstring *serialized; -} _objsnapshot; - -static void -_objsnapshot_init(_objsnapshot *osn) -{ - _rawstring_init(&osn->modname); - _rawstring_init(&osn->clsname); - osn->serialized = NULL; -} - -//static _objsnapshot * -//_objsnapshot_new(void) -//{ -// _objsnapshot *osn = PyMem_NEW(_objsnapshot, 1); -// if (osn == NULL) { -// PyErr_NoMemory(); -// return NULL; -// } -// _objsnapshot_init(osn); -// return osn; -//} - -static void -_objsnapshot_clear(_objsnapshot *osn) -{ - _rawstring_clear(&osn->modname); - _rawstring_clear(&osn->clsname); - if (osn->serialized != NULL) { - _rawstring_free(osn->serialized); - osn->serialized = NULL; - } -} - -//static void -//_objsnapshot_free(_objsnapshot *osn) -//{ -// _objsnapshot_clear(osn); -// PyMem_Free(osn); -//} - -#ifndef NDEBUG -static int -_objsnapshot_is_clear(_objsnapshot *osn) -{ - return osn->serialized == NULL - && _rawstring_is_clear(&osn->modname) - && _rawstring_is_clear(&osn->clsname); -} -#endif - -static void -_objsnapshot_summarize(_objsnapshot *osn, _rawstring *rawbuf, const char *msg) -{ - if (msg == NULL || *msg == '\0') { - // XXX Keep it NULL? - // XXX Keep it an empty string? - // XXX Use something more informative? - msg = "<no message>"; - } - const char *clsname = osn->clsname.data; - const char *modname = osn->modname.data; - if (modname && *modname == '\0') { - modname = NULL; - } - - // Prep the buffer. - Py_ssize_t size = strlen(clsname); - if (modname != NULL) { - if (strcmp(modname, "builtins") == 0) { - modname = NULL; - } else if (strcmp(modname, "__main__") == 0) { - modname = NULL; - } else { - size += strlen(modname) + 1; - } - } - if (msg != NULL) { - size += strlen(": ") + strlen(msg); - } - if (modname != NULL || msg != NULL) { - if (_rawstring_buffer(rawbuf, size) != 0) { - IGNORE_FAILURE("could not summarize object snapshot"); - return; - } - } - // ...else we'll proxy clsname as-is, so no need to allocate a buffer. - - // XXX Use __qualname__ somehow? - char *buf = (char *)rawbuf->data; - if (modname != NULL) { - if (msg != NULL) { - snprintf(buf, size+1, "%s.%s: %s", modname, clsname, msg); - } else { - snprintf(buf, size+1, "%s.%s", modname, clsname); - } - } else if (msg != NULL) { - snprintf(buf, size+1, "%s: %s", clsname, msg); - } else { - _rawstring_proxy(rawbuf, clsname); - } -} - -static _rawstring * -_objsnapshot_get_minimal_summary(_objsnapshot *osn, PyObject *obj) -{ - const char *str = NULL; - PyObject *objstr = PyObject_Str(obj); - if (objstr == NULL) { - PyErr_Clear(); - } else { - str = PyUnicode_AsUTF8(objstr); - if (str == NULL) { - PyErr_Clear(); - } - } - - _rawstring *summary = _rawstring_new(); - if (summary == NULL) { - return NULL; - } - _objsnapshot_summarize(osn, summary, str); - return summary; -} - -static void -_objsnapshot_extract(_objsnapshot *osn, PyObject *obj) -{ - assert(_objsnapshot_is_clear(osn)); - - // Get the "qualname". - _rawstring_proxy(&osn->modname, "<unknown>"); - _rawstring_proxy(&osn->clsname, "<unknown>"); - _pyobj_identify_type(obj, &osn->modname, &osn->clsname); - - // Serialize the object. - // XXX Use marshal? - PyObject *pickle = PyImport_ImportModule("pickle"); - if (pickle == NULL) { - IGNORE_FAILURE("could not serialize object: pickle import failed"); - return; - } - PyObject *objdata = PyObject_CallMethod(pickle, "dumps", "(O)", obj); - Py_DECREF(pickle); - if (objdata == NULL) { - IGNORE_FAILURE("could not serialize object: pickle.dumps failed"); - } else { - _rawstring *serialized = _rawstring_new(); - int res = _rawstring_from_pyobj(serialized, objdata); - Py_DECREF(objdata); - if (res != 0) { - IGNORE_FAILURE("could not serialize object: raw str failed"); - _rawstring_free(serialized); - } else if (serialized->size == 0) { - _rawstring_free(serialized); - } else { - osn->serialized = serialized; - } - } -} - -static PyObject * -_objsnapshot_resolve_serialized(_objsnapshot *osn) -{ - assert(osn->serialized != NULL); - - // XXX Use marshal? - PyObject *pickle = PyImport_ImportModule("pickle"); - if (pickle == NULL) { - return NULL; - } - PyObject *objdata = _rawstring_as_pybytes(osn->serialized); - if (objdata == NULL) { - return NULL; - } else { - PyObject *obj = PyObject_CallMethod(pickle, "loads", "O", objdata); - Py_DECREF(objdata); - return obj; - } -} - -static PyObject * -_objsnapshot_resolve_naive(_objsnapshot *osn, PyObject *arg) -{ - if (_rawstring_is_clear(&osn->clsname)) { - // We can't proceed without at least the class name. - PyErr_SetString(PyExc_ValueError, "missing class name"); - return NULL; - } - - if (osn->modname.data != NULL) { - return _pyobj_create(osn->modname.data, osn->clsname.data, arg); - } else { - PyObject *obj = _pyobj_create("builtins", osn->clsname.data, arg); - if (obj == NULL) { - PyErr_Clear(); - obj = _pyobj_create("__main__", osn->clsname.data, arg); - } - return obj; - } -} - -static PyObject * -_objsnapshot_resolve(_objsnapshot *osn) -{ - if (osn->serialized != NULL) { - PyObject *obj = _objsnapshot_resolve_serialized(osn); - if (obj != NULL) { - return obj; - } - IGNORE_FAILURE("could not de-serialize object"); - } - - // Fall back to naive resolution. - return _objsnapshot_resolve_naive(osn, NULL); -} - - -/* exception utils **********************************************************/ - -// _pyexc_create is inspired by _PyErr_SetObject(). - -static PyObject * -_pyexc_create(PyObject *exctype, const char *msg, PyObject *tb) -{ - assert(exctype != NULL && PyExceptionClass_Check(exctype)); - - PyObject *curtype = NULL, *curexc = NULL, *curtb = NULL; - PyErr_Fetch(&curtype, &curexc, &curtb); - - // Create the object. - PyObject *exc = NULL; - if (msg != NULL) { - PyObject *msgobj = PyUnicode_FromString(msg); - if (msgobj == NULL) { - IGNORE_FAILURE("could not deserialize propagated error message"); - } - exc = _PyObject_CallOneArg(exctype, msgobj); - Py_XDECREF(msgobj); - } else { - exc = _PyObject_CallNoArg(exctype); - } - if (exc == NULL) { - return NULL; - } - - // Set the traceback, if any. - if (tb == NULL) { - tb = curtb; - } - if (tb != NULL) { - // This does *not* steal a reference! - PyException_SetTraceback(exc, tb); - } - - PyErr_Restore(curtype, curexc, curtb); - - return exc; -} - -/* traceback snapshots */ - -typedef struct _tbsnapshot { - _rawstring tbs_funcname; - _rawstring tbs_filename; - int tbs_lineno; - struct _tbsnapshot *tbs_next; -} _tbsnapshot; - -static void -_tbsnapshot_init(_tbsnapshot *tbs) -{ - _rawstring_init(&tbs->tbs_funcname); - _rawstring_init(&tbs->tbs_filename); - tbs->tbs_lineno = -1; - tbs->tbs_next = NULL; -} - -static _tbsnapshot * -_tbsnapshot_new(void) -{ - _tbsnapshot *tbs = PyMem_NEW(_tbsnapshot, 1); - if (tbs == NULL) { - PyErr_NoMemory(); - return NULL; - } - _tbsnapshot_init(tbs); - return tbs; -} - -static void _tbsnapshot_free(_tbsnapshot *); // forward - -static void -_tbsnapshot_clear(_tbsnapshot *tbs) -{ - _rawstring_clear(&tbs->tbs_funcname); - _rawstring_clear(&tbs->tbs_filename); - tbs->tbs_lineno = -1; - if (tbs->tbs_next != NULL) { - _tbsnapshot_free(tbs->tbs_next); - tbs->tbs_next = NULL; - } -} - -static void -_tbsnapshot_free(_tbsnapshot *tbs) -{ - _tbsnapshot_clear(tbs); - PyMem_Free(tbs); -} - -#ifndef NDEBUG -static int -_tbsnapshot_is_clear(_tbsnapshot *tbs) -{ - return tbs->tbs_lineno == -1 && tbs->tbs_next == NULL - && _rawstring_is_clear(&tbs->tbs_funcname) - && _rawstring_is_clear(&tbs->tbs_filename); -} -#endif - -static int -_tbsnapshot_from_pytb(_tbsnapshot *tbs, PyTracebackObject *pytb) -{ - assert(_tbsnapshot_is_clear(tbs)); - assert(pytb != NULL); - - PyCodeObject *pycode = pytb->tb_frame->f_code; - const char *funcname = PyUnicode_AsUTF8(pycode->co_name); - if (_rawstring_strcpy(&tbs->tbs_funcname, funcname, 0) != 0) { - goto error; - } - const char *filename = PyUnicode_AsUTF8(pycode->co_filename); - if (_rawstring_strcpy(&tbs->tbs_filename, filename, 0) != 0) { - goto error; - } - tbs->tbs_lineno = pytb->tb_lineno; - - return 0; - -error: - _tbsnapshot_clear(tbs); - return -1; -} - -static int -_tbsnapshot_extract(_tbsnapshot *tbs, PyTracebackObject *pytb) -{ - assert(_tbsnapshot_is_clear(tbs)); - assert(pytb != NULL); - - _tbsnapshot *next = NULL; - while (pytb->tb_next != NULL) { - _tbsnapshot *_next = _tbsnapshot_new(); - if (_next == NULL) { - goto error; - } - if (_tbsnapshot_from_pytb(_next, pytb) != 0) { - goto error; - } - if (next != NULL) { - _next->tbs_next = next; - } - next = _next; - pytb = pytb->tb_next; - } - if (_tbsnapshot_from_pytb(tbs, pytb) != 0) { - goto error; - } - tbs->tbs_next = next; - - return 0; - -error: - _tbsnapshot_clear(tbs); - return -1; -} - -static PyObject * -_tbsnapshot_resolve(_tbsnapshot *tbs) -{ - assert(!PyErr_Occurred()); - // At this point there should be no traceback set yet. - - while (tbs != NULL) { - const char *funcname = tbs->tbs_funcname.data; - const char *filename = tbs->tbs_filename.data; - _PyTraceback_Add(funcname ? funcname : "", - filename ? filename : "", - tbs->tbs_lineno); - tbs = tbs->tbs_next; - } - - PyObject *exctype = NULL, *excval = NULL, *tb = NULL; - PyErr_Fetch(&exctype, &excval, &tb); - // Leave it cleared. - return tb; -} - -/* exception snapshots */ - -typedef struct _excsnapshot { - _objsnapshot es_object; - _rawstring *es_msg; - struct _excsnapshot *es_cause; - struct _excsnapshot *es_context; - char es_suppress_context; - struct _tbsnapshot *es_traceback; -} _excsnapshot; - -static void -_excsnapshot_init(_excsnapshot *es) -{ - _objsnapshot_init(&es->es_object); - es->es_msg = NULL; - es->es_cause = NULL; - es->es_context = NULL; - es->es_suppress_context = 0; - es->es_traceback = NULL; -} - -static _excsnapshot * -_excsnapshot_new(void) { - _excsnapshot *es = PyMem_NEW(_excsnapshot, 1); - if (es == NULL) { + char *copied = PyMem_Malloc(strlen(str)+1); + if (copied == NULL) { PyErr_NoMemory(); return NULL; } - _excsnapshot_init(es); - return es; -} - -static void _excsnapshot_free(_excsnapshot *); // forward - -static void -_excsnapshot_clear(_excsnapshot *es) -{ - _objsnapshot_clear(&es->es_object); - if (es->es_msg != NULL) { - _rawstring_free(es->es_msg); - es->es_msg = NULL; - } - if (es->es_cause != NULL) { - _excsnapshot_free(es->es_cause); - es->es_cause = NULL; - } - if (es->es_context != NULL) { - _excsnapshot_free(es->es_context); - es->es_context = NULL; - } - es->es_suppress_context = 0; - if (es->es_traceback != NULL) { - _tbsnapshot_free(es->es_traceback); - es->es_traceback = NULL; - } -} - -static void -_excsnapshot_free(_excsnapshot *es) -{ - _excsnapshot_clear(es); - PyMem_Free(es); -} - -#ifndef NDEBUG -static int -_excsnapshot_is_clear(_excsnapshot *es) -{ - return es->es_suppress_context == 0 - && es->es_cause == NULL - && es->es_context == NULL - && es->es_traceback == NULL - && es->es_msg == NULL - && _objsnapshot_is_clear(&es->es_object); -} -#endif - -static PyObject * -_excsnapshot_get_exc_naive(_excsnapshot *es) -{ - _rawstring buf; - const char *msg = NULL; - if (es->es_msg != NULL) { - msg = es->es_msg->data; - } else { - _objsnapshot_summarize(&es->es_object, &buf, NULL); - if (buf.size > 0) { - msg = buf.data; - } - } - - PyObject *exc = NULL; - // XXX Use _objsnapshot_resolve_naive()? - const char *modname = es->es_object.modname.size > 0 - ? es->es_object.modname.data - : NULL; - PyObject *exctype = _pyobj_get_class(modname, es->es_object.clsname.data); - if (exctype != NULL) { - exc = _pyexc_create(exctype, msg, NULL); - Py_DECREF(exctype); - if (exc != NULL) { - return exc; - } - PyErr_Clear(); - } else { - PyErr_Clear(); - } - exctype = PyExc_Exception; - return _pyexc_create(exctype, msg, NULL); -} - -static PyObject * -_excsnapshot_get_exc(_excsnapshot *es) -{ - assert(!_objsnapshot_is_clear(&es->es_object)); - - PyObject *exc = _objsnapshot_resolve(&es->es_object); - if (exc == NULL) { - // Fall back to resolving the object. - PyObject *curtype = NULL, *curexc = NULL, *curtb = NULL; - PyErr_Fetch(&curtype, &curexc, &curtb); - - exc = _excsnapshot_get_exc_naive(es); - if (exc == NULL) { - PyErr_Restore(curtype, curexc, curtb); - return NULL; - } - } - // People can do some weird stuff... - if (!PyExceptionInstance_Check(exc)) { - // We got a bogus "exception". - Py_DECREF(exc); - PyErr_SetString(PyExc_TypeError, "expected exception"); - return NULL; - } - return exc; -} - -static void _excsnapshot_extract(_excsnapshot *, PyObject *); -static void -_excsnapshot_extract(_excsnapshot *es, PyObject *excobj) -{ - assert(_excsnapshot_is_clear(es)); - assert(PyExceptionInstance_Check(excobj)); - - _objsnapshot_extract(&es->es_object, excobj); - - es->es_msg = _objsnapshot_get_minimal_summary(&es->es_object, excobj); - if (es->es_msg == NULL) { - PyErr_Clear(); - } - - PyBaseExceptionObject *exc = (PyBaseExceptionObject *)excobj; - - if (exc->cause != NULL && exc->cause != Py_None) { - es->es_cause = _excsnapshot_new(); - _excsnapshot_extract(es->es_cause, exc->cause); - } - - if (exc->context != NULL && exc->context != Py_None) { - es->es_context = _excsnapshot_new(); - _excsnapshot_extract(es->es_context, exc->context); - } - - es->es_suppress_context = exc->suppress_context; - - PyObject *tb = PyException_GetTraceback(excobj); - if (PyErr_Occurred()) { - IGNORE_FAILURE("could not get traceback"); - } else if (tb == Py_None) { - Py_DECREF(tb); - tb = NULL; - } - if (tb != NULL) { - es->es_traceback = _tbsnapshot_new(); - if (_tbsnapshot_extract(es->es_traceback, - (PyTracebackObject *)tb) != 0) { - IGNORE_FAILURE("could not extract __traceback__"); - } - } + strcpy(copied, str); + return copied; } -static PyObject * -_excsnapshot_resolve(_excsnapshot *es) +static PyInterpreterState * +_get_current(void) { - PyObject *exc = _excsnapshot_get_exc(es); - if (exc == NULL) { - return NULL; - } - - if (es->es_traceback != NULL) { - PyObject *tb = _tbsnapshot_resolve(es->es_traceback); - if (tb == NULL) { - // The snapshot is still somewhat useful without this. - IGNORE_FAILURE("could not deserialize traceback"); - } else { - // This does not steal references. - PyException_SetTraceback(exc, tb); - Py_DECREF(tb); - } - } - // NULL means "not set". - - if (es->es_context != NULL) { - PyObject *context = _excsnapshot_resolve(es->es_context); - if (context == NULL) { - // The snapshot is still useful without this. - IGNORE_FAILURE("could not deserialize __context__"); - } else { - // This steals references but we have one to give. - PyException_SetContext(exc, context); - } - } - // NULL means "not set". - - if (es->es_cause != NULL) { - PyObject *cause = _excsnapshot_resolve(es->es_cause); - if (cause == NULL) { - // The snapshot is still useful without this. - IGNORE_FAILURE("could not deserialize __cause__"); - } else { - // This steals references, but we have one to give. - PyException_SetCause(exc, cause); - } - } - // NULL means "not set". - - ((PyBaseExceptionObject *)exc)->suppress_context = es->es_suppress_context; - - return exc; + // PyInterpreterState_Get() aborts if lookup fails, so don't need + // to check the result for NULL. + return PyInterpreterState_Get(); } /* data-sharing-specific code ***********************************************/ -/* shared "object" */ - struct _sharednsitem { - _rawstring name; + char *name; _PyCrossInterpreterData data; }; @@ -935,7 +44,8 @@ static void _sharednsitem_clear(struct _sharednsitem *); // forward static int _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value) { - if (_rawstring_from_pyobj(&item->name, key) != 0) { + item->name = _copy_raw_string(key); + if (item->name == NULL) { return -1; } if (_PyObject_GetCrossInterpreterData(value, &item->data) != 0) { @@ -948,14 +58,17 @@ _sharednsitem_init(struct _sharednsitem *item, PyObject *key, PyObject *value) static void _sharednsitem_clear(struct _sharednsitem *item) { - _rawstring_clear(&item->name); + if (item->name != NULL) { + PyMem_Free(item->name); + item->name = NULL; + } _PyCrossInterpreterData_Release(&item->data); } static int _sharednsitem_apply(struct _sharednsitem *item, PyObject *ns) { - PyObject *name = PyUnicode_FromString(item->name.data); + PyObject *name = PyUnicode_FromString(item->name); if (name == NULL) { return -1; } @@ -1046,121 +159,121 @@ _sharedns_apply(_sharedns *shared, PyObject *ns) return 0; } -/* shared exception */ - // 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 _sharedexception { - _excsnapshot snapshot; - _rawstring msg; + char *name; + char *msg; } _sharedexception; -static void -_sharedexception_init(_sharedexception *she) -{ - _excsnapshot_init(&she->snapshot); - _rawstring_init(&she->msg); -} - static _sharedexception * _sharedexception_new(void) { - _sharedexception *she = PyMem_NEW(_sharedexception, 1); - if (she == NULL) { + _sharedexception *err = PyMem_NEW(_sharedexception, 1); + if (err == NULL) { PyErr_NoMemory(); return NULL; } - _sharedexception_init(she); - return she; + err->name = NULL; + err->msg = NULL; + return err; } static void -_sharedexception_clear(_sharedexception *she) +_sharedexception_clear(_sharedexception *exc) { - _excsnapshot_clear(&she->snapshot); - _rawstring_clear(&she->msg); + if (exc->name != NULL) { + PyMem_Free(exc->name); + } + if (exc->msg != NULL) { + PyMem_Free(exc->msg); + } } static void -_sharedexception_free(_sharedexception *she) +_sharedexception_free(_sharedexception *exc) { - _sharedexception_clear(she); - PyMem_Free(she); + _sharedexception_clear(exc); + PyMem_Free(exc); } -#ifndef NDEBUG -static int -_sharedexception_is_clear(_sharedexception *she) +static _sharedexception * +_sharedexception_bind(PyObject *exctype, PyObject *exc, PyObject *tb) { - return 1 - && _excsnapshot_is_clear(&she->snapshot) - && _rawstring_is_clear(&she->msg); -} -#endif + assert(exctype != NULL); + char *failure = NULL; -static PyObject * -_sharedexception_get_cause(_sharedexception *sharedexc) -{ - // FYI, "cause" is already normalized. - PyObject *cause = _excsnapshot_resolve(&sharedexc->snapshot); - if (cause == NULL) { - if (PyErr_Occurred()) { - IGNORE_FAILURE("could not deserialize exc snapshot"); - } - return NULL; + _sharedexception *err = _sharedexception_new(); + if (err == NULL) { + goto finally; } - // XXX Ensure "cause" has a traceback. - return cause; -} -static void -_sharedexception_extract(_sharedexception *she, PyObject *exc) -{ - assert(_sharedexception_is_clear(she)); - assert(exc != NULL); + PyObject *name = PyUnicode_FromFormat("%S", exctype); + if (name == NULL) { + failure = "unable to format exception type name"; + goto finally; + } + err->name = _copy_raw_string(name); + Py_DECREF(name); + if (err->name == NULL) { + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + failure = "out of memory copying exception type name"; + } else { + failure = "unable to encode and copy exception type name"; + } + goto finally; + } - _excsnapshot_extract(&she->snapshot, exc); + if (exc != NULL) { + PyObject *msg = PyUnicode_FromFormat("%S", exc); + if (msg == NULL) { + failure = "unable to format exception message"; + goto finally; + } + err->msg = _copy_raw_string(msg); + Py_DECREF(msg); + if (err->msg == NULL) { + if (PyErr_ExceptionMatches(PyExc_MemoryError)) { + failure = "out of memory copying exception message"; + } else { + failure = "unable to encode and copy exception message"; + } + goto finally; + } + } - // Compose the message. - const char *msg = NULL; - PyObject *msgobj = PyUnicode_FromFormat("%S", exc); - if (msgobj == NULL) { - IGNORE_FAILURE("unable to format exception message"); - } else { - msg = PyUnicode_AsUTF8(msgobj); - if (PyErr_Occurred()) { - PyErr_Clear(); +finally: + if (failure != NULL) { + PyErr_Clear(); + if (err->name != NULL) { + PyMem_Free(err->name); + err->name = NULL; } + err->msg = failure; } - _objsnapshot_summarize(&she->snapshot.es_object, &she->msg, msg); - Py_XDECREF(msgobj); + return err; } -static PyObject * -_sharedexception_resolve(_sharedexception *sharedexc, PyObject *wrapperclass) +static void +_sharedexception_apply(_sharedexception *exc, PyObject *wrapperclass) { - assert(!PyErr_Occurred()); - - // Get the exception object (already normalized). - PyObject *exc = _pyexc_create(wrapperclass, sharedexc->msg.data, NULL); - assert(exc != NULL); - - // Set __cause__, is possible. - PyObject *cause = _sharedexception_get_cause(sharedexc); - if (cause != NULL) { - // Set __context__. - Py_INCREF(cause); // PyException_SetContext() steals a reference. - PyException_SetContext(exc, cause); - - // Set __cause__. - Py_INCREF(cause); // PyException_SetCause() steals a reference. - PyException_SetCause(exc, cause); + if (exc->name != NULL) { + if (exc->msg != NULL) { + PyErr_Format(wrapperclass, "%s: %s", exc->name, exc->msg); + } + else { + PyErr_SetString(wrapperclass, exc->name); + } + } + else if (exc->msg != NULL) { + PyErr_SetString(wrapperclass, exc->msg); + } + else { + PyErr_SetNone(wrapperclass); } - - return exc; } @@ -2756,9 +1869,11 @@ _ensure_not_running(PyInterpreterState *interp) static int _run_script(PyInterpreterState *interp, const char *codestr, - _sharedns *shared, _sharedexception **pexc) + _sharedns *shared, _sharedexception **exc) { - assert(!PyErr_Occurred()); // ...in the called interpreter. + PyObject *exctype = NULL; + PyObject *excval = NULL; + PyObject *tb = NULL; PyObject *main_mod = _PyInterpreterState_GetMainModule(interp); if (main_mod == NULL) { @@ -2789,38 +1904,25 @@ _run_script(PyInterpreterState *interp, const char *codestr, Py_DECREF(result); // We throw away the result. } - *pexc = NULL; + *exc = NULL; return 0; - PyObject *exctype = NULL, *exc = NULL, *tb = NULL; error: - PyErr_Fetch(&exctype, &exc, &tb); - - // First normalize the exception. - PyErr_NormalizeException(&exctype, &exc, &tb); - assert(PyExceptionInstance_Check(exc)); - if (tb != NULL) { - PyException_SetTraceback(exc, tb); - } - - // Behave as though the exception was caught in this thread. - PyErr_SetExcInfo(exctype, exc, tb); // Like entering "except" block. + PyErr_Fetch(&exctype, &excval, &tb); - // Serialize the exception. - _sharedexception *sharedexc = _sharedexception_new(); + _sharedexception *sharedexc = _sharedexception_bind(exctype, excval, tb); + Py_XDECREF(exctype); + Py_XDECREF(excval); + Py_XDECREF(tb); if (sharedexc == NULL) { - IGNORE_FAILURE("script raised an uncaught exception"); - } else { - _sharedexception_extract(sharedexc, exc); + fprintf(stderr, "RunFailedError: script raised an uncaught exception"); + PyErr_Clear(); + sharedexc = NULL; + } + else { assert(!PyErr_Occurred()); } - - // Clear the exception. - PyErr_SetExcInfo(NULL, NULL, NULL); // Like leaving "except" block. - PyErr_Clear(); // Do not re-raise. - - // "Return" the serialized exception. - *pexc = sharedexc; + *exc = sharedexc; return -1; } @@ -2828,8 +1930,6 @@ static int _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, PyObject *shareables) { - assert(!PyErr_Occurred()); // ...in the calling interpreter. - if (_ensure_not_running(interp) < 0) { return -1; } @@ -2863,8 +1963,8 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, } // Run the script. - _sharedexception *sharedexc = NULL; - int result = _run_script(interp, codestr, shared, &sharedexc); + _sharedexception *exc = NULL; + int result = _run_script(interp, codestr, shared, &exc); // Switch back. if (save_tstate != NULL) { @@ -2873,14 +1973,9 @@ _run_script_in_interpreter(PyInterpreterState *interp, const char *codestr, #endif // Propagate any exception out to the caller. - if (sharedexc != NULL) { - assert(!PyErr_Occurred()); - PyObject *exc = _sharedexception_resolve(sharedexc, RunFailedError); - // XXX This is not safe once interpreters no longer share allocators. - _sharedexception_free(sharedexc); - PyObject *exctype = (PyObject *)Py_TYPE(exc); - Py_INCREF(exctype); // PyErr_Restore() steals a reference. - PyErr_Restore(exctype, exc, PyException_GetTraceback(exc)); + if (exc != NULL) { + _sharedexception_apply(exc, RunFailedError); + _sharedexception_free(exc); } else if (result != 0) { // We were unable to allocate a shared exception. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index cf6d7449ba..41baa45573 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -8388,18 +8388,24 @@ PyDoc_STRVAR(os_DirEntry_is_symlink__doc__, "Return True if the entry is a symbolic link; cached per entry."); #define OS_DIRENTRY_IS_SYMLINK_METHODDEF \ - {"is_symlink", (PyCFunction)os_DirEntry_is_symlink, METH_NOARGS, os_DirEntry_is_symlink__doc__}, + {"is_symlink", (PyCFunction)(void(*)(void))os_DirEntry_is_symlink, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, os_DirEntry_is_symlink__doc__}, static int -os_DirEntry_is_symlink_impl(DirEntry *self); +os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class); static PyObject * -os_DirEntry_is_symlink(DirEntry *self, PyObject *Py_UNUSED(ignored)) +os_DirEntry_is_symlink(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; + static const char * const _keywords[] = { NULL}; + static _PyArg_Parser _parser = {":is_symlink", _keywords, 0}; int _return_value; - _return_value = os_DirEntry_is_symlink_impl(self); + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser + )) { + goto exit; + } + _return_value = os_DirEntry_is_symlink_impl(self, defining_class); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } @@ -8416,34 +8422,25 @@ PyDoc_STRVAR(os_DirEntry_stat__doc__, "Return stat_result object for the entry; cached per entry."); #define OS_DIRENTRY_STAT_METHODDEF \ - {"stat", (PyCFunction)(void(*)(void))os_DirEntry_stat, METH_FASTCALL|METH_KEYWORDS, os_DirEntry_stat__doc__}, + {"stat", (PyCFunction)(void(*)(void))os_DirEntry_stat, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, os_DirEntry_stat__doc__}, static PyObject * -os_DirEntry_stat_impl(DirEntry *self, int follow_symlinks); +os_DirEntry_stat_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks); static PyObject * -os_DirEntry_stat(DirEntry *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +os_DirEntry_stat(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"follow_symlinks", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "stat", 0}; - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + static _PyArg_Parser _parser = {"|$p:stat", _keywords, 0}; int follow_symlinks = 1; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_kwonly; - } - follow_symlinks = PyObject_IsTrue(args[0]); - if (follow_symlinks < 0) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &follow_symlinks)) { goto exit; } -skip_optional_kwonly: - return_value = os_DirEntry_stat_impl(self, follow_symlinks); + return_value = os_DirEntry_stat_impl(self, defining_class, follow_symlinks); exit: return return_value; @@ -8456,35 +8453,26 @@ PyDoc_STRVAR(os_DirEntry_is_dir__doc__, "Return True if the entry is a directory; cached per entry."); #define OS_DIRENTRY_IS_DIR_METHODDEF \ - {"is_dir", (PyCFunction)(void(*)(void))os_DirEntry_is_dir, METH_FASTCALL|METH_KEYWORDS, os_DirEntry_is_dir__doc__}, + {"is_dir", (PyCFunction)(void(*)(void))os_DirEntry_is_dir, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, os_DirEntry_is_dir__doc__}, static int -os_DirEntry_is_dir_impl(DirEntry *self, int follow_symlinks); +os_DirEntry_is_dir_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks); static PyObject * -os_DirEntry_is_dir(DirEntry *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +os_DirEntry_is_dir(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"follow_symlinks", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "is_dir", 0}; - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + static _PyArg_Parser _parser = {"|$p:is_dir", _keywords, 0}; int follow_symlinks = 1; int _return_value; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_kwonly; - } - follow_symlinks = PyObject_IsTrue(args[0]); - if (follow_symlinks < 0) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &follow_symlinks)) { goto exit; } -skip_optional_kwonly: - _return_value = os_DirEntry_is_dir_impl(self, follow_symlinks); + _return_value = os_DirEntry_is_dir_impl(self, defining_class, follow_symlinks); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } @@ -8501,35 +8489,26 @@ PyDoc_STRVAR(os_DirEntry_is_file__doc__, "Return True if the entry is a file; cached per entry."); #define OS_DIRENTRY_IS_FILE_METHODDEF \ - {"is_file", (PyCFunction)(void(*)(void))os_DirEntry_is_file, METH_FASTCALL|METH_KEYWORDS, os_DirEntry_is_file__doc__}, + {"is_file", (PyCFunction)(void(*)(void))os_DirEntry_is_file, METH_METHOD|METH_FASTCALL|METH_KEYWORDS, os_DirEntry_is_file__doc__}, static int -os_DirEntry_is_file_impl(DirEntry *self, int follow_symlinks); +os_DirEntry_is_file_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks); static PyObject * -os_DirEntry_is_file(DirEntry *self, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +os_DirEntry_is_file(DirEntry *self, PyTypeObject *defining_class, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) { PyObject *return_value = NULL; static const char * const _keywords[] = {"follow_symlinks", NULL}; - static _PyArg_Parser _parser = {NULL, _keywords, "is_file", 0}; - PyObject *argsbuf[1]; - Py_ssize_t noptargs = nargs + (kwnames ? PyTuple_GET_SIZE(kwnames) : 0) - 0; + static _PyArg_Parser _parser = {"|$p:is_file", _keywords, 0}; int follow_symlinks = 1; int _return_value; - args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 0, 0, 0, argsbuf); - if (!args) { - goto exit; - } - if (!noptargs) { - goto skip_optional_kwonly; - } - follow_symlinks = PyObject_IsTrue(args[0]); - if (follow_symlinks < 0) { + if (!_PyArg_ParseStackAndKeywords(args, nargs, kwnames, &_parser, + &follow_symlinks)) { goto exit; } -skip_optional_kwonly: - _return_value = os_DirEntry_is_file_impl(self, follow_symlinks); + _return_value = os_DirEntry_is_file_impl(self, defining_class, follow_symlinks); if ((_return_value == -1) && PyErr_Occurred()) { goto exit; } @@ -9417,4 +9396,4 @@ exit: #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=be90d3aba972098b input=a9049054013a1b77]*/ +/*[clinic end generated code: output=005919eaaef3f8e6 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 60a60e9aed..2ddf30de89 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2101,48 +2101,50 @@ statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds) static int _posix_clear(PyObject *module) { - Py_CLEAR(get_posix_state(module)->billion); - Py_CLEAR(get_posix_state(module)->DirEntryType); - Py_CLEAR(get_posix_state(module)->ScandirIteratorType); + _posixstate *state = get_posix_state(module); + Py_CLEAR(state->billion); + Py_CLEAR(state->DirEntryType); + Py_CLEAR(state->ScandirIteratorType); #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) - Py_CLEAR(get_posix_state(module)->SchedParamType); + Py_CLEAR(state->SchedParamType); #endif - Py_CLEAR(get_posix_state(module)->StatResultType); - Py_CLEAR(get_posix_state(module)->StatVFSResultType); - Py_CLEAR(get_posix_state(module)->TerminalSizeType); - Py_CLEAR(get_posix_state(module)->TimesResultType); - Py_CLEAR(get_posix_state(module)->UnameResultType); + Py_CLEAR(state->StatResultType); + Py_CLEAR(state->StatVFSResultType); + Py_CLEAR(state->TerminalSizeType); + Py_CLEAR(state->TimesResultType); + Py_CLEAR(state->UnameResultType); #if defined(HAVE_WAITID) && !defined(__APPLE__) - Py_CLEAR(get_posix_state(module)->WaitidResultType); + Py_CLEAR(state->WaitidResultType); #endif #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4) - Py_CLEAR(get_posix_state(module)->struct_rusage); + Py_CLEAR(state->struct_rusage); #endif - Py_CLEAR(get_posix_state(module)->st_mode); + Py_CLEAR(state->st_mode); return 0; } static int _posix_traverse(PyObject *module, visitproc visit, void *arg) { - Py_VISIT(get_posix_state(module)->billion); - Py_VISIT(get_posix_state(module)->DirEntryType); - Py_VISIT(get_posix_state(module)->ScandirIteratorType); + _posixstate *state = get_posix_state(module); + Py_VISIT(state->billion); + Py_VISIT(state->DirEntryType); + Py_VISIT(state->ScandirIteratorType); #if defined(HAVE_SCHED_SETPARAM) || defined(HAVE_SCHED_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDULER) || defined(POSIX_SPAWN_SETSCHEDPARAM) - Py_VISIT(get_posix_state(module)->SchedParamType); + Py_VISIT(state->SchedParamType); #endif - Py_VISIT(get_posix_state(module)->StatResultType); - Py_VISIT(get_posix_state(module)->StatVFSResultType); - Py_VISIT(get_posix_state(module)->TerminalSizeType); - Py_VISIT(get_posix_state(module)->TimesResultType); - Py_VISIT(get_posix_state(module)->UnameResultType); + Py_VISIT(state->StatResultType); + Py_VISIT(state->StatVFSResultType); + Py_VISIT(state->TerminalSizeType); + Py_VISIT(state->TimesResultType); + Py_VISIT(state->UnameResultType); #if defined(HAVE_WAITID) && !defined(__APPLE__) - Py_VISIT(get_posix_state(module)->WaitidResultType); + Py_VISIT(state->WaitidResultType); #endif #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4) - Py_VISIT(get_posix_state(module)->struct_rusage); + Py_VISIT(state->struct_rusage); #endif - Py_VISIT(get_posix_state(module)->st_mode); + Py_VISIT(state->st_mode); return 0; } @@ -12747,17 +12749,20 @@ DirEntry_dealloc(DirEntry *entry) /* Forward reference */ static int -DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits); +DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self, + int follow_symlinks, unsigned short mode_bits); /*[clinic input] os.DirEntry.is_symlink -> bool + defining_class: defining_class + / Return True if the entry is a symbolic link; cached per entry. [clinic start generated code]*/ static int -os_DirEntry_is_symlink_impl(DirEntry *self) -/*[clinic end generated code: output=42244667d7bcfc25 input=1605a1b4b96976c3]*/ +os_DirEntry_is_symlink_impl(DirEntry *self, PyTypeObject *defining_class) +/*[clinic end generated code: output=293096d589b6d47c input=e9acc5ee4d511113]*/ { #ifdef MS_WINDOWS return (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK; @@ -12766,21 +12771,15 @@ os_DirEntry_is_symlink_impl(DirEntry *self) if (self->d_type != DT_UNKNOWN) return self->d_type == DT_LNK; else - return DirEntry_test_mode(self, 0, S_IFLNK); + return DirEntry_test_mode(defining_class, self, 0, S_IFLNK); #else /* POSIX without d_type */ - return DirEntry_test_mode(self, 0, S_IFLNK); + return DirEntry_test_mode(defining_class, self, 0, S_IFLNK); #endif } -static inline PyObject* -DirEntry_get_module(DirEntry *self) -{ - return PyType_GetModule(Py_TYPE(self)); -} - static PyObject * -DirEntry_fetch_stat(DirEntry *self, int follow_symlinks) +DirEntry_fetch_stat(PyObject *module, DirEntry *self, int follow_symlinks) { int result; STRUCT_STAT st; @@ -12816,18 +12815,18 @@ DirEntry_fetch_stat(DirEntry *self, int follow_symlinks) if (result != 0) return path_object_error(self->path); - return _pystat_fromstructstat(DirEntry_get_module(self), &st); + return _pystat_fromstructstat(module, &st); } static PyObject * -DirEntry_get_lstat(DirEntry *self) +DirEntry_get_lstat(PyTypeObject *defining_class, DirEntry *self) { if (!self->lstat) { + PyObject *module = PyType_GetModule(defining_class); #ifdef MS_WINDOWS - self->lstat = _pystat_fromstructstat(DirEntry_get_module(self), - &self->win32_lstat); + self->lstat = _pystat_fromstructstat(module, &self->win32_lstat); #else /* POSIX */ - self->lstat = DirEntry_fetch_stat(self, 0); + self->lstat = DirEntry_fetch_stat(module, self, 0); #endif } Py_XINCREF(self->lstat); @@ -12836,6 +12835,8 @@ DirEntry_get_lstat(DirEntry *self) /*[clinic input] os.DirEntry.stat + defining_class: defining_class + / * follow_symlinks: bool = True @@ -12843,20 +12844,26 @@ Return stat_result object for the entry; cached per entry. [clinic start generated code]*/ static PyObject * -os_DirEntry_stat_impl(DirEntry *self, int follow_symlinks) -/*[clinic end generated code: output=008593b3a6d01305 input=280d14c1d6f1d00d]*/ +os_DirEntry_stat_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks) +/*[clinic end generated code: output=23f803e19c3e780e input=e816273c4e67ee98]*/ { - if (!follow_symlinks) - return DirEntry_get_lstat(self); + if (!follow_symlinks) { + return DirEntry_get_lstat(defining_class, self); + } if (!self->stat) { - int result = os_DirEntry_is_symlink_impl(self); - if (result == -1) + int result = os_DirEntry_is_symlink_impl(self, defining_class); + if (result == -1) { return NULL; - else if (result) - self->stat = DirEntry_fetch_stat(self, 1); - else - self->stat = DirEntry_get_lstat(self); + } + if (result) { + PyObject *module = PyType_GetModule(defining_class); + self->stat = DirEntry_fetch_stat(module, self, 1); + } + else { + self->stat = DirEntry_get_lstat(defining_class, self); + } } Py_XINCREF(self->stat); @@ -12865,7 +12872,8 @@ os_DirEntry_stat_impl(DirEntry *self, int follow_symlinks) /* Set exception and return -1 on error, 0 for False, 1 for True */ static int -DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits) +DirEntry_test_mode(PyTypeObject *defining_class, DirEntry *self, + int follow_symlinks, unsigned short mode_bits) { PyObject *stat = NULL; PyObject *st_mode = NULL; @@ -12890,7 +12898,7 @@ DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits #if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE) if (need_stat) { #endif - stat = os_DirEntry_stat_impl(self, follow_symlinks); + stat = os_DirEntry_stat_impl(self, defining_class, follow_symlinks); if (!stat) { if (PyErr_ExceptionMatches(PyExc_FileNotFoundError)) { /* If file doesn't exist (anymore), then return False @@ -12900,7 +12908,8 @@ DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits } goto error; } - st_mode = PyObject_GetAttr(stat, get_posix_state(DirEntry_get_module(self))->st_mode); + _posixstate* state = get_posix_state(PyType_GetModule(defining_class)); + st_mode = PyObject_GetAttr(stat, state->st_mode); if (!st_mode) goto error; @@ -12943,6 +12952,8 @@ error: /*[clinic input] os.DirEntry.is_dir -> bool + defining_class: defining_class + / * follow_symlinks: bool = True @@ -12950,14 +12961,17 @@ Return True if the entry is a directory; cached per entry. [clinic start generated code]*/ static int -os_DirEntry_is_dir_impl(DirEntry *self, int follow_symlinks) -/*[clinic end generated code: output=ad2e8d54365da287 input=0135232766f53f58]*/ +os_DirEntry_is_dir_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks) +/*[clinic end generated code: output=0cd453b9c0987fdf input=1a4ffd6dec9920cb]*/ { - return DirEntry_test_mode(self, follow_symlinks, S_IFDIR); + return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFDIR); } /*[clinic input] os.DirEntry.is_file -> bool + defining_class: defining_class + / * follow_symlinks: bool = True @@ -12965,10 +12979,11 @@ Return True if the entry is a file; cached per entry. [clinic start generated code]*/ static int -os_DirEntry_is_file_impl(DirEntry *self, int follow_symlinks) -/*[clinic end generated code: output=8462ade481d8a476 input=0dc90be168b041ee]*/ +os_DirEntry_is_file_impl(DirEntry *self, PyTypeObject *defining_class, + int follow_symlinks) +/*[clinic end generated code: output=f7c277ab5ba80908 input=0a64c5a12e802e3b]*/ { - return DirEntry_test_mode(self, follow_symlinks, S_IFREG); + return DirEntry_test_mode(defining_class, self, follow_symlinks, S_IFREG); } /*[clinic input] @@ -13496,6 +13511,8 @@ static PyType_Spec ScandirIteratorType_spec = { MODNAME ".ScandirIterator", sizeof(ScandirIterator), 0, + // bpo-40549: Py_TPFLAGS_BASETYPE should not be used, since + // PyType_GetModule(Py_TYPE(self)) doesn't work on a subclass instance. Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE, ScandirIteratorType_slots }; @@ -14785,12 +14802,10 @@ static const char * const have_functions[] = { static int posixmodule_exec(PyObject *m) { - PyObject *v; - PyObject *list; - const char * const *trace; + _posixstate *state = get_posix_state(m); /* Initialize environ dictionary */ - v = convertenviron(); + PyObject *v = convertenviron(); Py_XINCREF(v); if (v == NULL || PyModule_AddObject(m, "environ", v) != 0) return -1; @@ -14813,7 +14828,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(WaitidResultType); PyModule_AddObject(m, "waitid_result", WaitidResultType); - get_posix_state(m)->WaitidResultType = WaitidResultType; + state->WaitidResultType = WaitidResultType; #endif stat_result_desc.name = "os.stat_result"; /* see issue #19209 */ @@ -14826,7 +14841,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(StatResultType); PyModule_AddObject(m, "stat_result", StatResultType); - get_posix_state(m)->StatResultType = StatResultType; + state->StatResultType = StatResultType; structseq_new = ((PyTypeObject *)StatResultType)->tp_new; ((PyTypeObject *)StatResultType)->tp_new = statresult_new; @@ -14837,7 +14852,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(StatVFSResultType); PyModule_AddObject(m, "statvfs_result", StatVFSResultType); - get_posix_state(m)->StatVFSResultType = StatVFSResultType; + state->StatVFSResultType = StatVFSResultType; #ifdef NEED_TICKS_PER_SECOND # if defined(HAVE_SYSCONF) && defined(_SC_CLK_TCK) ticks_per_second = sysconf(_SC_CLK_TCK); @@ -14856,7 +14871,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(SchedParamType); PyModule_AddObject(m, "sched_param", SchedParamType); - get_posix_state(m)->SchedParamType = SchedParamType; + state->SchedParamType = SchedParamType; ((PyTypeObject *)SchedParamType)->tp_new = os_sched_param; #endif @@ -14867,14 +14882,14 @@ posixmodule_exec(PyObject *m) } Py_INCREF(TerminalSizeType); PyModule_AddObject(m, "terminal_size", TerminalSizeType); - get_posix_state(m)->TerminalSizeType = TerminalSizeType; + state->TerminalSizeType = TerminalSizeType; /* initialize scandir types */ PyObject *ScandirIteratorType = PyType_FromModuleAndSpec(m, &ScandirIteratorType_spec, NULL); if (ScandirIteratorType == NULL) { return -1; } - get_posix_state(m)->ScandirIteratorType = ScandirIteratorType; + state->ScandirIteratorType = ScandirIteratorType; PyObject *DirEntryType = PyType_FromModuleAndSpec(m, &DirEntryType_spec, NULL); if (DirEntryType == NULL) { @@ -14882,7 +14897,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(DirEntryType); PyModule_AddObject(m, "DirEntry", DirEntryType); - get_posix_state(m)->DirEntryType = DirEntryType; + state->DirEntryType = DirEntryType; times_result_desc.name = MODNAME ".times_result"; PyObject *TimesResultType = (PyObject *)PyStructSequence_NewType(×_result_desc); @@ -14891,7 +14906,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(TimesResultType); PyModule_AddObject(m, "times_result", TimesResultType); - get_posix_state(m)->TimesResultType = TimesResultType; + state->TimesResultType = TimesResultType; PyTypeObject *UnameResultType = PyStructSequence_NewType(&uname_result_desc); if (UnameResultType == NULL) { @@ -14899,7 +14914,7 @@ posixmodule_exec(PyObject *m) } Py_INCREF(UnameResultType); PyModule_AddObject(m, "uname_result", (PyObject *)UnameResultType); - get_posix_state(m)->UnameResultType = (PyObject *)UnameResultType; + state->UnameResultType = (PyObject *)UnameResultType; #ifdef __APPLE__ /* @@ -14939,15 +14954,15 @@ posixmodule_exec(PyObject *m) #endif /* __APPLE__ */ - if ((get_posix_state(m)->billion = PyLong_FromLong(1000000000)) == NULL) + if ((state->billion = PyLong_FromLong(1000000000)) == NULL) return -1; #if defined(HAVE_WAIT3) || defined(HAVE_WAIT4) - get_posix_state(m)->struct_rusage = PyUnicode_InternFromString("struct_rusage"); - if (get_posix_state(m)->struct_rusage == NULL) + state->struct_rusage = PyUnicode_InternFromString("struct_rusage"); + if (state->struct_rusage == NULL) return -1; #endif - get_posix_state(m)->st_mode = PyUnicode_InternFromString("st_mode"); - if (get_posix_state(m)->st_mode == NULL) + state->st_mode = PyUnicode_InternFromString("st_mode"); + if (state->st_mode == NULL) return -1; /* suppress "function not used" warnings */ @@ -14964,10 +14979,11 @@ posixmodule_exec(PyObject *m) * provide list of locally available functions * so os.py can populate support_* lists */ - list = PyList_New(0); - if (!list) + PyObject *list = PyList_New(0); + if (!list) { return -1; - for (trace = have_functions; *trace; trace++) { + } + for (const char * const *trace = have_functions; *trace; trace++) { PyObject *unicode = PyUnicode_DecodeASCII(*trace, strlen(*trace), NULL); if (!unicode) return -1; |