TProcess.Parameters acts differently on Windows vs Unix for typical C/C++ programs and typical FPC programs.
Summary
When writing #41328 (closed) I found found by reading the code that the current implementation of SysExecute on Windows results in different arguments being passed compared to the Unix version.
System Information
- Operating system: Windows
- Processor architecture: x86-64
- Compiler version: trunk
- Device: N/A
Reason to believe the bug exists
- On Windows, https://gitlab.com/freepascal.org/fpc/source/-/blob/main/packages/fcl-process/src/win/process.inc#L209-215 uses a
MaybeQuoteIfNotQuotedlogic to deal withTProcess.Parameters. - On Unix
TProcess.Parametersjust becomes argv.
Steps to reproduce
- Write a Windows VC++ program that performs "echo".
#include <stdio.h>followed byint main(int ac, char** av){ printf("%s\n", av[1]); return 0; }will suffice. - Call it.
- Write a Free Pascal program that performs "echo".
program Echo;
begin
writeln (ParamStr(1));
end.
- Also call it.
What is the current bug behavior?
For a TProcess.Parameters containing one member, '"a"', being used to call echo or a Windows VC++ program written to perform the same thing.
- On Windows,
MaybeQuoteIfNotQuotedwould not try to quote the string because it appears to be quoted. As a result, the program would receive the CommandLineecho.exe "a"and print onlya. - On Unix, the program would print
"a".
What is the expected (correct) behavior?
It should print "a" like on Linux. This translates to a CommandLine of "\"a\"".
Possible fixes
I believe the Unix implementation to be more logical and the Windows version should be changed to match. Instead of MaybeQuoteIfNotQuoted, what we need is a QuoteIfNeeded or even Quote (always):
Function Quote(Const S : TProcessString) : TProcessString;
var
C : Char;
Backslashes : Integer;
begin
Backslashes = 0;
Result := '"';
for C in S do
case C of
'"':
begin
Result := Result + StringOfChar('\', Backslashes * 2 + 1) + C;
Backslashes := 0;
end
'\':
Backslashes := Backslashes + 1;
else
begin
Result := Result + StringOfChar('\', Backslashes) + C;
Backslashes := 0;
end
Result := Result + StringOfChar('\', Backslashes * 2) + '"';
end;
Function QuoteIfNeeded`(Const S : TProcessString) : TProcessString
begin
If (Pos(' ',S)<>0) or (pos('"',S)<>0) or (pos(#9,S)<>0) then
Result := Quote(S)
else
Result := S;
end;
Edited by Mingye Wang