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

Steps to reproduce

  • Write a Windows VC++ program that performs "echo". #include <stdio.h> followed by int 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, MaybeQuoteIfNotQuoted would not try to quote the string because it appears to be quoted. As a result, the program would receive the CommandLine echo.exe "a" and print only a.
  • 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
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information