From 1e38e24780757ac3dd40dd85748524b8b98a9b89 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Mon, 17 Apr 2023 14:54:16 -0700 Subject: [PATCH] Fix Environment.GetCommandLineArg for AOT compiled libraries Made the implementation shared between standard CoreCLR and native AOT Fixes #84944 --- .../src/System/Environment.CoreCLR.cs | 22 ------------------- .../StartupCodeHelpers.Extensions.cs | 10 +++++---- .../src/System/Environment.NativeAot.cs | 13 ----------- .../src/System/Environment.cs | 13 +++++++++++ 4 files changed, 19 insertions(+), 39 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs index cd7a1a3560de11..e8040964e03458 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Environment.CoreCLR.cs @@ -61,28 +61,6 @@ public static extern int ExitCode [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void FailFast(string? message, Exception? exception, string? errorMessage); - private static string[]? s_commandLineArgs; - - public static string[] GetCommandLineArgs() - { - // There are multiple entry points to a hosted app. The host could - // use ::ExecuteAssembly() or ::CreateDelegate option: - // - // ::ExecuteAssembly() -> In this particular case, the runtime invokes the main - // method based on the arguments set by the host, and we return those arguments - // - // ::CreateDelegate() -> In this particular case, the host is asked to create a - // delegate based on the appDomain, assembly and methodDesc passed to it. - // which the caller uses to invoke the method. In this particular case we do not have - // any information on what arguments would be passed to the delegate. - // So our best bet is to simply use the commandLine that was used to invoke the process. - // in case it is present. - - return s_commandLineArgs != null ? - (string[])s_commandLineArgs.Clone() : - GetCommandLineArgsNative(); - } - private static unsafe string[] InitializeCommandLineArgs(char* exePath, int argc, char** argv) // invoked from VM { string[] commandLineArgs = new string[argc + 1]; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/StartupCode/StartupCodeHelpers.Extensions.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/StartupCode/StartupCodeHelpers.Extensions.cs index 6edae44156dd7e..e320f18d69d60b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/StartupCode/StartupCodeHelpers.Extensions.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/StartupCode/StartupCodeHelpers.Extensions.cs @@ -26,7 +26,7 @@ internal static unsafe void InitializeCommandLineArgsW(int argc, char** argv) { args[i] = new string(argv[i]); } - Environment.SetCommandLineArgs(args); + Environment.s_commandLineArgs = args; } internal static unsafe void InitializeCommandLineArgs(int argc, sbyte** argv) @@ -36,14 +36,16 @@ internal static unsafe void InitializeCommandLineArgs(int argc, sbyte** argv) { args[i] = new string(argv[i]); } - Environment.SetCommandLineArgs(args); + Environment.s_commandLineArgs = args; } private static string[] GetMainMethodArguments() { - // GetCommandLineArgs includes the executable name, Main() arguments do not. - string[] args = Environment.GetCommandLineArgs(); + // Environment.s_commandLineArgs includes the executable name, Main() arguments do not. + string[]? args = Environment.s_commandLineArgs; + // Environment.s_commandLineArgs is expected to initialized during startup. + Debug.Assert(args != null); Debug.Assert(args.Length > 0); string[] mainArgs = new string[args.Length - 1]; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs index 011458f4a516ce..10312e4473b902 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Environment.NativeAot.cs @@ -63,18 +63,5 @@ internal static void ShutdownCore() } public static int TickCount => (int)TickCount64; - - private static string[]? s_commandLineArgs; - - public static string[] GetCommandLineArgs() - { - Debug.Assert(s_commandLineArgs != null, "VM did not properly setup application."); - return (string[])s_commandLineArgs.Clone(); - } - - internal static void SetCommandLineArgs(string[] cmdLineArgs) - { - s_commandLineArgs = cmdLineArgs; - } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.cs index 99956b82abf552..da368b943ff7cf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.cs @@ -86,6 +86,19 @@ public static void SetEnvironmentVariable(string variable, string? value, Enviro SetEnvironmentVariableFromRegistry(variable, value, fromMachine: fromMachine); } +#if !MONO + internal static string[]? s_commandLineArgs; + + public static string[] GetCommandLineArgs() + { + // s_commandLineArgs is expected to be initialize with application command line arguments + // during startup. GetCommandLineArgsNative fallback is used for hosted libraries. + return s_commandLineArgs != null ? + (string[])s_commandLineArgs.Clone() : + GetCommandLineArgsNative(); + } +#endif + public static string CommandLine => PasteArguments.Paste(GetCommandLineArgs(), pasteFirstArgumentUsingArgV0Rules: true); public static string CurrentDirectory