-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Can't start a Process
if StartInfo.EnvironmentVariables
is called or evaluated on Windows systems
#94338
Comments
Tagging subscribers to this area: @dotnet/area-system-diagnostics-process Issue DetailsDescriptionThe When This is the message that is emitted as soon as Start() is called after evaluation:
What's worse is that this issue can be either triggered by hovering over the Furthermore, it appears to only affect Windows systems as Linux users don't get this error. Reproduction Steps
Expected behaviorThe process will start the Command Prompt on Windows and will not emit an Actual behaviorAn error of
This error comes from Regression?This is not a regression, because this issue occurred on .NET Framework, .NET 6.0, and .NET 7.0. Known WorkaroundsOne can use a dirty reflection-based workaround to get the StartInfo back to how it was before calling the internal static ProcessStartInfo StripEnvironmentVariables(ProcessStartInfo processStartInfo)
{
var privateReflection = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetField;
var startInfoType = processStartInfo.GetType();
var envVarsField = startInfoType.GetField("_environmentVariables", privateReflection);
envVarsField.SetValue(processStartInfo, null);
return processStartInfo;
} Then, one can call this function to re-assign the Console.WriteLine($"{proc.StartInfo.EnvironmentVariables.Count}");
proc.StartInfo = StripEnvironmentVariables(proc.StartInfo)
proc.Start(); This workaround is not needed in cases where However, this workaround only lasts until the next evaluation of Configuration
This issue only occurs when running on Windows. Other informationI've reviewed the source code for the .NET runtime and found that when starting processes with It looks like that one of these checks is for the if (startInfo._environmentVariables != null)
throw new InvalidOperationException(SR.CantUseEnvVars); This variable is populated when any attempt to evaluate public IDictionary<string, string?> Environment
{
get
{
if (_environmentVariables == null)
{
IDictionary envVars = System.Environment.GetEnvironmentVariables();
_environmentVariables = new DictionaryWrapper(new Dictionary<string, string?>(
envVars.Count,
OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal));
// Manual use of IDictionaryEnumerator instead of foreach to avoid DictionaryEntry box allocations.
IDictionaryEnumerator e = envVars.GetEnumerator();
Debug.Assert(!(e is IDisposable), "Environment.GetEnvironmentVariables should not be IDisposable.");
while (e.MoveNext())
{
DictionaryEntry entry = e.Entry;
_environmentVariables.Add((string)entry.Key, (string?)entry.Value);
}
}
return _environmentVariables;
}
}
|
Duplicate of #58069. As suggested there, this could be fixed by attempting to detect mutation of the IDictionary. @AptiviCEO would you be interested in sending a PR? |
Description
The
Process
class contains a property calledStartInfo
that allows you to customize how the process will start, likeUseShellExecute
to determine whether the process is created by the operating system or by the application itself.When
UseShellExecute
is turned on by setting it to true, the process can't be started withStart()
because of anInvalidOperationException
. This happens after evaluation of either theEnvironment
or theEnvironmentVariables
property from theStartInfo
of theProcess
.This is the message that is emitted as soon as
Start()
is called after evaluation:System.InvalidOperationException: The Process object must have the UseShellExecute property set to false in order to use environment variables.
What's worse is that this issue can be either triggered by hovering over the
Process
variable on Visual Studio and opening theStartInfo
property to see its values while debugging your process start code, or by directly invoking theEnvironmentVariables
property from your code as we can see in the POC.Furthermore, it appears to only affect Windows systems as Linux users don't get this error.
Reproduction Steps
InvalidOperationException
Expected behavior
The process will start the Command Prompt on Windows and will not emit an
InvalidOperationException
Actual behavior
An error of
InvalidOperationException
occurs and the process will not launch.System.InvalidOperationException: The Process object must have the UseShellExecute property set to false in order to use environment variables.
This error comes from
StartWithShellExecuteEx()
, which is called byStartCore()
.Regression?
This is not a regression, because this issue occurred on .NET Framework, .NET 6.0, and .NET 7.0.
Known Workarounds
One can use a dirty reflection-based workaround to get the StartInfo back to how it was before calling the
EnvironmentVariables
property:Then, one can call this function to re-assign the
StartInfo
property on the afflictedProcess
variable:This workaround is not needed in cases where
UseShellExecute
is not enabled.However, this workaround only lasts until the next evaluation of
EnvironmentVariables
orEnvironment
.Configuration
This issue only occurs when running on Windows.
Other information
I've reviewed the source code for the .NET runtime and found that when starting processes with
UseShellExecute
enabled,StartCore()
callsStartWithShellExecuteEx()
, which checks the state of theProcess
instance before starting the process.It looks like that one of these checks is for the
startInfo._environmentVariables
variable on line 47.This variable is populated when any attempt to evaluate
EnvironmentVariables
orEnvironment
is done either by the Visual Studio debugger or by the user code. This is on line 91.The text was updated successfully, but these errors were encountered: