diff --git a/Lib/test/test_os.py b/Lib/test/test_os.py index b9e2f320082..f95d286e646 100644 --- a/Lib/test/test_os.py +++ b/Lib/test/test_os.py @@ -447,6 +447,15 @@ class EnvironTests(mapping_tests.BasicTestMappingProtocol): value_str = value.decode(sys.getfilesystemencoding(), 'surrogateescape') self.assertEqual(os.environ['bytes'], value_str) + def test_unset_error(self): + if sys.platform == "win32": + # an environment variable is limited to 32,767 characters + key = 'x' * 50000 + else: + # "=" is not allowed in a variable name + key = 'key=' + self.assertRaises(OSError, os.environ.__delitem__, key) + class WalkTests(unittest.TestCase): """Tests for os.walk().""" diff --git a/Misc/NEWS b/Misc/NEWS index adc434c3cdb..ababd791d57 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -387,6 +387,8 @@ Core and Builtins Library ------- +- Issue #13415: os.unsetenv() doesn't ignore errors anymore. + - Issue #13245: sched.scheduler class constructor's timefunc and delayfunct parameters are now optional. scheduler.enter and scheduler.enterabs methods gained a new kwargs parameter. diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index fe924915ee7..094d0711726 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7749,61 +7749,28 @@ static PyObject *posix_putenv_garbage; static PyObject * posix_putenv(PyObject *self, PyObject *args) { -#ifdef MS_WINDOWS - PyObject *s1, *s2; - wchar_t *newenv; -#else - PyObject *os1, *os2; - char *s1, *s2; - char *newenv; - size_t len; -#endif PyObject *newstr = NULL; - #ifdef MS_WINDOWS + PyObject *os1, *os2; + wchar_t *newenv; + if (!PyArg_ParseTuple(args, "UU:putenv", - &s1, &s2)) + &os1, &os2)) return NULL; -#else - if (!PyArg_ParseTuple(args, - "O&O&:putenv", - PyUnicode_FSConverter, &os1, - PyUnicode_FSConverter, &os2)) - return NULL; - s1 = PyBytes_AsString(os1); - s2 = PyBytes_AsString(os2); -#endif -#if defined(PYOS_OS2) - if (stricmp(s1, "BEGINLIBPATH") == 0) { - APIRET rc; - - rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH); - if (rc != NO_ERROR) { - os2_error(rc); - goto error; - } - - } else if (stricmp(s1, "ENDLIBPATH") == 0) { - APIRET rc; - - rc = DosSetExtLIBPATH(s2, END_LIBPATH); - if (rc != NO_ERROR) { - os2_error(rc); - goto error; - } - } else { -#endif - /* XXX This can leak memory -- not easy to fix :-( */ - /* len includes space for a trailing \0; the size arg to - PyBytes_FromStringAndSize does not count that */ -#ifdef MS_WINDOWS - newstr = PyUnicode_FromFormat("%U=%U", s1, s2); + newstr = PyUnicode_FromFormat("%U=%U", os1, os2); if (newstr == NULL) { PyErr_NoMemory(); goto error; } + if (_MAX_ENV < PyUnicode_GET_LENGTH(newstr)) { + PyErr_Format(PyExc_ValueError, + "the environment variable is longer than %u characters", + _MAX_ENV); + goto error; + } + newenv = PyUnicode_AsUnicode(newstr); if (newenv == NULL) goto error; @@ -7812,15 +7779,25 @@ posix_putenv(PyObject *self, PyObject *args) goto error; } #else - len = PyBytes_GET_SIZE(os1) + PyBytes_GET_SIZE(os2) + 2; - newstr = PyBytes_FromStringAndSize(NULL, (int)len - 1); + PyObject *os1, *os2; + char *s1, *s2; + char *newenv; + + if (!PyArg_ParseTuple(args, + "O&O&:putenv", + PyUnicode_FSConverter, &os1, + PyUnicode_FSConverter, &os2)) + return NULL; + s1 = PyBytes_AsString(os1); + s2 = PyBytes_AsString(os2); + + newstr = PyBytes_FromFormat("%s=%s", s1, s2); if (newstr == NULL) { PyErr_NoMemory(); goto error; } newenv = PyBytes_AS_STRING(newstr); - PyOS_snprintf(newenv, len, "%s=%s", s1, s2); if (putenv(newenv)) { posix_error(); goto error; @@ -7831,13 +7808,7 @@ posix_putenv(PyObject *self, PyObject *args) * this will cause previous value to be collected. This has to * happen after the real putenv() call because the old value * was still accessible until then. */ - if (PyDict_SetItem(posix_putenv_garbage, -#ifdef MS_WINDOWS - PyTuple_GET_ITEM(args, 0), -#else - os1, -#endif - newstr)) { + if (PyDict_SetItem(posix_putenv_garbage, os1, newstr)) { /* really not much we can do; just leak */ PyErr_Clear(); } @@ -7845,10 +7816,6 @@ posix_putenv(PyObject *self, PyObject *args) Py_DECREF(newstr); } -#if defined(PYOS_OS2) - } -#endif - #ifndef MS_WINDOWS Py_DECREF(os1); Py_DECREF(os2); @@ -7873,42 +7840,27 @@ Delete an environment variable."); static PyObject * posix_unsetenv(PyObject *self, PyObject *args) { -#ifdef MS_WINDOWS - char *s1; - - if (!PyArg_ParseTuple(args, "s:unsetenv", &s1)) - return NULL; -#else - PyObject *os1; - char *s1; + PyObject *name; + int err; if (!PyArg_ParseTuple(args, "O&:unsetenv", - PyUnicode_FSConverter, &os1)) + PyUnicode_FSConverter, &name)) return NULL; - s1 = PyBytes_AsString(os1); -#endif - unsetenv(s1); + err = unsetenv(PyBytes_AS_STRING(name)); + if (err) + return posix_error(); /* Remove the key from posix_putenv_garbage; * this will cause it to be collected. This has to * happen after the real unsetenv() call because the * old value was still accessible until then. */ - if (PyDict_DelItem(posix_putenv_garbage, -#ifdef MS_WINDOWS - PyTuple_GET_ITEM(args, 0) -#else - os1 -#endif - )) { + if (PyDict_DelItem(posix_putenv_garbage, name)) { /* really not much we can do; just leak */ PyErr_Clear(); } - -#ifndef MS_WINDOWS - Py_DECREF(os1); -#endif + Py_DECREF(name); Py_RETURN_NONE; } #endif /* unsetenv */