diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-01-20-13-13-33.bpo-39395.-Khif5.rst b/Misc/NEWS.d/next/Core and Builtins/2020-01-20-13-13-33.bpo-39395.-Khif5.rst new file mode 100644 index 00000000000000..f4f92b6cd766e7 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-01-20-13-13-33.bpo-39395.-Khif5.rst @@ -0,0 +1,2 @@ +Environment variables set by :data:`os.environ` and :func:`os.putenv` are now +cleared at exit. Python manages their memory which is released at exit. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 322c2159812cdd..c278839b9a43c6 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -2101,10 +2101,36 @@ statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds) return (PyObject*)result; } + +#ifdef HAVE_UNSETENV +/* bpo-39395: Clear environment variables set by os.environ and os.putenv() + before clearing posix_putenv_garbage dictionary. Python manages the + variables memory which is cleared at exit. */ +static void +posix_unset_envvars(PyObject *posix_putenv_garbage) +{ + if (posix_putenv_garbage == NULL) { + return; + } + assert(PyDict_CheckExact(posix_putenv_garbage)); + + Py_ssize_t pos = 0; + PyObject *key, *value; + while (PyDict_Next(posix_putenv_garbage, &pos, &key, &value)) { + /* ignore unsetenv() error */ + unsetenv(PyBytes_AS_STRING(key)); + } +} +#endif + + static int _posix_clear(PyObject *module) { Py_CLEAR(_posixstate(module)->billion); +#ifdef HAVE_UNSETENV + posix_unset_envvars(_posixstate(module)->posix_putenv_garbage); +#endif Py_CLEAR(_posixstate(module)->posix_putenv_garbage); Py_CLEAR(_posixstate(module)->DirEntryType); Py_CLEAR(_posixstate(module)->ScandirIteratorType);