This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients eryksun, mandel59, paul.moore, steve.dower, tim.golden, zach.ware
Date 2018-07-08.11:11:19
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1531048279.6.0.56676864532.issue34064@psf.upfronthosting.co.za>
In-reply-to
Content
This PR works around a bug in CMD, so I'm inclined to close it as a third-party issue. 

CMD is supposed to implement the following behavior:

    1.  If all of the following conditions are met, then quote 
        characters on the command line are preserved:

        - no /S switch
        - exactly two quote characters
        - no special characters between the two quote characters,
          where special is one of: &<>()@^|
        - there are one or more whitespace characters between the
          two quote characters
        - the string between the two quote characters is the name
          of an executable file.

    2.  Otherwise, old behavior is to see if the first character is
        a quote character and if so, strip the leading character and
        remove the last quote character on the command line, preserving
        any text after the last quote character.

In particular quotes should only be preserved if the quoted string is "the name of an executable file". To determine this, CMD calls an internal function named SearchForExecutable. This function special cases any command that begins with "cmd " (case insensitive) by substituting the current value of the %ComSpec% environment variable for the *entire* string. Of course this search succeeds, so it ends up handling the string "cmd /c echo hello" as if it's an executable. Probably no has noticed this bug since running `cmd /c "cmd /c ..."` is kind of a weird thing to do.

To demonstrate this bug, let's compare running "cmd /c ..." with "cmd.exe /c ...":

    >>> subprocess.check_output('cmd /c "cmd /c echo hello"')
    b'hello"\r\n'


    >>> subprocess.check_output('cmd /c "cmd.exe /c echo hello"')
    b'hello\r\n'

Adding /S makes CMD always use the old behavior that strips the quotes. However, this will change the existing behavior when the command line is an unquoted executable path with spaces in it. For example:

    >>> sys.executable
    'C:\\Program Files\\Python36\\python.exe'

    >>> subprocess.call(sys.executable, shell=True)
    Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:54:40) [MSC v.1900 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> exit()
    0

With /S, CMD strips the quotes from the command. Without the quotes it parses "C:\Program" as the executable to run:

    >>> subprocess.call('cmd /s /c "{}"'.format(sys.executable))
    'C:\Program' is not recognized as an internal or external command,
    operable program or batch file.
    1
History
Date User Action Args
2018-07-08 11:11:19eryksunsetrecipients: + eryksun, paul.moore, tim.golden, zach.ware, steve.dower, mandel59
2018-07-08 11:11:19eryksunsetmessageid: <1531048279.6.0.56676864532.issue34064@psf.upfronthosting.co.za>
2018-07-08 11:11:19eryksunlinkissue34064 messages
2018-07-08 11:11:19eryksuncreate