]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Issue #28732: Raise ValueError when argv[0] is empty
authorSteve Dower <steve.dower@microsoft.com>
Sun, 20 Nov 2016 03:17:26 +0000 (19:17 -0800)
committerSteve Dower <steve.dower@microsoft.com>
Sun, 20 Nov 2016 03:17:26 +0000 (19:17 -0800)
1  2 
Lib/test/test_os.py
Modules/posixmodule.c

index 9194a8a2beb39168cf4fe2eb813176e5c9f2cee4,10383cfc1f0e9358c52eef194eb96cdaec311ec9..e9fdb0719f4bf4267d0c51bbbe5f53e861bcb6f6
@@@ -1481,8 -1442,8 +1481,16 @@@ class ExecTests(unittest.TestCase)
          self.assertRaises(OSError, os.execvpe, 'no such app-',
                            ['no such app-'], None)
  
++    def test_execv_with_bad_arglist(self):
++        self.assertRaises(ValueError, os.execv, 'notepad', ())
++        self.assertRaises(ValueError, os.execv, 'notepad', [])
++        self.assertRaises(ValueError, os.execv, 'notepad', ('',))
++        self.assertRaises(ValueError, os.execv, 'notepad', [''])
++
      def test_execvpe_with_bad_arglist(self):
          self.assertRaises(ValueError, os.execvpe, 'notepad', [], None)
++        self.assertRaises(ValueError, os.execvpe, 'notepad', [], {})
++        self.assertRaises(ValueError, os.execvpe, 'notepad', [''], {})
  
      @unittest.skipUnless(hasattr(os, '_execvpe'),
                           "No internal os._execvpe function to test.")
@@@ -2224,125 -2182,6 +2232,131 @@@ class PidTests(unittest.TestCase)
          self.assertEqual(status, (pid, 0))
  
  
-     def test_spawnl_noargs(self):
 +class SpawnTests(unittest.TestCase):
 +    def create_args(self, *, with_env=False, use_bytes=False):
 +        self.exitcode = 17
 +
 +        filename = support.TESTFN
 +        self.addCleanup(support.unlink, filename)
 +
 +        if not with_env:
 +            code = 'import sys; sys.exit(%s)' % self.exitcode
 +        else:
 +            self.env = dict(os.environ)
 +            # create an unique key
 +            self.key = str(uuid.uuid4())
 +            self.env[self.key] = self.key
 +            # read the variable from os.environ to check that it exists
 +            code = ('import sys, os; magic = os.environ[%r]; sys.exit(%s)'
 +                    % (self.key, self.exitcode))
 +
 +        with open(filename, "w") as fp:
 +            fp.write(code)
 +
 +        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
 +
 +    @requires_os_func('spawnl')
 +    def test_spawnl(self):
 +        args = self.create_args()
 +        exitcode = os.spawnl(os.P_WAIT, args[0], *args)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnle')
 +    def test_spawnle(self):
 +        args = self.create_args(with_env=True)
 +        exitcode = os.spawnle(os.P_WAIT, args[0], *args, self.env)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnlp')
 +    def test_spawnlp(self):
 +        args = self.create_args()
 +        exitcode = os.spawnlp(os.P_WAIT, args[0], *args)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnlpe')
 +    def test_spawnlpe(self):
 +        args = self.create_args(with_env=True)
 +        exitcode = os.spawnlpe(os.P_WAIT, args[0], *args, self.env)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnv')
 +    def test_spawnv(self):
 +        args = self.create_args()
 +        exitcode = os.spawnv(os.P_WAIT, args[0], args)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnve')
 +    def test_spawnve(self):
 +        args = self.create_args(with_env=True)
 +        exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnvp')
 +    def test_spawnvp(self):
 +        args = self.create_args()
 +        exitcode = os.spawnvp(os.P_WAIT, args[0], args)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnvpe')
 +    def test_spawnvpe(self):
 +        args = self.create_args(with_env=True)
 +        exitcode = os.spawnvpe(os.P_WAIT, args[0], args, self.env)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnv')
 +    def test_nowait(self):
 +        args = self.create_args()
 +        pid = os.spawnv(os.P_NOWAIT, args[0], args)
 +        result = os.waitpid(pid, 0)
 +        self.assertEqual(result[0], pid)
 +        status = result[1]
 +        if hasattr(os, 'WIFEXITED'):
 +            self.assertTrue(os.WIFEXITED(status))
 +            self.assertEqual(os.WEXITSTATUS(status), self.exitcode)
 +        else:
 +            self.assertEqual(status, self.exitcode << 8)
 +
 +    @requires_os_func('spawnve')
 +    def test_spawnve_bytes(self):
 +        # Test bytes handling in parse_arglist and parse_envlist (#28114)
 +        args = self.create_args(with_env=True, use_bytes=True)
 +        exitcode = os.spawnve(os.P_WAIT, args[0], args, self.env)
 +        self.assertEqual(exitcode, self.exitcode)
 +
 +    @requires_os_func('spawnl')
 +    def test_spawnl_noargs(self):
 +        args = self.create_args()
 +        self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0])
++        self.assertRaises(ValueError, os.spawnl, os.P_NOWAIT, args[0], '')
 +
 +    @requires_os_func('spawnle')
-     def test_spawnv_noargs(self):
++    def test_spawnle_noargs(self):
 +        args = self.create_args()
 +        self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], {})
++        self.assertRaises(ValueError, os.spawnle, os.P_NOWAIT, args[0], '', {})
 +
 +    @requires_os_func('spawnv')
 +    def test_spawnv_noargs(self):
 +        args = self.create_args()
 +        self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ())
 +        self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], [])
++        self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], ('',))
++        self.assertRaises(ValueError, os.spawnv, os.P_NOWAIT, args[0], [''])
 +
 +    @requires_os_func('spawnve')
++    def test_spawnve_noargs(self):
 +        args = self.create_args()
 +        self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], (), {})
 +        self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [], {})
++        self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], ('',), {})
++        self.assertRaises(ValueError, os.spawnve, os.P_NOWAIT, args[0], [''], {})
 +
  # The introduction of this TestCase caused at least two different errors on
  # *nix buildbots. Temporarily skip this to let the buildbots move along.
  @unittest.skip("Skip due to platform/environment differences on *NIX buildbots")
index 0482f2bbd034cf1ebcbcc94325b38d1b1835f424,3e446a524e9e93e1c4fd5f661691ae27c1e944bf..acef3c31e8b5dd356da6675ffb1ed83d0bd8880b
@@@ -4916,12 -5065,8 +4916,20 @@@ os_execv_impl(PyObject *module, path_t 
      if (argvlist == NULL) {
          return NULL;
      }
++    if (!argvlist[0][0]) {
++        PyErr_SetString(PyExc_ValueError,
++            "execv() arg 2 first element cannot be empty");
++        free_string_array(argvlist, argc);
++        return NULL;
++    }
  
 -    execv(path_char, argvlist);
++    _Py_BEGIN_SUPPRESS_IPH
 +#ifdef HAVE_WEXECV
 +    _wexecv(path->wide, argvlist);
 +#else
 +    execv(path->narrow, argvlist);
 +#endif
++    _Py_END_SUPPRESS_IPH
  
      /* If we get here it's definitely an error */
  
@@@ -4961,6 -5106,6 +4969,11 @@@ os_execve_impl(PyObject *module, path_
          goto fail;
      }
      argc = PySequence_Size(argv);
++    if (argc < 1) {
++        PyErr_SetString(PyExc_ValueError, "execve: argv must not be empty");
++        return NULL;
++    }
++
      if (!PyMapping_Check(env)) {
          PyErr_SetString(PyExc_TypeError,
                          "execve: environment must be a mapping object");
      if (argvlist == NULL) {
          goto fail;
      }
++    if (!argvlist[0][0]) {
++        PyErr_SetString(PyExc_ValueError,
++            "execve: argv first element cannot be empty");
++        goto fail;
++    }
  
      envlist = parse_envlist(env, &envc);
      if (envlist == NULL)
          goto fail;
  
++    _Py_BEGIN_SUPPRESS_IPH
  #ifdef HAVE_FEXECVE
      if (path->fd > -1)
          fexecve(path->fd, argvlist, envlist);
      else
  #endif
 +#ifdef HAVE_WEXECV
 +        _wexecve(path->wide, argvlist, envlist);
 +#else
          execve(path->narrow, argvlist, envlist);
 +#endif
++    _Py_END_SUPPRESS_IPH
  
      /* If we get here it's definitely an error */
  
@@@ -5061,6 -5210,15 +5081,13 @@@ os_spawnv_impl(PyObject *module, int mo
                  "spawnv() arg 2 must contain only strings");
              return NULL;
          }
 -#ifdef MS_WINDOWS
+         if (i == 0 && !argvlist[0][0]) {
+             free_string_array(argvlist, i);
+             PyErr_SetString(
+                 PyExc_ValueError,
+                 "spawnv() arg 2 first element cannot be empty");
+             return NULL;
+         }
 -#endif
      }
      argvlist[argc] = NULL;
  
@@@ -5155,6 -5306,6 +5182,13 @@@ os_spawnve_impl(PyObject *module, int m
              lastarg = i;
              goto fail_1;
          }
++        if (i == 0 && !argvlist[0][0]) {
++            lastarg = i;
++            PyErr_SetString(
++                PyExc_ValueError,
++                "spawnv() arg 2 first element cannot be empty");
++            goto fail_1;
++        }
      }
      lastarg = argc;
      argvlist[argc] = NULL;