]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.12] gh-130163: Fix crashes related to PySys_GetObject() (GH-130503) (GH-130556...
authorSerhiy Storchaka <storchaka@gmail.com>
Wed, 26 Feb 2025 15:20:47 +0000 (17:20 +0200)
committerGitHub <noreply@github.com>
Wed, 26 Feb 2025 15:20:47 +0000 (17:20 +0200)
The use of PySys_GetObject() and _PySys_GetAttr(), which return a borrowed
reference, has been replaced by using one of the following functions, which
return a strong reference and distinguish a missing attribute from an error:
_PySys_GetOptionalAttr(), _PySys_GetOptionalAttrString(),
_PySys_GetRequiredAttr(), and _PySys_GetRequiredAttrString().

(cherry picked from commit 0ef4ffeefd1737c18dc9326133c7894d58108c2e)
(cherry picked from commit 7c1b76fce8c8df00da38830f72dbdde6881a33be)
(cherry picked from commit 2ab7e1135a2d5ca45b60881ece27729e4fc0ee8b)

21 files changed:
Include/internal/pycore_sysmodule.h
Lib/test/test_builtin.py
Lib/test/test_print.py
Lib/test/test_sys.py
Misc/NEWS.d/next/Core and Builtins/2025-02-24-14-25-36.gh-issue-130163.rGpc9v.rst [new file with mode: 0644]
Modules/_cursesmodule.c
Modules/_pickle.c
Modules/_threadmodule.c
Modules/_tkinter.c
Modules/faulthandler.c
Modules/syslogmodule.c
Python/_warnings.c
Python/bltinmodule.c
Python/errors.c
Python/import.c
Python/initconfig.c
Python/intrinsics.c
Python/pylifecycle.c
Python/pythonrun.c
Python/sysmodule.c
Python/traceback.c

index b4b1febafa447970cfb55b158d162e9fb9d96f36..e76c269100201deb4b7126979795508ab576e5ac 100644 (file)
@@ -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,
index c71c56877f690f147f95d9653de5595d36a976dc..5f2ed5c30fcde072a3fe2ee7dbd36d147ad56bd7 100644 (file)
@@ -1526,6 +1526,29 @@ class BuiltinTest(unittest.TestCase):
             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):
index 5f1bfd9e30db9810c830d6c24a3f3ce152772dba..a782225ce99971f514b710014db1b8d845742e09 100644 (file)
@@ -129,6 +129,17 @@ class TestPrint(unittest.TestCase):
                 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,
index 2f06299f6db6a92f23a3801bf22aca596ea94fb6..51afa29c567cc6389c03abb928625596ffb38c0d 100644 (file)
@@ -1,6 +1,7 @@
 import builtins
 import codecs
 import gc
+import io
 import locale
 import operator
 import os
@@ -79,6 +80,18 @@ class DisplayHookTest(unittest.TestCase):
             code = compile("42", "<string>", "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 (file)
index 0000000..590a3fa
--- /dev/null
@@ -0,0 +1,2 @@
+Fix possible crashes related to concurrent
+change and use of the :mod:`sys` module attributes.
index 3fc7f88c61ede47402c8b49783ac9d3faa57c169..26c515136973a2fd5f22509cfef5090dd1a2d489 100644 (file)
@@ -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;
         }
index b8f701c2af2e676dcf270c0d3770e572ef96dff0..c4b59700d3ef98499e82e00aab2758b02ce4df38 100644 (file)
@@ -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 <stdlib.h>               // 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__);
index 366ee6186de0d5b480480eeb0e8db2e63b3d1bfb..56a9f3d893650f3a3535138241a0f14d5218e26a 100644 (file)
@@ -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 <stddef.h>               // 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);
index 6b5fcb8a365b611ea2ccaa803cf6dffbd6480fd6..60f66a556842eb85935259b0ac979162beae9192 100644 (file)
@@ -33,6 +33,7 @@ Copyright (C) 1994 Steen Lumholt.
 #endif
 
 #include "pycore_long.h"
+#include "pycore_sysmodule.h"     // _PySys_GetOptionalAttrString()
 
 #ifdef MS_WINDOWS
 #include <windows.h>
@@ -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()) {
index f3062a71ab83bd31e0c7e0c970143d5081b57c5f..2f2b00787edd7614c3123b885b8538a78fe5c613 100644 (file)
@@ -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 <object.h>
@@ -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;
index c925a42dc05c531e3dde0c5f27f19b302ba2e417..55ed2426fb4c2551e807db7ced96f289b72d449e 100644 (file)
@@ -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 <syslog.h>
 
@@ -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
index 1f91edbf5cb5dce5f983b3a883528e695e3908a9..bcfd241df2357c64f659376030a7380461438b54 100644 (file)
@@ -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();
 }
index 8bbdba7eb9167592f11e9d98562fd4058424f541..ab87ee4fc4dfe9be37b60ceee698129ddc344a06 100644 (file)
@@ -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;
 }
 
 
index bfc37f3dbb6ff0f01cf9201620058b07b72c145f..79cf4e07f3e0107560403bc2aae9a84a2c0be018 100644 (file)
@@ -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);
index 66391c04a0baaae9a8e0bff2fececcf8753cb500..ac741cb64f6b6136326369fa98dbe4806d292622 100644 (file)
@@ -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;
 }
index 192089b5cc3e53ae34788c3dd5969574dae253e1..6eb09ab8eec3947b7b2397759e99a1ed13e5a3dc 100644 (file)
@@ -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);
 }
index c6f5ac5402d6449dae132bc6ea49d1cc39dd9d22..50b279693bf9fac376019c12438e7b005ec8a9d6 100644 (file)
@@ -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
index ef4e60765705b943e710ad4706cb369ecc54c480..f5bea14b16b401d9bfcbcc5ccd7f4c906ac9ff7f 100644 (file)
@@ -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;
 }
index cf84573a8e6147e96724e6ae0dfa1c45eb1d66ef..ac71e73311f2971a1ed72d9f37f758de0fe78f51 100644 (file)
@@ -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);
     }
 }
 
index 1f7cc655c45ed077829bbfe719baffe6d3d5ad13..e3bdff15a856bfe68d9cabcb74fe196fe64a557b 100644 (file)
@@ -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);
index fba3594e97ceac589d6e74961f13d9c73a699b91..1cb82c572037587bea78f9277b9eee2e70ca2063 100644 (file)
@@ -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 @@ error:
     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;
     }