diff --git a/Include/internal/pycore_sysmodule.h b/Include/internal/pycore_sysmodule.h index b4b1febafa4479..e76c269100201d 100644 --- a/Include/internal/pycore_sysmodule.h +++ b/Include/internal/pycore_sysmodule.h @@ -8,6 +8,11 @@ extern "C" { # error "this header requires Py_BUILD_CORE define" #endif +PyAPI_FUNC(int) _PySys_GetOptionalAttr(PyObject *, PyObject **); +PyAPI_FUNC(int) _PySys_GetOptionalAttrString(const char *, PyObject **); +PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttr(PyObject *); +PyAPI_FUNC(PyObject *) _PySys_GetRequiredAttrString(const char *); + PyAPI_FUNC(int) _PySys_Audit( PyThreadState *tstate, const char *event, diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py index c71c56877f690f..5f2ed5c30fcde0 100644 --- a/Lib/test/test_builtin.py +++ b/Lib/test/test_builtin.py @@ -1526,6 +1526,29 @@ def test_input(self): sys.stdout = savestdout fp.close() + def test_input_gh130163(self): + class X(io.StringIO): + def __getattribute__(self, name): + nonlocal patch + if patch: + patch = False + sys.stdout = X() + sys.stderr = X() + sys.stdin = X('input\n') + support.gc_collect() + return io.StringIO.__getattribute__(self, name) + + with (support.swap_attr(sys, 'stdout', None), + support.swap_attr(sys, 'stderr', None), + support.swap_attr(sys, 'stdin', None)): + patch = False + # the only references: + sys.stdout = X() + sys.stderr = X() + sys.stdin = X('input\n') + patch = True + input() # should not crash + # test_int(): see test_int.py for tests of built-in function int(). def test_repr(self): diff --git a/Lib/test/test_print.py b/Lib/test/test_print.py index 5f1bfd9e30db98..a782225ce99971 100644 --- a/Lib/test/test_print.py +++ b/Lib/test/test_print.py @@ -129,6 +129,17 @@ def flush(self): raise RuntimeError self.assertRaises(RuntimeError, print, 1, file=noflush(), flush=True) + def test_gh130163(self): + class X: + def __str__(self): + sys.stdout = StringIO() + support.gc_collect() + return 'foo' + + with support.swap_attr(sys, 'stdout', None): + sys.stdout = StringIO() # the only reference + print(X()) # should not crash + class TestPy2MigrationHint(unittest.TestCase): """Test that correct hint is produced analogous to Python3 syntax, diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 2f06299f6db6a9..51afa29c567cc6 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1,6 +1,7 @@ import builtins import codecs import gc +import io import locale import operator import os @@ -79,6 +80,18 @@ def baddisplayhook(obj): code = compile("42", "", "single") self.assertRaises(ValueError, eval, code) + def test_gh130163(self): + class X: + def __repr__(self): + sys.stdout = io.StringIO() + support.gc_collect() + return 'foo' + + with support.swap_attr(sys, 'stdout', None): + sys.stdout = io.StringIO() # the only reference + sys.displayhook(X()) # should not crash + + class ActiveExceptionTests(unittest.TestCase): def test_exc_info_no_exception(self): self.assertEqual(sys.exc_info(), (None, None, None)) diff --git a/Misc/NEWS.d/next/Core and Builtins/2025-02-24-14-25-36.gh-issue-130163.rGpc9v.rst b/Misc/NEWS.d/next/Core and Builtins/2025-02-24-14-25-36.gh-issue-130163.rGpc9v.rst new file mode 100644 index 00000000000000..590a3fa437b936 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2025-02-24-14-25-36.gh-issue-130163.rGpc9v.rst @@ -0,0 +1,2 @@ +Fix possible crashes related to concurrent +change and use of the :mod:`sys` module attributes. diff --git a/Modules/_cursesmodule.c b/Modules/_cursesmodule.c index 3fc7f88c61ede4..26c515136973a2 100644 --- a/Modules/_cursesmodule.c +++ b/Modules/_cursesmodule.c @@ -109,6 +109,7 @@ static const char PyCursesVersion[] = "2.2"; #include "Python.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_structseq.h" // _PyStructSequence_NewType() +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() #ifdef __hpux #define STRICT_SYSV_CURSES @@ -3375,17 +3376,20 @@ _curses_setupterm_impl(PyObject *module, const char *term, int fd) if (fd == -1) { PyObject* sys_stdout; - sys_stdout = PySys_GetObject("stdout"); + if (_PySys_GetOptionalAttrString("stdout", &sys_stdout) < 0) { + return NULL; + } if (sys_stdout == NULL || sys_stdout == Py_None) { PyErr_SetString( PyCursesError, "lost sys.stdout"); + Py_XDECREF(sys_stdout); return NULL; } fd = PyObject_AsFileDescriptor(sys_stdout); - + Py_DECREF(sys_stdout); if (fd == -1) { return NULL; } diff --git a/Modules/_pickle.c b/Modules/_pickle.c index b8f701c2af2e67..c4b59700d3ef98 100644 --- a/Modules/_pickle.c +++ b/Modules/_pickle.c @@ -13,6 +13,7 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_runtime.h" // _Py_ID() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() #include "structmember.h" // PyMemberDef #include // strtol() @@ -1984,19 +1985,19 @@ whichmodule(PyObject *global, PyObject *dotted_path) assert(module_name == NULL); /* Fallback on walking sys.modules */ - PyThreadState *tstate = _PyThreadState_GET(); - modules = _PySys_GetAttr(tstate, &_Py_ID(modules)); + modules = _PySys_GetRequiredAttr(&_Py_ID(modules)); if (modules == NULL) { - PyErr_SetString(PyExc_RuntimeError, "unable to get sys.modules"); return NULL; } if (PyDict_CheckExact(modules)) { i = 0; while (PyDict_Next(modules, &i, &module_name, &module)) { if (_checkmodule(module_name, module, global, dotted_path) == 0) { + Py_DECREF(modules); return Py_NewRef(module_name); } if (PyErr_Occurred()) { + Py_DECREF(modules); return NULL; } } @@ -2004,6 +2005,7 @@ whichmodule(PyObject *global, PyObject *dotted_path) else { PyObject *iterator = PyObject_GetIter(modules); if (iterator == NULL) { + Py_DECREF(modules); return NULL; } while ((module_name = PyIter_Next(iterator))) { @@ -2011,22 +2013,26 @@ whichmodule(PyObject *global, PyObject *dotted_path) if (module == NULL) { Py_DECREF(module_name); Py_DECREF(iterator); + Py_DECREF(modules); return NULL; } if (_checkmodule(module_name, module, global, dotted_path) == 0) { Py_DECREF(module); Py_DECREF(iterator); + Py_DECREF(modules); return module_name; } Py_DECREF(module); Py_DECREF(module_name); if (PyErr_Occurred()) { Py_DECREF(iterator); + Py_DECREF(modules); return NULL; } } Py_DECREF(iterator); } + Py_DECREF(modules); /* If no module is found, use __main__. */ module_name = &_Py_ID(__main__); diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c index 366ee6186de0d5..56a9f3d893650f 100644 --- a/Modules/_threadmodule.c +++ b/Modules/_threadmodule.c @@ -7,6 +7,8 @@ #include "pycore_moduleobject.h" // _PyModule_GetState() #include "pycore_pylifecycle.h" #include "pycore_pystate.h" // _PyThreadState_SetCurrent() +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttr() + #include // offsetof() #include "structmember.h" // PyMemberDef @@ -1567,9 +1569,12 @@ thread_excepthook(PyObject *module, PyObject *args) PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2); PyObject *thread = PyStructSequence_GET_ITEM(args, 3); - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *file; + if (_PySys_GetOptionalAttr( &_Py_ID(stderr), &file) < 0) { + return NULL; + } if (file == NULL || file == Py_None) { + Py_XDECREF(file); if (thread == Py_None) { /* do nothing if sys.stderr is None and thread is None */ Py_RETURN_NONE; @@ -1586,9 +1591,6 @@ thread_excepthook(PyObject *module, PyObject *args) Py_RETURN_NONE; } } - else { - Py_INCREF(file); - } int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb, thread); diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c index 6b5fcb8a365b61..60f66a556842eb 100644 --- a/Modules/_tkinter.c +++ b/Modules/_tkinter.c @@ -33,6 +33,7 @@ Copyright (C) 1994 Steen Lumholt. #endif #include "pycore_long.h" +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() #ifdef MS_WINDOWS #include @@ -154,9 +155,11 @@ _get_tcl_lib_path(void) /* Check expected location for an installed Python first */ tcl_library_path = PyUnicode_FromString("\\tcl\\tcl" TCL_VERSION); if (tcl_library_path == NULL) { + Py_DECREF(prefix); return NULL; } tcl_library_path = PyUnicode_Concat(prefix, tcl_library_path); + Py_DECREF(prefix); if (tcl_library_path == NULL) { return NULL; } @@ -3509,6 +3512,7 @@ PyInit__tkinter(void) uexe = PyUnicode_FromWideChar(Py_GetProgramName(), -1); if (uexe) { cexe = PyUnicode_EncodeFSDefault(uexe); + Py_DECREF(uexe); if (cexe) { #ifdef MS_WINDOWS int set_var = 0; @@ -3521,12 +3525,14 @@ PyInit__tkinter(void) if (!ret && GetLastError() == ERROR_ENVVAR_NOT_FOUND) { str_path = _get_tcl_lib_path(); if (str_path == NULL && PyErr_Occurred()) { + Py_DECREF(cexe); Py_DECREF(m); return NULL; } if (str_path != NULL) { wcs_path = PyUnicode_AsWideCharString(str_path, NULL); if (wcs_path == NULL) { + Py_DECREF(cexe); Py_DECREF(m); return NULL; } @@ -3546,7 +3552,6 @@ PyInit__tkinter(void) #endif /* MS_WINDOWS */ } Py_XDECREF(cexe); - Py_DECREF(uexe); } if (PyErr_Occurred()) { diff --git a/Modules/faulthandler.c b/Modules/faulthandler.c index f3062a71ab83bd..2f2b00787edd76 100644 --- a/Modules/faulthandler.c +++ b/Modules/faulthandler.c @@ -3,6 +3,7 @@ #include "pycore_pyerrors.h" // _Py_DumpExtensionModules #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_signal.h" // Py_NSIG +#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() #include "pycore_traceback.h" // _Py_DumpTracebackThreads #include @@ -104,14 +105,13 @@ faulthandler_get_fileno(PyObject **file_ptr) PyObject *file = *file_ptr; if (file == NULL || file == Py_None) { - PyThreadState *tstate = _PyThreadState_GET(); - file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + file = _PySys_GetRequiredAttr(&_Py_ID(stderr)); if (file == NULL) { - PyErr_SetString(PyExc_RuntimeError, "unable to get sys.stderr"); return -1; } if (file == Py_None) { PyErr_SetString(PyExc_RuntimeError, "sys.stderr is None"); + Py_DECREF(file); return -1; } } @@ -127,10 +127,15 @@ faulthandler_get_fileno(PyObject **file_ptr) *file_ptr = NULL; return fd; } + else { + Py_INCREF(file); + } result = PyObject_CallMethodNoArgs(file, &_Py_ID(fileno)); - if (result == NULL) + if (result == NULL) { + Py_DECREF(file); return -1; + } fd = -1; if (PyLong_Check(result)) { @@ -143,6 +148,7 @@ faulthandler_get_fileno(PyObject **file_ptr) if (fd == -1) { PyErr_SetString(PyExc_RuntimeError, "file.fileno() is not a valid file descriptor"); + Py_DECREF(file); return -1; } @@ -225,19 +231,23 @@ faulthandler_dump_traceback_py(PyObject *self, return NULL; tstate = get_thread_state(); - if (tstate == NULL) + if (tstate == NULL) { + Py_XDECREF(file); return NULL; + } if (all_threads) { errmsg = _Py_DumpTracebackThreads(fd, NULL, tstate); if (errmsg != NULL) { PyErr_SetString(PyExc_RuntimeError, errmsg); + Py_XDECREF(file); return NULL; } } else { _Py_DumpTraceback(fd, tstate); } + Py_XDECREF(file); if (PyErr_CheckSignals()) return NULL; @@ -499,10 +509,11 @@ faulthandler_py_enable(PyObject *self, PyObject *args, PyObject *kwargs) return NULL; tstate = get_thread_state(); - if (tstate == NULL) + if (tstate == NULL) { + Py_XDECREF(file); return NULL; + } - Py_XINCREF(file); Py_XSETREF(fatal_error.file, file); fatal_error.fd = fd; fatal_error.all_threads = all_threads; @@ -692,12 +703,14 @@ faulthandler_dump_traceback_later(PyObject *self, if (!thread.running) { thread.running = PyThread_allocate_lock(); if (!thread.running) { + Py_XDECREF(file); return PyErr_NoMemory(); } } if (!thread.cancel_event) { thread.cancel_event = PyThread_allocate_lock(); if (!thread.cancel_event || !thread.running) { + Py_XDECREF(file); return PyErr_NoMemory(); } @@ -709,6 +722,7 @@ faulthandler_dump_traceback_later(PyObject *self, /* format the timeout */ header = format_timeout(timeout_us); if (header == NULL) { + Py_XDECREF(file); return PyErr_NoMemory(); } header_len = strlen(header); @@ -716,7 +730,6 @@ faulthandler_dump_traceback_later(PyObject *self, /* Cancel previous thread, if running */ cancel_dump_traceback_later(); - Py_XINCREF(file); Py_XSETREF(thread.file, file); thread.fd = fd; /* the downcast is safe: we check that 0 < timeout_us < PY_TIMEOUT_MAX */ @@ -878,14 +891,17 @@ faulthandler_register_py(PyObject *self, if (user_signals == NULL) { user_signals = PyMem_Calloc(Py_NSIG, sizeof(user_signal_t)); - if (user_signals == NULL) + if (user_signals == NULL) { + Py_XDECREF(file); return PyErr_NoMemory(); + } } user = &user_signals[signum]; if (!user->enabled) { #ifdef FAULTHANDLER_USE_ALT_STACK if (faulthandler_allocate_stack() < 0) { + Py_XDECREF(file); return NULL; } #endif @@ -893,13 +909,13 @@ faulthandler_register_py(PyObject *self, err = faulthandler_register(signum, chain, &previous); if (err) { PyErr_SetFromErrno(PyExc_OSError); + Py_XDECREF(file); return NULL; } user->previous = previous; } - Py_XINCREF(file); Py_XSETREF(user->file, file); user->fd = fd; user->all_threads = all_threads; diff --git a/Modules/syslogmodule.c b/Modules/syslogmodule.c index c925a42dc05c53..55ed2426fb4c25 100644 --- a/Modules/syslogmodule.c +++ b/Modules/syslogmodule.c @@ -49,8 +49,13 @@ Revision history: /* syslog module */ +#ifndef Py_BUILD_CORE_BUILTIN +# define Py_BUILD_CORE_MODULE 1 +#endif + #include "Python.h" #include "osdefs.h" // SEP +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() #include @@ -84,45 +89,50 @@ syslog_get_argv(void) Py_ssize_t argv_len, scriptlen; PyObject *scriptobj; Py_ssize_t slash; - PyObject *argv = PySys_GetObject("argv"); + PyObject *argv; - if (argv == NULL) { - return(NULL); + if (_PySys_GetOptionalAttrString("argv", &argv) <= 0) { + return NULL; } argv_len = PyList_Size(argv); if (argv_len == -1) { PyErr_Clear(); - return(NULL); + Py_DECREF(argv); + return NULL; } if (argv_len == 0) { - return(NULL); + Py_DECREF(argv); + return NULL; } scriptobj = PyList_GetItem(argv, 0); + Py_XINCREF(scriptobj); + Py_DECREF(argv); if (scriptobj == NULL) { PyErr_Clear(); return NULL; } if (!PyUnicode_Check(scriptobj)) { - return(NULL); + Py_DECREF(scriptobj); + return NULL; } scriptlen = PyUnicode_GET_LENGTH(scriptobj); if (scriptlen == 0) { - return(NULL); + Py_DECREF(scriptobj); + return NULL; } slash = PyUnicode_FindChar(scriptobj, SEP, 0, scriptlen, -1); if (slash == -2) { PyErr_Clear(); + Py_DECREF(scriptobj); return NULL; } if (slash != -1) { - return PyUnicode_Substring(scriptobj, slash + 1, scriptlen); - } else { - Py_INCREF(scriptobj); - return(scriptobj); + Py_SETREF(scriptobj, PyUnicode_Substring(scriptobj, slash + 1, scriptlen)); } + return scriptobj; } @@ -156,6 +166,9 @@ syslog_openlog_impl(PyObject *module, PyObject *ident, long logopt, else { /* get sys.argv[0] or NULL if we can't for some reason */ ident = syslog_get_argv(); + if (ident == NULL && PyErr_Occurred()) { + return NULL; + } } /* At this point, ident should be INCREF()ed. openlog(3) does not diff --git a/Python/_warnings.c b/Python/_warnings.c index 1f91edbf5cb5dc..bcfd241df2357c 100644 --- a/Python/_warnings.c +++ b/Python/_warnings.c @@ -5,6 +5,8 @@ #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_frame.h" +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttr() + #include "clinic/_warnings.c.h" #define MODULE_NAME "_warnings" @@ -493,7 +495,7 @@ static void show_warning(PyThreadState *tstate, PyObject *filename, int lineno, PyObject *text, PyObject *category, PyObject *sourceline) { - PyObject *f_stderr; + PyObject *f_stderr = NULL; PyObject *name; char lineno_str[128]; @@ -504,8 +506,7 @@ show_warning(PyThreadState *tstate, PyObject *filename, int lineno, goto error; } - f_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); - if (f_stderr == NULL) { + if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &f_stderr) <= 0) { fprintf(stderr, "lost sys.stderr\n"); goto error; } @@ -558,6 +559,7 @@ show_warning(PyThreadState *tstate, PyObject *filename, int lineno, } error: + Py_XDECREF(f_stderr); Py_XDECREF(name); PyErr_Clear(); } diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 8bbdba7eb91675..ab87ee4fc4dfe9 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -9,6 +9,7 @@ #include "pycore_object.h" // _Py_AddToAllObjects() #include "pycore_pyerrors.h" // _PyErr_NoMemory() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() #include "pycore_tuple.h" // _PyTuple_FromArray() #include "pycore_ceval.h" // _PyEval_Vector() @@ -455,18 +456,16 @@ builtin_callable(PyObject *module, PyObject *obj) static PyObject * builtin_breakpoint(PyObject *self, PyObject *const *args, Py_ssize_t nargs, PyObject *keywords) { - PyObject *hook = PySys_GetObject("breakpointhook"); - + PyObject *hook = _PySys_GetRequiredAttrString("breakpointhook"); if (hook == NULL) { - PyErr_SetString(PyExc_RuntimeError, "lost sys.breakpointhook"); return NULL; } if (PySys_Audit("builtins.breakpoint", "O", hook) < 0) { + Py_DECREF(hook); return NULL; } - Py_INCREF(hook); PyObject *retval = PyObject_Vectorcall(hook, args, nargs, keywords); Py_DECREF(hook); return retval; @@ -2003,18 +2002,20 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, int i, err; if (file == Py_None) { - PyThreadState *tstate = _PyThreadState_GET(); - file = _PySys_GetAttr(tstate, &_Py_ID(stdout)); + file = _PySys_GetRequiredAttr(&_Py_ID(stdout)); if (file == NULL) { - PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); return NULL; } /* sys.stdout may be None when FILE* stdout isn't connected */ if (file == Py_None) { + Py_DECREF(file); Py_RETURN_NONE; } } + else { + Py_INCREF(file); + } if (sep == Py_None) { sep = NULL; @@ -2023,6 +2024,7 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, PyErr_Format(PyExc_TypeError, "sep must be None or a string, not %.200s", Py_TYPE(sep)->tp_name); + Py_DECREF(file); return NULL; } if (end == Py_None) { @@ -2032,6 +2034,7 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, PyErr_Format(PyExc_TypeError, "end must be None or a string, not %.200s", Py_TYPE(end)->tp_name); + Py_DECREF(file); return NULL; } @@ -2044,11 +2047,13 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, err = PyFile_WriteObject(sep, file, Py_PRINT_RAW); } if (err) { + Py_DECREF(file); return NULL; } } err = PyFile_WriteObject(PyTuple_GET_ITEM(args, i), file, Py_PRINT_RAW); if (err) { + Py_DECREF(file); return NULL; } } @@ -2060,16 +2065,19 @@ builtin_print_impl(PyObject *module, PyObject *args, PyObject *sep, err = PyFile_WriteObject(end, file, Py_PRINT_RAW); } if (err) { + Py_DECREF(file); return NULL; } if (flush) { PyObject *tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (tmp == NULL) { + Py_DECREF(file); return NULL; } Py_DECREF(tmp); } + Py_DECREF(file); Py_RETURN_NONE; } @@ -2094,36 +2102,41 @@ static PyObject * builtin_input_impl(PyObject *module, PyObject *prompt) /*[clinic end generated code: output=83db5a191e7a0d60 input=159c46d4ae40977e]*/ { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *fin = _PySys_GetAttr( - tstate, &_Py_ID(stdin)); - PyObject *fout = _PySys_GetAttr( - tstate, &_Py_ID(stdout)); - PyObject *ferr = _PySys_GetAttr( - tstate, &_Py_ID(stderr)); + PyObject *fin = NULL; + PyObject *fout = NULL; + PyObject *ferr = NULL; PyObject *tmp; long fd; int tty; /* Check that stdin/out/err are intact */ - if (fin == NULL || fin == Py_None) { - PyErr_SetString(PyExc_RuntimeError, - "input(): lost sys.stdin"); - return NULL; + fin = _PySys_GetRequiredAttr(&_Py_ID(stdin)); + if (fin == NULL) { + goto error; } - if (fout == NULL || fout == Py_None) { - PyErr_SetString(PyExc_RuntimeError, - "input(): lost sys.stdout"); - return NULL; + if (fin == Py_None) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.stdin"); + goto error; } - if (ferr == NULL || ferr == Py_None) { - PyErr_SetString(PyExc_RuntimeError, - "input(): lost sys.stderr"); - return NULL; + fout = _PySys_GetRequiredAttr(&_Py_ID(stdout)); + if (fout == NULL) { + goto error; + } + if (fout == Py_None) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); + goto error; + } + ferr = _PySys_GetRequiredAttr(&_Py_ID(stderr)); + if (ferr == NULL) { + goto error; + } + if (ferr == Py_None) { + PyErr_SetString(PyExc_RuntimeError, "lost sys.stderr"); + goto error; } if (PySys_Audit("builtins.input", "O", prompt ? prompt : Py_None) < 0) { - return NULL; + goto error; } /* First of all, flush stderr */ @@ -2144,8 +2157,9 @@ builtin_input_impl(PyObject *module, PyObject *prompt) else { fd = PyLong_AsLong(tmp); Py_DECREF(tmp); - if (fd < 0 && PyErr_Occurred()) - return NULL; + if (fd < 0 && PyErr_Occurred()) { + goto error; + } tty = fd == fileno(stdin) && isatty(fd); } if (tty) { @@ -2158,7 +2172,7 @@ builtin_input_impl(PyObject *module, PyObject *prompt) fd = PyLong_AsLong(tmp); Py_DECREF(tmp); if (fd < 0 && PyErr_Occurred()) - return NULL; + goto error; tty = fd == fileno(stdout) && isatty(fd); } } @@ -2283,10 +2297,13 @@ builtin_input_impl(PyObject *module, PyObject *prompt) if (result != NULL) { if (PySys_Audit("builtins.input/result", "O", result) < 0) { - return NULL; + goto error; } } + Py_DECREF(fin); + Py_DECREF(fout); + Py_DECREF(ferr); return result; _readline_errors: @@ -2296,7 +2313,7 @@ builtin_input_impl(PyObject *module, PyObject *prompt) Py_XDECREF(stdout_errors); Py_XDECREF(po); if (tty) - return NULL; + goto error; PyErr_Clear(); } @@ -2304,14 +2321,25 @@ builtin_input_impl(PyObject *module, PyObject *prompt) /* Fallback if we're not interactive */ if (prompt != NULL) { if (PyFile_WriteObject(prompt, fout, Py_PRINT_RAW) != 0) - return NULL; + goto error; } tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); if (tmp == NULL) PyErr_Clear(); else Py_DECREF(tmp); - return PyFile_GetLine(fin, -1); + + tmp = PyFile_GetLine(fin, -1); + Py_DECREF(fin); + Py_DECREF(fout); + Py_DECREF(ferr); + return tmp; + +error: + Py_XDECREF(fin); + Py_XDECREF(fout); + Py_XDECREF(ferr); + return NULL; } diff --git a/Python/errors.c b/Python/errors.c index bfc37f3dbb6ff0..79cf4e07f3e010 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -1562,14 +1562,15 @@ write_unraisable_exc(PyThreadState *tstate, PyObject *exc_type, PyObject *exc_value, PyObject *exc_tb, PyObject *err_msg, PyObject *obj) { - PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *file; + if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) { + return -1; + } if (file == NULL || file == Py_None) { + Py_XDECREF(file); return 0; } - /* Hold a strong reference to ensure that sys.stderr doesn't go away - while we use it */ - Py_INCREF(file); int res = write_unraisable_exc_file(tstate, exc_type, exc_value, exc_tb, err_msg, obj, file); Py_DECREF(file); @@ -1666,13 +1667,20 @@ _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj) goto error; } - PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(unraisablehook)); + PyObject *hook; + if (_PySys_GetOptionalAttr(&_Py_ID(unraisablehook), &hook) < 0) { + Py_DECREF(hook_args); + err_msg_str = NULL; + obj = NULL; + goto error; + } if (hook == NULL) { Py_DECREF(hook_args); goto default_hook; } if (_PySys_Audit(tstate, "sys.unraisablehook", "OO", hook, hook_args) < 0) { + Py_DECREF(hook); Py_DECREF(hook_args); err_msg_str = "Exception ignored in audit hook"; obj = NULL; @@ -1680,11 +1688,13 @@ _PyErr_WriteUnraisableMsg(const char *err_msg_str, PyObject *obj) } if (hook == Py_None) { + Py_DECREF(hook); Py_DECREF(hook_args); goto default_hook; } PyObject *res = PyObject_CallOneArg(hook, hook_args); + Py_DECREF(hook); Py_DECREF(hook_args); if (res != NULL) { Py_DECREF(res); diff --git a/Python/import.c b/Python/import.c index 66391c04a0baaa..ac741cb64f6b61 100644 --- a/Python/import.c +++ b/Python/import.c @@ -2431,19 +2431,15 @@ PyObject * PyImport_GetImporter(PyObject *path) { PyThreadState *tstate = _PyThreadState_GET(); - PyObject *path_importer_cache = PySys_GetObject("path_importer_cache"); + PyObject *path_importer_cache = _PySys_GetRequiredAttrString("path_importer_cache"); if (path_importer_cache == NULL) { - PyErr_SetString(PyExc_RuntimeError, "lost sys.path_importer_cache"); return NULL; } - Py_INCREF(path_importer_cache); - PyObject *path_hooks = PySys_GetObject("path_hooks"); + PyObject *path_hooks = _PySys_GetRequiredAttrString("path_hooks"); if (path_hooks == NULL) { - PyErr_SetString(PyExc_RuntimeError, "lost sys.path_hooks"); Py_DECREF(path_importer_cache); return NULL; } - Py_INCREF(path_hooks); PyObject *importer = get_path_importer(tstate, path_importer_cache, path_hooks, path); Py_DECREF(path_hooks); Py_DECREF(path_importer_cache); @@ -2745,15 +2741,31 @@ import_find_and_load(PyThreadState *tstate, PyObject *abs_name) _PyTime_t t1 = 0, accumulated_copy = accumulated; - PyObject *sys_path = PySys_GetObject("path"); - PyObject *sys_meta_path = PySys_GetObject("meta_path"); - PyObject *sys_path_hooks = PySys_GetObject("path_hooks"); + PyObject *sys_path, *sys_meta_path, *sys_path_hooks; + if (_PySys_GetOptionalAttrString("path", &sys_path) < 0) { + return NULL; + } + if (_PySys_GetOptionalAttrString("meta_path", &sys_meta_path) < 0) { + Py_XDECREF(sys_path); + return NULL; + } + if (_PySys_GetOptionalAttrString("path_hooks", &sys_path_hooks) < 0) { + Py_XDECREF(sys_meta_path); + Py_XDECREF(sys_path); + return NULL; + } if (_PySys_Audit(tstate, "import", "OOOOO", abs_name, Py_None, sys_path ? sys_path : Py_None, sys_meta_path ? sys_meta_path : Py_None, sys_path_hooks ? sys_path_hooks : Py_None) < 0) { + Py_XDECREF(sys_path_hooks); + Py_XDECREF(sys_meta_path); + Py_XDECREF(sys_path); return NULL; } + Py_XDECREF(sys_path_hooks); + Py_XDECREF(sys_meta_path); + Py_XDECREF(sys_path); /* XOptions is initialized after first some imports. @@ -3207,10 +3219,8 @@ _PyImport_FiniCore(PyInterpreterState *interp) static int init_zipimport(PyThreadState *tstate, int verbose) { - PyObject *path_hooks = PySys_GetObject("path_hooks"); + PyObject *path_hooks = _PySys_GetRequiredAttrString("path_hooks"); if (path_hooks == NULL) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "unable to get sys.path_hooks"); return -1; } @@ -3230,12 +3240,14 @@ init_zipimport(PyThreadState *tstate, int verbose) int err = PyList_Insert(path_hooks, 0, zipimporter); Py_DECREF(zipimporter); if (err < 0) { + Py_DECREF(path_hooks); return -1; } if (verbose) { PySys_WriteStderr("# installed zipimport hook\n"); } } + Py_DECREF(path_hooks); return 0; } diff --git a/Python/initconfig.c b/Python/initconfig.c index 192089b5cc3e53..6eb09ab8eec394 100644 --- a/Python/initconfig.c +++ b/Python/initconfig.c @@ -9,6 +9,7 @@ #include "pycore_pylifecycle.h" // _Py_PreInitializeFromConfig() #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttrString() #include "osdefs.h" // DELIM @@ -3144,10 +3145,13 @@ _Py_DumpPathConfig(PyThreadState *tstate) #define DUMP_SYS(NAME) \ do { \ - obj = PySys_GetObject(#NAME); \ PySys_FormatStderr(" sys.%s = ", #NAME); \ + if (_PySys_GetOptionalAttrString(#NAME, &obj) < 0) { \ + PyErr_Clear(); \ + } \ if (obj != NULL) { \ PySys_FormatStderr("%A", obj); \ + Py_DECREF(obj); \ } \ else { \ PySys_WriteStderr("(not set)"); \ @@ -3165,7 +3169,8 @@ _Py_DumpPathConfig(PyThreadState *tstate) DUMP_SYS(exec_prefix); #undef DUMP_SYS - PyObject *sys_path = PySys_GetObject("path"); /* borrowed reference */ + PyObject *sys_path; + (void) _PySys_GetOptionalAttrString("path", &sys_path); if (sys_path != NULL && PyList_Check(sys_path)) { PySys_WriteStderr(" sys.path = [\n"); Py_ssize_t len = PyList_GET_SIZE(sys_path); @@ -3175,6 +3180,7 @@ _Py_DumpPathConfig(PyThreadState *tstate) } PySys_WriteStderr(" ]\n"); } + Py_XDECREF(sys_path); _PyErr_SetRaisedException(tstate, exc); } diff --git a/Python/intrinsics.c b/Python/intrinsics.c index c6f5ac5402d644..50b279693bf9fa 100644 --- a/Python/intrinsics.c +++ b/Python/intrinsics.c @@ -8,6 +8,7 @@ #include "pycore_global_objects.h" #include "pycore_intrinsics.h" #include "pycore_pyerrors.h" +#include "pycore_sysmodule.h" // _PySys_GetRequiredAttr() #include "pycore_typevarobject.h" @@ -21,16 +22,16 @@ no_intrinsic(PyThreadState* tstate, PyObject *unused) } static PyObject * -print_expr(PyThreadState* tstate, PyObject *value) +print_expr(PyThreadState* Py_UNUSED(ignored), PyObject *value) { - PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(displayhook)); + PyObject *hook = _PySys_GetRequiredAttr(&_Py_ID(displayhook)); // Can't use ERROR_IF here. if (hook == NULL) { - _PyErr_SetString(tstate, PyExc_RuntimeError, - "lost sys.displayhook"); return NULL; } - return PyObject_CallOneArg(hook, value); + PyObject *res = PyObject_CallOneArg(hook, value); + Py_DECREF(hook); + return res; } static int diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index ef4e60765705b9..f5bea14b16b401 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1189,8 +1189,12 @@ init_interp_main(PyThreadState *tstate) if (is_main_interp) { /* Initialize warnings. */ - PyObject *warnoptions = PySys_GetObject("warnoptions"); - if (warnoptions != NULL && PyList_Size(warnoptions) > 0) + PyObject *warnoptions; + if (_PySys_GetOptionalAttrString("warnoptions", &warnoptions) < 0) { + return _PyStatus_ERR("can't initialize warnings"); + } + if (warnoptions != NULL && PyList_Check(warnoptions) && + PyList_Size(warnoptions) > 0) { PyObject *warnings_module = PyImport_ImportModule("warnings"); if (warnings_module == NULL) { @@ -1199,6 +1203,7 @@ init_interp_main(PyThreadState *tstate) } Py_XDECREF(warnings_module); } + Py_XDECREF(warnoptions); interp->runtime->initialized = 1; } @@ -1667,24 +1672,32 @@ file_is_closed(PyObject *fobj) static int flush_std_files(void) { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *fout = _PySys_GetAttr(tstate, &_Py_ID(stdout)); - PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *file; PyObject *tmp; int status = 0; - if (fout != NULL && fout != Py_None && !file_is_closed(fout)) { - tmp = PyObject_CallMethodNoArgs(fout, &_Py_ID(flush)); + if (_PySys_GetOptionalAttr(&_Py_ID(stdout), &file) < 0) { + status = -1; + } + else if (file != NULL && file != Py_None && !file_is_closed(file)) { + tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (tmp == NULL) { - PyErr_WriteUnraisable(fout); status = -1; } else Py_DECREF(tmp); } + if (status < 0) { + PyErr_WriteUnraisable(file); + } + Py_XDECREF(file); - if (ferr != NULL && ferr != Py_None && !file_is_closed(ferr)) { - tmp = PyObject_CallMethodNoArgs(ferr, &_Py_ID(flush)); + if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) { + PyErr_Clear(); + status = -1; + } + else if (file != NULL && file != Py_None && !file_is_closed(file)) { + tmp = PyObject_CallMethodNoArgs(file, &_Py_ID(flush)); if (tmp == NULL) { PyErr_Clear(); status = -1; @@ -1692,6 +1705,7 @@ flush_std_files(void) else Py_DECREF(tmp); } + Py_XDECREF(file); return status; } @@ -2655,10 +2669,14 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) return 0; } - PyObject *ferr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *ferr; + if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &ferr) < 0) { + _PyErr_Clear(tstate); + } if (ferr == NULL || ferr == Py_None) { /* sys.stderr is not set yet or set to None, no need to try to display the exception */ + Py_XDECREF(ferr); Py_DECREF(exc); return 0; } @@ -2678,6 +2696,7 @@ _Py_FatalError_PrintExc(PyThreadState *tstate) else { Py_DECREF(res); } + Py_DECREF(ferr); return has_tb; } diff --git a/Python/pythonrun.c b/Python/pythonrun.c index cf84573a8e6147..ac71e73311f297 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -115,17 +115,35 @@ _PyRun_InteractiveLoopObject(FILE *fp, PyObject *filename, PyCompilerFlags *flag flags = &local_flags; } - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *v = _PySys_GetAttr(tstate, &_Py_ID(ps1)); + PyObject *v; + if (_PySys_GetOptionalAttr(&_Py_ID(ps1), &v) < 0) { + PyErr_Print(); + return -1; + } if (v == NULL) { - _PySys_SetAttr(&_Py_ID(ps1), v = PyUnicode_FromString(">>> ")); - Py_XDECREF(v); + v = PyUnicode_FromString(">>> "); + if (v == NULL) { + PyErr_Clear(); + } + if (_PySys_SetAttr(&_Py_ID(ps1), v) < 0) { + PyErr_Clear(); + } + } + Py_XDECREF(v); + if (_PySys_GetOptionalAttr(&_Py_ID(ps2), &v) < 0) { + PyErr_Print(); + return -1; } - v = _PySys_GetAttr(tstate, &_Py_ID(ps2)); if (v == NULL) { - _PySys_SetAttr(&_Py_ID(ps2), v = PyUnicode_FromString("... ")); - Py_XDECREF(v); + v = PyUnicode_FromString("... "); + if (v == NULL) { + PyErr_Clear(); + } + if (_PySys_SetAttr(&_Py_ID(ps2), v) < 0) { + PyErr_Clear(); + } } + Py_XDECREF(v); #ifdef Py_REF_DEBUG int show_ref_count = _Py_GetConfig()->show_ref_count; @@ -190,11 +208,12 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, PyArena *arena; const char *ps1 = "", *ps2 = "", *enc = NULL; int errcode = 0; - PyThreadState *tstate = _PyThreadState_GET(); if (fp == stdin) { /* Fetch encoding from sys.stdin if possible. */ - v = _PySys_GetAttr(tstate, &_Py_ID(stdin)); + if (_PySys_GetOptionalAttr(&_Py_ID(stdin), &v) < 0) { + return -1; + } if (v && v != Py_None) { oenc = PyObject_GetAttr(v, &_Py_ID(encoding)); if (oenc) @@ -202,10 +221,14 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, if (!enc) PyErr_Clear(); } + Py_XDECREF(v); + } + if (_PySys_GetOptionalAttr(&_Py_ID(ps1), &v) < 0) { + Py_XDECREF(oenc); + return -1; } - v = _PySys_GetAttr(tstate, &_Py_ID(ps1)); if (v != NULL) { - v = PyObject_Str(v); + Py_SETREF(v, PyObject_Str(v)); if (v == NULL) PyErr_Clear(); else if (PyUnicode_Check(v)) { @@ -216,9 +239,12 @@ PyRun_InteractiveOneObjectEx(FILE *fp, PyObject *filename, } } } - w = _PySys_GetAttr(tstate, &_Py_ID(ps2)); + if (_PySys_GetOptionalAttr(&_Py_ID(ps2), &w) < 0) { + Py_XDECREF(oenc); + return -1; + } if (w != NULL) { - w = PyObject_Str(w); + Py_SETREF(w, PyObject_Str(w)); if (w == NULL) PyErr_Clear(); else if (PyUnicode_Check(w)) { @@ -718,8 +744,8 @@ _Py_HandleSystemExit(int *exitcode_p) exitcode = (int)PyLong_AsLong(exc); } else { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *sys_stderr; + (void) _PySys_GetOptionalAttr(&_Py_ID(stderr), &sys_stderr); /* We clear the exception here to avoid triggering the assertion * in PyObject_Str that ensures it won't silently lose exception * details. @@ -731,6 +757,7 @@ _Py_HandleSystemExit(int *exitcode_p) PyObject_Print(exc, stderr, Py_PRINT_RAW); fflush(stderr); } + Py_XDECREF(sys_stderr); PySys_WriteStderr("\n"); exitcode = 1; } @@ -755,7 +782,7 @@ handle_system_exit(void) static void _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) { - PyObject *typ = NULL, *tb = NULL; + PyObject *typ = NULL, *tb = NULL, *hook = NULL; handle_system_exit(); PyObject *exc = _PyErr_GetRaisedException(tstate); @@ -784,7 +811,9 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) _PyErr_Clear(tstate); } } - PyObject *hook = _PySys_GetAttr(tstate, &_Py_ID(excepthook)); + if (_PySys_GetOptionalAttr(&_Py_ID(excepthook), &hook) < 0) { + PyErr_Clear(); + } if (_PySys_Audit(tstate, "sys.excepthook", "OOOO", hook ? hook : Py_None, typ, exc, tb) < 0) { if (PyErr_ExceptionMatches(PyExc_RuntimeError)) { @@ -821,6 +850,7 @@ _PyErr_PrintEx(PyThreadState *tstate, int set_sys_last_vars) } done: + Py_XDECREF(hook); Py_XDECREF(typ); Py_XDECREF(exc); Py_XDECREF(tb); @@ -1567,17 +1597,24 @@ _PyErr_Display(PyObject *file, PyObject *unused, PyObject *value, PyObject *tb) void PyErr_Display(PyObject *unused, PyObject *value, PyObject *tb) { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *file = _PySys_GetAttr(tstate, &_Py_ID(stderr)); + PyObject *file; + if (_PySys_GetOptionalAttr(&_Py_ID(stderr), &file) < 0) { + PyObject *exc = PyErr_GetRaisedException(); + _PyObject_Dump(value); + fprintf(stderr, "lost sys.stderr\n"); + _PyObject_Dump(exc); + Py_DECREF(exc); + return; + } if (file == NULL) { _PyObject_Dump(value); fprintf(stderr, "lost sys.stderr\n"); return; } if (file == Py_None) { + Py_DECREF(file); return; } - Py_INCREF(file); _PyErr_Display(file, NULL, value, tb); Py_DECREF(file); } @@ -1664,7 +1701,10 @@ PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, static void flush_io_stream(PyThreadState *tstate, PyObject *name) { - PyObject *f = _PySys_GetAttr(tstate, name); + PyObject *f; + if (_PySys_GetOptionalAttr(name, &f) < 0) { + PyErr_Clear(); + } if (f != NULL) { PyObject *r = _PyObject_CallMethodNoArgs(f, &_Py_ID(flush)); if (r) { @@ -1673,6 +1713,7 @@ flush_io_stream(PyThreadState *tstate, PyObject *name) else { PyErr_Clear(); } + Py_DECREF(f); } } diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 1f7cc655c45ed0..e3bdff15a856bf 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -29,6 +29,7 @@ Data members: #include "pycore_pymem.h" // _PyMem_SetDefaultAllocator() #include "pycore_pystate.h" // _PyThreadState_GET() #include "pycore_structseq.h" // _PyStructSequence_InitBuiltinWithFlags() +#include "pycore_sysmodule.h" #include "pycore_tuple.h" // _PyTuple_FromArray() #include "frameobject.h" // PyFrame_FastToLocalsWithError() @@ -78,23 +79,97 @@ _PySys_GetAttr(PyThreadState *tstate, PyObject *name) return value; } -static PyObject * -_PySys_GetObject(PyInterpreterState *interp, const char *name) + PyObject * +_PySys_GetRequiredAttr(PyObject *name) { - PyObject *sysdict = interp->sysdict; + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + Py_TYPE(name)->tp_name); + return NULL; + } + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *sysdict = tstate->interp->sysdict; if (sysdict == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no sys module"); return NULL; } - return _PyDict_GetItemStringWithError(sysdict, name); + PyObject *value = _PyDict_GetItemWithError(sysdict, name); + Py_XINCREF(value); + if (value == NULL && !_PyErr_Occurred(tstate)) { + PyErr_Format(PyExc_RuntimeError, "lost sys.%U", name); + } + return value; } PyObject * -PySys_GetObject(const char *name) +_PySys_GetRequiredAttrString(const char *name) { PyThreadState *tstate = _PyThreadState_GET(); + PyObject *sysdict = tstate->interp->sysdict; + if (sysdict == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no sys module"); + return NULL; + } + PyObject *value = _PyDict_GetItemStringWithError(sysdict, name); + Py_XINCREF(value); + if (value == NULL && !_PyErr_Occurred(tstate)) { + PyErr_Format(PyExc_RuntimeError, "lost sys.%s", name); + } + return value; +} +int +_PySys_GetOptionalAttr(PyObject *name, PyObject **value) +{ + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, + "attribute name must be string, not '%.200s'", + Py_TYPE(name)->tp_name); + *value = NULL; + return -1; + } + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *sysdict = tstate->interp->sysdict; + if (sysdict == NULL) { + *value = NULL; + return 0; + } + *value = _PyDict_GetItemWithError(sysdict, name); + if (*value) { + Py_INCREF(*value); + return 1; + } + return _PyErr_Occurred(tstate) ? -1 : 0; +} + +int +_PySys_GetOptionalAttrString(const char *name, PyObject **value) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *sysdict = tstate->interp->sysdict; + if (sysdict == NULL) { + *value = NULL; + return 0; + } + *value = _PyDict_GetItemStringWithError(sysdict, name); + if (*value) { + Py_INCREF(*value); + return 1; + } + return _PyErr_Occurred(tstate) ? -1 : 0; +} + +PyObject * +PySys_GetObject(const char *name) +{ + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *sysdict = tstate->interp->sysdict; + if (sysdict == NULL) { + return NULL; + } PyObject *exc = _PyErr_GetRaisedException(tstate); - PyObject *value = _PySys_GetObject(tstate->interp, name); + PyObject *value = _PyDict_GetItemStringWithError(sysdict, name); /* XXX Suppress a new exception if it was raised and restore * the old one. */ _PyErr_SetRaisedException(tstate, exc); @@ -108,6 +183,10 @@ sys_set_object(PyInterpreterState *interp, PyObject *key, PyObject *v) return -1; } PyObject *sd = interp->sysdict; + if (sd == NULL) { + PyErr_SetString(PyExc_RuntimeError, "no sys module"); + return -1; + } if (v == NULL) { v = _PyDict_Pop(sd, key, Py_None); if (v == NULL) { @@ -724,9 +803,13 @@ sys_displayhook(PyObject *module, PyObject *o) } if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), Py_None) != 0) return NULL; - outf = _PySys_GetAttr(tstate, &_Py_ID(stdout)); - if (outf == NULL || outf == Py_None) { + outf = _PySys_GetRequiredAttr(&_Py_ID(stdout)); + if (outf == NULL) { + return NULL; + } + if (outf == Py_None) { _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.stdout"); + Py_DECREF(outf); return NULL; } if (PyFile_WriteObject(o, outf, 0) != 0) { @@ -737,17 +820,23 @@ sys_displayhook(PyObject *module, PyObject *o) _PyErr_Clear(tstate); err = sys_displayhook_unencodable(outf, o); if (err) { + Py_DECREF(outf); return NULL; } } else { + Py_DECREF(outf); return NULL; } } - if (PyFile_WriteObject(_Py_LATIN1_CHR('\n'), outf, Py_PRINT_RAW) != 0) + if (PyFile_WriteObject(_Py_LATIN1_CHR('\n'), outf, Py_PRINT_RAW) != 0) { + Py_DECREF(outf); return NULL; - if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), o) != 0) + } + Py_DECREF(outf); + if (PyObject_SetAttr(builtins, _Py_LATIN1_CHR('_'), o) != 0) { return NULL; + } Py_RETURN_NONE; } @@ -2610,7 +2699,10 @@ _PySys_ReadPreinitXOptions(PyConfig *config) static PyObject * get_warnoptions(PyThreadState *tstate) { - PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); + PyObject *warnoptions; + if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) { + return NULL; + } if (warnoptions == NULL || !PyList_Check(warnoptions)) { /* PEP432 TODO: we can reach this if warnoptions is NULL in the main * interpreter config. When that happens, we need to properly set @@ -2622,6 +2714,7 @@ get_warnoptions(PyThreadState *tstate) * call optional for embedding applications, thus making this * reachable again. */ + Py_XDECREF(warnoptions); warnoptions = PyList_New(0); if (warnoptions == NULL) { return NULL; @@ -2630,7 +2723,6 @@ get_warnoptions(PyThreadState *tstate) Py_DECREF(warnoptions); return NULL; } - Py_DECREF(warnoptions); } return warnoptions; } @@ -2644,10 +2736,15 @@ PySys_ResetWarnOptions(void) return; } - PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); - if (warnoptions == NULL || !PyList_Check(warnoptions)) + PyObject *warnoptions; + if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) { + PyErr_Clear(); return; - PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); + } + if (warnoptions != NULL && PyList_Check(warnoptions)) { + PyList_SetSlice(warnoptions, 0, PyList_GET_SIZE(warnoptions), NULL); + } + Py_XDECREF(warnoptions); } static int @@ -2659,8 +2756,10 @@ _PySys_AddWarnOptionWithError(PyThreadState *tstate, PyObject *option) return -1; } if (PyList_Append(warnoptions, option)) { + Py_DECREF(warnoptions); return -1; } + Py_DECREF(warnoptions); return 0; } @@ -2698,16 +2797,24 @@ _Py_COMP_DIAG_POP int PySys_HasWarnOptions(void) { - PyThreadState *tstate = _PyThreadState_GET(); - PyObject *warnoptions = _PySys_GetAttr(tstate, &_Py_ID(warnoptions)); - return (warnoptions != NULL && PyList_Check(warnoptions) - && PyList_GET_SIZE(warnoptions) > 0); + PyObject *warnoptions; + if (_PySys_GetOptionalAttr(&_Py_ID(warnoptions), &warnoptions) < 0) { + PyErr_Clear(); + return 0; + } + int r = (warnoptions != NULL && PyList_Check(warnoptions) && + PyList_GET_SIZE(warnoptions) > 0); + Py_XDECREF(warnoptions); + return r; } static PyObject * get_xoptions(PyThreadState *tstate) { - PyObject *xoptions = _PySys_GetAttr(tstate, &_Py_ID(_xoptions)); + PyObject *xoptions; + if (_PySys_GetOptionalAttr(&_Py_ID(_xoptions), &xoptions) < 0) { + return NULL; + } if (xoptions == NULL || !PyDict_Check(xoptions)) { /* PEP432 TODO: we can reach this if xoptions is NULL in the main * interpreter config. When that happens, we need to properly set @@ -2719,6 +2826,7 @@ get_xoptions(PyThreadState *tstate) * call optional for embedding applications, thus making this * reachable again. */ + Py_XDECREF(xoptions); xoptions = PyDict_New(); if (xoptions == NULL) { return NULL; @@ -2727,7 +2835,6 @@ get_xoptions(PyThreadState *tstate) Py_DECREF(xoptions); return NULL; } - Py_DECREF(xoptions); } return xoptions; } @@ -2766,11 +2873,13 @@ _PySys_AddXOptionWithError(const wchar_t *s) } Py_DECREF(name); Py_DECREF(value); + Py_DECREF(opts); return 0; error: Py_XDECREF(name); Py_XDECREF(value); + Py_XDECREF(opts); return -1; } @@ -2792,7 +2901,9 @@ PyObject * PySys_GetXOptions(void) { PyThreadState *tstate = _PyThreadState_GET(); - return get_xoptions(tstate); + PyObject *opts = get_xoptions(tstate); + Py_XDECREF(opts); + return opts; } /* XXX This doc string is too long to be a single string literal in VC++ 5.0. @@ -3517,16 +3628,15 @@ _PySys_UpdateConfig(PyThreadState *tstate) #undef COPY_WSTR // sys.flags - PyObject *flags = _PySys_GetObject(interp, "flags"); // borrowed ref + PyObject *flags = _PySys_GetRequiredAttrString("flags"); if (flags == NULL) { - if (!_PyErr_Occurred(tstate)) { - _PyErr_SetString(tstate, PyExc_RuntimeError, "lost sys.flags"); - } return -1; } if (set_flags_from_config(interp, flags) < 0) { + Py_DECREF(flags); return -1; } + Py_DECREF(flags); SET_SYS("dont_write_bytecode", PyBool_FromLong(!config->write_bytecode)); @@ -3754,12 +3864,15 @@ PySys_SetArgvEx(int argc, wchar_t **argv, int updatepath) Py_FatalError("can't compute path0 from argv"); } - PyObject *sys_path = _PySys_GetAttr(tstate, &_Py_ID(path)); - if (sys_path != NULL) { + PyObject *sys_path; + if (_PySys_GetOptionalAttr(&_Py_ID(path), &sys_path) < 0) { + Py_FatalError("can't get sys.path"); + } + else if (sys_path != NULL) { if (PyList_Insert(sys_path, 0, path0) < 0) { - Py_DECREF(path0); Py_FatalError("can't prepend path0 to sys.path"); } + Py_DECREF(sys_path); } Py_DECREF(path0); } @@ -3847,8 +3960,8 @@ sys_write(PyObject *key, FILE *fp, const char *format, va_list va) PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); - file = _PySys_GetAttr(tstate, key); written = PyOS_vsnprintf(buffer, sizeof(buffer), format, va); + file = _PySys_GetRequiredAttr(key); if (sys_pyfile_write(buffer, file) != 0) { _PyErr_Clear(tstate); fputs(buffer, fp); @@ -3858,6 +3971,7 @@ sys_write(PyObject *key, FILE *fp, const char *format, va_list va) if (sys_pyfile_write(truncated, file) != 0) fputs(truncated, fp); } + Py_XDECREF(file); _PyErr_SetRaisedException(tstate, exc); } @@ -3889,15 +4003,16 @@ sys_format(PyObject *key, FILE *fp, const char *format, va_list va) PyThreadState *tstate = _PyThreadState_GET(); PyObject *exc = _PyErr_GetRaisedException(tstate); - file = _PySys_GetAttr(tstate, key); message = PyUnicode_FromFormatV(format, va); if (message != NULL) { + file = _PySys_GetRequiredAttr(key); if (sys_pyfile_write_unicode(message, file) != 0) { _PyErr_Clear(tstate); utf8 = PyUnicode_AsUTF8(message); if (utf8 != NULL) fputs(utf8, fp); } + Py_XDECREF(file); Py_DECREF(message); } _PyErr_SetRaisedException(tstate, exc); diff --git a/Python/traceback.c b/Python/traceback.c index fba3594e97ceac..1cb82c57203758 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -13,6 +13,7 @@ #include "pycore_pyarena.h" // _PyArena_Free() #include "pycore_pyerrors.h" // _PyErr_GetRaisedException() #include "pycore_pystate.h" // _PyThreadState_GET() +#include "pycore_sysmodule.h" // _PySys_GetOptionalAttr() #include "pycore_traceback.h" // EXCEPTION_TB_HEADER #include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset() @@ -349,9 +350,13 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * taillen = strlen(tail); PyThreadState *tstate = _PyThreadState_GET(); - syspath = _PySys_GetAttr(tstate, &_Py_ID(path)); - if (syspath == NULL || !PyList_Check(syspath)) + if (_PySys_GetOptionalAttr(&_Py_ID(path), &syspath) < 0) { + PyErr_Clear(); + goto error; + } + if (syspath == NULL || !PyList_Check(syspath)) { goto error; + } npath = PyList_Size(syspath); open = PyObject_GetAttr(io, &_Py_ID(open)); @@ -394,6 +399,7 @@ _Py_FindSourceFile(PyObject *filename, char* namebuf, size_t namelen, PyObject * result = NULL; finally: Py_XDECREF(open); + Py_XDECREF(syspath); Py_DECREF(filebytes); return result; } @@ -1064,17 +1070,21 @@ _PyTraceBack_Print_Indented(PyObject *v, int indent, const char *margin, PyErr_BadInternalCall(); return -1; } - limitv = PySys_GetObject("tracebacklimit"); - if (limitv && PyLong_Check(limitv)) { + if (_PySys_GetOptionalAttrString("tracebacklimit", &limitv) < 0) { + return -1; + } + else if (limitv != NULL && PyLong_Check(limitv)) { int overflow; limit = PyLong_AsLongAndOverflow(limitv, &overflow); if (overflow > 0) { limit = LONG_MAX; } else if (limit <= 0) { + Py_DECREF(limitv); return 0; } } + Py_XDECREF(limitv); if (_Py_WriteIndentedMargin(indent, header_margin, f) < 0) { return -1; }