diff -r 070cc3b9d5cc Lib/test/test_os.py --- a/Lib/test/test_os.py Wed Sep 14 15:04:33 2016 +0200 +++ b/Lib/test/test_os.py Wed Sep 14 14:13:15 2016 +0000 @@ -2165,8 +2165,8 @@ class SpawnTests(unittest.TestCase): - def create_args(self, with_env=False): - self.exitcode = 17 + def create_args(self, with_env=False, use_bytes=False): + self.exitcode = 17 filename = support.TESTFN self.addCleanup(support.unlink, filename) @@ -2185,7 +2185,13 @@ with open(filename, "w") as fp: fp.write(code) - return [sys.executable, filename] + args = [sys.executable, filename] + if use_bytes: + args = [os.fsencode(a) for a in args] + self.env = {os.fsencode(k):os.fsencode(v) + for k, v in self.env.items()} + + return args @unittest.skipUnless(hasattr(os, 'spawnl'), 'need os.spawnl') def test_spawnl(self): @@ -2248,6 +2254,13 @@ else: self.assertEqual(status, self.exitcode << 8) + @unittest.skipUnless(hasattr(os, 'spawnve'), 'need os.spawnve') + def test_spawnve_bytes(self): + # Test bytes handling in parse_arglist and parse_envlist. + # See issue 28114. + args = self.create_args(True, use_bytes=True) + exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env) + self.assertEqual(exitcode, self.exitcode) # The introduction of this TestCase caused at least two different errors on # *nix buildbots. Temporarily skip this to let the buildbots move along. diff -r 070cc3b9d5cc Modules/posixmodule.c --- a/Modules/posixmodule.c Wed Sep 14 15:04:33 2016 +0200 +++ b/Modules/posixmodule.c Wed Sep 14 14:13:15 2016 +0000 @@ -4729,28 +4729,31 @@ PyMem_DEL(array); } -static -int fsconvert_strdup(PyObject *o, EXECV_CHAR**out) +static int +fsconvert_strdup(PyObject *o, EXECV_CHAR**out) { Py_ssize_t size; + PyObject *ub; + int result = 0; #if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV) - *out = PyUnicode_AsWideCharString(o, &size); - if (!*out) + if (!PyUnicode_FSDecoder(o, &ub)) return 0; -#else - PyObject *bytes; - if (!PyUnicode_FSConverter(o, &bytes)) + *out = PyUnicode_AsWideCharString(ub, &size); + if (*out) + result = 1; +#else + if (!PyUnicode_FSConverter(o, &ub)) return 0; - size = PyBytes_GET_SIZE(bytes); - *out = PyMem_Malloc(size+1); - if (!*out) { + size = PyBytes_GET_SIZE(ub); + *out = PyMem_Malloc(size + 1); + if (*out) { + memcpy(*out, PyBytes_AS_STRING(ub), size + 1); + result = 1; + } else PyErr_NoMemory(); - return 0; - } - memcpy(*out, PyBytes_AsString(bytes), size+1); - Py_DECREF(bytes); -#endif - return 1; +#endif + Py_DECREF(ub); + return result; } #endif @@ -4760,7 +4763,7 @@ { Py_ssize_t i, pos, envc; PyObject *keys=NULL, *vals=NULL; - PyObject *key, *val, *keyval; + PyObject *key, *val, *key2, *val2, *keyval; EXECV_CHAR **envlist; i = PyMapping_Size(env); @@ -4790,15 +4793,32 @@ if (!key || !val) goto error; - keyval = PyUnicode_FromFormat("%U=%U", key, val); +#if defined(HAVE_WEXECV) || defined(HAVE_WSPAWNV) + if (!PyUnicode_FSDecoder(key, &key2)) + goto error; + if (!PyUnicode_FSDecoder(val, &val2)) { + Py_DECREF(key2); + goto error; + } + keyval = PyUnicode_FromFormat("%U=%U", key2, val2); +#else + if (!PyUnicode_FSConverter(key, &key2)) + goto error; + if (!PyUnicode_FSConverter(val, &val2)) { + Py_DECREF(key2); + goto error; + } + keyval = PyBytes_FromFormat("%s=%s", PyBytes_AS_STRING(key2), + PyBytes_AS_STRING(val2)); +#endif + Py_DECREF(key2); + Py_DECREF(val2); if (!keyval) goto error; - if (!fsconvert_strdup(keyval, &envlist[envc++])) { Py_DECREF(keyval); goto error; } - Py_DECREF(keyval); } Py_DECREF(vals);