Closed Bodigrim closed 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
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.
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 expecttranslateInternal
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.