-
Notifications
You must be signed in to change notification settings - Fork 30
Description
Flutter PTY Windows Bug Report & Fix
Title
[Windows] Executable name duplicated in arguments when spawning process via Pty.start
Description
On Windows, when Pty.start creates a process, the executable name is incorrectly duplicated in the command line arguments passed to the child process.
The Dart side (Pty.start) correctly constructs the argument list starting with the executable path at index 0 (standard convention). However, the Windows native implementation (flutter_pty_win.c) treats the entire argument list as additional arguments to be appended to the command line, failing to skip argv[0].
This causes critical issues with shells like PowerShell 7 (pwsh), which interpret the first positional argument as a script file path if it's not a flag, leading to startup failure.
Steps to Reproduce
- Run a Dart/Flutter app using
flutter_ptyon Windows. - Attempt to start a process:
Pty.start('pwsh.exe', arguments: ['-NoLogo']);
- Expected Behavior:
- Command line:
pwsh.exe -NoLogo - Process starts successfully.
- Command line:
- Actual Behavior:
- Command line becomes:
pwsh.exe pwsh.exe -NoLogo pwsherror:The argument 'pwsh.exe' is not recognized as the name of a script file.
- Command line becomes:
Environment
- OS: Windows 11
- Package: flutter_pty (v0.4.2)
Technical Fix Instructions
To resolve this, the native Windows implementation must skip the first element of the argument array (argv[0]) when constructing the command line string, as argv[0] is the executable itself which is already handled.
Target File
src/flutter_pty_win.c
Function
static LPWSTR build_command(char *executable, char **arguments)
Changes
Change the loop initialization from 0 to 1 in two places:
- When calculating the total string length.
- When building the command string.
1. Length Calculation Loop
if (arguments != NULL)
{
// CHANGE: Start from 1 to skip executable name
int i = 1;
while (arguments[i] != NULL)
{
command_length += (int)strlen(arguments[i]) + 1;
i++;
}
}2. String Construction Loop
if (arguments != NULL)
{
// CHANGE: Start from 1 to skip executable name
int j = 1;
while (arguments[j] != NULL)
{
command[i++] = ' ';
int k = 0;
while (arguments[j][k] != 0)
{
command[i] = (WCHAR)arguments[j][k];
i++;
k++;
}
j++;
}
}This change prevents the executable name from appearing twice in the final command line string passed to CreateProcessW.