haskell / process

Library for dealing with system processes
http://hackage.haskell.org/package/process
Other
87 stars 82 forks source link

process mangles \\shared\drive\paths #294

Closed Bodigrim closed 1 year ago

Bodigrim commented 1 year ago

https://github.com/haskell/process/blob/f94c1c7cb36b88b7c00c9008beece70f06bede21/System/Process/Windows.hsc#L425-L427 https://github.com/haskell/process/blob/f94c1c7cb36b88b7c00c9008beece70f06bede21/System/Process/Windows.hsc#L470-L480

It seems translateInternal assumes that any \\ comes from an overzealous user who has already escaped \ manually - and thus decides to pass it untranslated. This is problematic when an argument naturally contains two slashes, e.g., Windows network path \\shared\drive\path. One would expect translateInternal to convert it into "\\\\shared\\drive\\path", but in fact it returns "\\shared\\drive\\path", equivalent to \shared\drive\path, which is wrong.

If we are in agreement on this, I'll submit a patch soon.

Bodigrim commented 1 year ago

The code in question has been added in 4df8c588af78ce4f74ca45ab542b05dfa6d232fd:

commit 4df8c588af78ce4f74ca45ab542b05dfa6d232fd
Author: simonmar <unknown>
Date:   Tue Feb 24 12:39:12 2004 +0000

    [project @ 2004-02-24 12:39:12 by simonmar]
    New version of translate for mingw32, which correctly (allegedly)
    reverses the command-line translation done by the standard C runtime
    on Windows.

diff --git a/System/Cmd.hs b/System/Cmd.hs
index 78d3b28..41fabb2 100644
--- a/System/Cmd.hs
+++ b/System/Cmd.hs
@@ -203,9 +203,24 @@ rawSystem cmd args = do

 translate :: String -> String
 translate str@('"':_) = str -- already escaped.
-translate str = '"' : foldr escape "\"" str
-  where escape '"'  str = '\\' : '"'  : str
-       escape c    str = c : str
+       -- ToDo: this case is wrong.  It is only here because we
+       -- abuse the system in GHC's SysTools by putting arguments into
+       -- the command name; at some point we should fix it up and remove
+       -- the case above.
+translate str = '"' : snd (foldr escape (True,"\"") str)
+  where escape '"'  (b,     str) = (True,  '\\' : '"'  : str)
+        escape '\\' (True,  str) = (True,  '\\' : '\\' : str)
+        escape '\\' (False, str) = (False, '\\' : str)
+       escape c    (b,     str) = (False, c : str)
+       -- This function attempts to invert the Microsoft C runtime's
+       -- quoting rules, which can be found here:
+       --     http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccelng/htm/progs_12.asp
+       -- (if this URL stops working, you might be able to find it by
+       -- searching for "Parsing C Command-Line Arguments" on MSDN).
+       --
+       -- The Bool passed back along the string is True iff the
+       -- rest of the string is a sequence of backslashes followed by
+       -- a double quote.

 foreign import ccall unsafe "rawSystem"
   c_rawSystem :: CString -> IO Int
Bodigrim commented 1 year ago

Reading https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments?view=msvc-170, it seems that my understanding of escaping in Windows was wrong. Maybe some other part of my application is mangling slashes. Closing for now.