diff --git a/src/coreclr/dlls/mscoree/exports.cpp b/src/coreclr/dlls/mscoree/exports.cpp index 053993ad1918a3..07b4d9761e19c5 100644 --- a/src/coreclr/dlls/mscoree/exports.cpp +++ b/src/coreclr/dlls/mscoree/exports.cpp @@ -262,7 +262,7 @@ int coreclr_initialize( &hostContract); #ifdef TARGET_UNIX - DWORD error = PAL_InitializeCoreCLR(exePath, g_coreclr_embedded); + DWORD error = PAL_InitializeCoreCLR(g_coreclr_embedded); hr = HRESULT_FROM_WIN32(error); // If PAL initialization failed, then we should return right away and avoid diff --git a/src/coreclr/pal/inc/pal.h b/src/coreclr/pal/inc/pal.h index 5f6caecd340ee8..b724fbc9dede76 100644 --- a/src/coreclr/pal/inc/pal.h +++ b/src/coreclr/pal/inc/pal.h @@ -201,7 +201,7 @@ PALIMPORT DWORD PALAPI PAL_InitializeCoreCLR( - const char *szExePath, BOOL runningInExe); + BOOL runningInExe); /// /// This function shuts down PAL WITHOUT exiting the current process. @@ -3303,15 +3303,6 @@ PALAPI SetLastError( IN DWORD dwErrCode); -PALIMPORT -LPWSTR -PALAPI -GetCommandLineW(); - -#ifdef UNICODE -#define GetCommandLine GetCommandLineW -#endif - PALIMPORT VOID PALAPI diff --git a/src/coreclr/pal/src/include/pal/process.h b/src/coreclr/pal/src/include/pal/process.h index b15d2ab837a696..52e1f37aaa99a5 100644 --- a/src/coreclr/pal/src/include/pal/process.h +++ b/src/coreclr/pal/src/include/pal/process.h @@ -69,22 +69,6 @@ Notes : --*/ BOOL PROCCreateInitialProcess(LPWSTR lpwstrCmdLine, LPWSTR lpwstrFullPath); -/*++ -Function: - PROCCleanupInitialProcess - -Abstract - Cleanup all the structures for the initial process. - -Parameter - VOID - -Return - VOID - ---*/ -VOID PROCCleanupInitialProcess(VOID); - /*++ Function PROCAbortInitialize() diff --git a/src/coreclr/pal/src/include/pal/procobj.hpp b/src/coreclr/pal/src/include/pal/procobj.hpp index a53551f03d0234..e20f4f510b9bf8 100644 --- a/src/coreclr/pal/src/include/pal/procobj.hpp +++ b/src/coreclr/pal/src/include/pal/procobj.hpp @@ -23,12 +23,6 @@ Module Name: namespace CorUnix { - PAL_ERROR - InitializeProcessCommandLine( - LPWSTR lpwstrCmdLine, - LPWSTR lpwstrFullPath - ); - PAL_ERROR CreateInitialProcessAndThreadObjects( CPalThread *pThread diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index 6c5c9989a2bb3f..d7439969b7ccd7 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -114,10 +114,8 @@ static minipal_mutex* init_critsec = NULL; static DWORD g_initializeDLLFlags = PAL_INITIALIZE_DLL; -static int Initialize(int argc, const char *const argv[], DWORD flags); -static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv); +static int Initialize(DWORD flags); static LPWSTR INIT_GetCurrentEXEPath(); -static BOOL INIT_SharedFilesPath(void); /*++ Function: @@ -139,7 +137,7 @@ PAL_Initialize( int argc, char *const argv[]) { - return Initialize(argc, argv, PAL_INITIALIZE); + return Initialize(PAL_INITIALIZE); } /*++ @@ -163,7 +161,7 @@ PAL_InitializeWithFlags( const char *const argv[], DWORD flags) { - return Initialize(argc, argv, flags); + return Initialize(flags); } /*++ @@ -182,7 +180,7 @@ int PALAPI PAL_InitializeDLL() { - return Initialize(0, nullptr, g_initializeDLLFlags); + return Initialize(g_initializeDLLFlags); } /*++ @@ -285,14 +283,11 @@ InitializeDefaultStackSize() --*/ int Initialize( - int argc, - const char *const argv[], DWORD flags) { PAL_ERROR palError = ERROR_GEN_FAILURE; CPalThread *pThread = nullptr; CListedObjectManager *plom = nullptr; - LPWSTR command_line = nullptr; LPWSTR exe_path = nullptr; int retval = -1; bool fFirstTimeInit = false; @@ -300,7 +295,7 @@ Initialize( /* the first ENTRY within the first call to PAL_Initialize is a special case, since debug channels are not initialized yet. So in that case the ENTRY will be called after the DBG channels initialization */ - ENTRY_EXTERNAL("PAL_Initialize(argc = %d argv = %p)\n", argc, argv); + ENTRY_EXTERNAL("PAL_Initialize\n"); /*Firstly initiate a lastError */ SetLastError(ERROR_GEN_FAILURE); @@ -467,50 +462,25 @@ Initialize( palError = ERROR_GEN_FAILURE; - if (argc > 0 && argv != nullptr) + /* find out the application's full path */ + exe_path = INIT_GetCurrentEXEPath(); + if (nullptr == exe_path) { - /* build the command line */ - command_line = INIT_FormatCommandLine(argc, argv); - if (nullptr == command_line) - { - ERROR("Error building command line\n"); - palError = ERROR_PALINIT_COMMAND_LINE; - goto CLEANUP1d; - } - - /* find out the application's full path */ - exe_path = INIT_GetCurrentEXEPath(); - if (nullptr == exe_path) - { - ERROR("Unable to find exe path\n"); - palError = ERROR_PALINIT_CONVERT_EXE_PATH; - goto CLEANUP1e; - } - - palError = InitializeProcessCommandLine( - command_line, - exe_path); - - if (NO_ERROR != palError) - { - ERROR("Unable to initialize command line\n"); - goto CLEANUP2; - } - - // InitializeProcessCommandLine took ownership of this memory. - command_line = nullptr; - - if (!LOADSetExeName(exe_path)) - { - ERROR("Unable to set exe name\n"); - palError = ERROR_PALINIT_SET_EXE_NAME; - goto CLEANUP2; - } + ERROR("Unable to find exe path\n"); + palError = ERROR_PALINIT_CONVERT_EXE_PATH; + goto CLEANUP1e; + } - // LOADSetExeName took ownership of this memory. - exe_path = nullptr; + if (!LOADSetExeName(exe_path)) + { + ERROR("Unable to set exe name\n"); + palError = ERROR_PALINIT_SET_EXE_NAME; + goto CLEANUP2; } + // LOADSetExeName took ownership of this memory. + exe_path = nullptr; + if (init_count == 0) { // @@ -600,12 +570,10 @@ Initialize( CLEANUP10: MAPCleanup(); CLEANUP6: - PROCCleanupInitialProcess(); + // Cleanup initial process data CLEANUP2: free(exe_path); CLEANUP1e: - free(command_line); -CLEANUP1d: // Cleanup synchronization manager CLEANUP1c: // Cleanup object manager @@ -642,8 +610,7 @@ Initialize( PAL_InitializeCoreCLR Abstract: - A replacement for PAL_Initialize when loading CoreCLR. Instead of taking a command line (which CoreCLR - instances aren't given anyway) the path into which the CoreCLR is installed is supplied instead. + A replacement for PAL_Initialize when loading CoreCLR. This routine also makes sure the psuedo dynamic libraries PALRT and mscorwks have their initialization methods called. @@ -655,12 +622,11 @@ Initialize( --*/ PAL_ERROR PALAPI -PAL_InitializeCoreCLR(const char *szExePath, BOOL runningInExe) +PAL_InitializeCoreCLR(BOOL runningInExe) { g_running_in_exe = runningInExe; - // Fake up a command line to call PAL initialization with. - int result = Initialize(1, &szExePath, PAL_INITIALIZE_CORECLR); + int result = Initialize(PAL_INITIALIZE_CORECLR); if (result != 0) { return GetLastError(); @@ -851,132 +817,6 @@ void PALInitUnlock(void) /* Internal functions *********************************************************/ -/*++ -Function: - INIT_FormatCommandLine [Internal] - -Abstract: - This function converts an array of arguments (argv) into a Unicode - command-line for use by GetCommandLineW - -Parameters : - int argc : number of arguments in argv - char **argv : argument list in an array of NULL-terminated strings - -Return value : - pointer to Unicode command line. This is a buffer allocated with malloc; - caller is responsible for freeing it with free() - -Note : not all peculiarities of Windows command-line processing are supported; - --what is supported : - -arguments with white-space must be double quoted (we'll just double-quote - all arguments to simplify things) - -some characters must be escaped with \ : particularly, the double-quote, - to avoid confusion with the double-quotes at the start and end of - arguments, and \ itself, to avoid confusion with escape sequences. --what is not supported: - -under Windows, \\ is interpreted as an escaped \ ONLY if it's followed by - an escaped double-quote \". \\\" is passed to argv as \", but \\a is - passed to argv as \\a... there may be other similar cases - -there may be other characters which must be escaped ---*/ -static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv) -{ - LPWSTR retval; - LPSTR command_line=nullptr, command_ptr; - LPCSTR arg_ptr; - INT length, i,j; - BOOL bQuoted = FALSE; - - /* list of characters that need no be escaped with \ when building the - command line. currently " and \ */ - LPCSTR ESCAPE_CHARS="\"\\"; - - /* allocate temporary memory for the string. Play it safe : - double the length of each argument (in case they're composed - exclusively of escaped characters), and add 3 (for the double-quotes - and separating space). This is temporary anyway, we return a LPWSTR */ - length=0; - for(i=0; i(malloc(length != 0 ? length : 1)); - - if(!command_line) - { - ERROR("couldn't allocate memory for command line!\n"); - return nullptr; - } - - command_ptr=command_line; - for(i=0; i(malloc((sizeof(WCHAR)*i))); - if(retval == nullptr) - { - ERROR("can't allocate memory for Unicode command line!\n"); - free(command_line); - return nullptr; - } - - if(!MultiByteToWideChar(CP_ACP, 0,command_line, -1, retval, i)) - { - ASSERT("MultiByteToWideChar failure\n"); - free(retval); - retval = nullptr; - } - else - TRACE("Command line is %s\n", command_line); - - free(command_line); - return retval; -} - /*++ Function: INIT_GetCurrentEXEPath diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 94ff751db5dac8..e172351dda6e76 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -120,12 +120,6 @@ extern bool g_running_in_exe; using namespace CorUnix; -// -// The command line and app name for the process -// -LPWSTR g_lpwstrCmdLine = NULL; -LPWSTR g_lpwstrAppDir = NULL; - // Thread ID of thread that has started the ExitProcess process Volatile terminator = 0; @@ -1238,30 +1232,6 @@ PAL_GetTransportPipeName( suffix); } -/*++ -Function: - GetCommandLineW - -See MSDN doc. ---*/ -LPWSTR -PALAPI -GetCommandLineW( - VOID) -{ - PERF_ENTRY(GetCommandLineW); - ENTRY("GetCommandLineW()\n"); - - LPWSTR lpwstr = g_lpwstrCmdLine ? g_lpwstrCmdLine : (LPWSTR)W(""); - - LOGEXIT("GetCommandLineW returns LPWSTR %p (%S)\n", - g_lpwstrCmdLine, - lpwstr); - PERF_EXIT(GetCommandLineW); - - return lpwstr; -} - /*++ Function PROCNotifyProcessShutdown @@ -1978,80 +1948,6 @@ PROCAbort(int signal, siginfo_t* siginfo, void* context) } \ while(0) -/*++ -Function - InitializeProcessCommandLine - -Abstract - Initializes (or re-initializes) the saved command line and exe path. - -Parameter - lpwstrCmdLine - lpwstrFullPath - -Return - PAL_ERROR - -Notes - This function takes ownership of lpwstrCmdLine, but not of lpwstrFullPath ---*/ - -PAL_ERROR -CorUnix::InitializeProcessCommandLine( - LPWSTR lpwstrCmdLine, - LPWSTR lpwstrFullPath -) -{ - PAL_ERROR palError = NO_ERROR; - LPWSTR initial_dir = NULL; - - // - // Save the command line and initial directory - // - - if (lpwstrFullPath) - { - LPWSTR lpwstr = PAL_wcsrchr(lpwstrFullPath, '/'); - if (!lpwstr) - { - ERROR("Invalid full path\n"); - palError = ERROR_INTERNAL_ERROR; - goto exit; - } - lpwstr[0] = '\0'; - size_t n = PAL_wcslen(lpwstrFullPath) + 1; - - size_t iLen = n; - initial_dir = reinterpret_cast(malloc(iLen*sizeof(WCHAR))); - if (NULL == initial_dir) - { - ERROR("malloc() failed! (initial_dir) \n"); - palError = ERROR_NOT_ENOUGH_MEMORY; - goto exit; - } - - if (wcscpy_s(initial_dir, iLen, lpwstrFullPath) != SAFECRT_SUCCESS) - { - ERROR("wcscpy_s failed!\n"); - free(initial_dir); - palError = ERROR_INTERNAL_ERROR; - goto exit; - } - - lpwstr[0] = '/'; - - free(g_lpwstrAppDir); - g_lpwstrAppDir = initial_dir; - } - - free(g_lpwstrCmdLine); - g_lpwstrCmdLine = lpwstrCmdLine; - -exit: - return palError; -} - - /*++ Function: CreateInitialProcessAndThreadObjects @@ -2098,35 +1994,6 @@ CorUnix::CreateInitialProcessAndThreadObjects( } -/*++ -Function: - PROCCleanupInitialProcess - -Abstract - Cleanup all the structures for the initial process. - -Parameter - VOID - -Return - VOID - ---*/ -VOID -PROCCleanupInitialProcess(VOID) -{ - /* Free the application directory */ - free(g_lpwstrAppDir); - - /* Free the stored command line */ - free(g_lpwstrCmdLine); - - // - // Object manager shutdown will handle freeing the underlying - // thread and process data - // -} - /*++ Function: TerminateCurrentProcessNoExit diff --git a/src/coreclr/pal/tests/palsuite/CMakeLists.txt b/src/coreclr/pal/tests/palsuite/CMakeLists.txt index cb6f541087d2b7..8aa8dc60c4bea9 100644 --- a/src/coreclr/pal/tests/palsuite/CMakeLists.txt +++ b/src/coreclr/pal/tests/palsuite/CMakeLists.txt @@ -292,7 +292,6 @@ add_executable_clr(paltests miscellaneous/FormatMessageW/test6/test.cpp miscellaneous/FreeEnvironmentStringsW/test1/test.cpp miscellaneous/FreeEnvironmentStringsW/test2/test.cpp - miscellaneous/GetCommandLineW/test1/test.cpp miscellaneous/GetEnvironmentStringsW/test1/test.cpp miscellaneous/GetEnvironmentVariableA/test1/test.cpp miscellaneous/GetEnvironmentVariableA/test2/test.cpp diff --git a/src/coreclr/pal/tests/palsuite/compilableTests.txt b/src/coreclr/pal/tests/palsuite/compilableTests.txt index 61943a5515492f..1500145501b791 100644 --- a/src/coreclr/pal/tests/palsuite/compilableTests.txt +++ b/src/coreclr/pal/tests/palsuite/compilableTests.txt @@ -220,7 +220,6 @@ miscellaneous/FormatMessageW/test5/paltest_formatmessagew_test5 miscellaneous/FormatMessageW/test6/paltest_formatmessagew_test6 miscellaneous/FreeEnvironmentStringsW/test1/paltest_freeenvironmentstringsw_test1 miscellaneous/FreeEnvironmentStringsW/test2/paltest_freeenvironmentstringsw_test2 -miscellaneous/GetCommandLineW/test1/paltest_getcommandlinew_test1 miscellaneous/GetEnvironmentStringsW/test1/paltest_getenvironmentstringsw_test1 miscellaneous/GetEnvironmentVariableA/test1/paltest_getenvironmentvariablea_test1 miscellaneous/GetEnvironmentVariableA/test2/paltest_getenvironmentvariablea_test2 diff --git a/src/coreclr/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.cpp b/src/coreclr/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.cpp deleted file mode 100644 index eca5a53a3194ee..00000000000000 --- a/src/coreclr/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/*============================================================ -** -** Source : test.c -** -** Purpose: Test for GetCommandLineW() function -** -** -**=========================================================*/ - -#define UNICODE -#include - -PALTEST(miscellaneous_GetCommandLineW_test1_paltest_getcommandlinew_test1, "miscellaneous/GetCommandLineW/test1/paltest_getcommandlinew_test1") -{ - - LPWSTR TheResult = NULL; - WCHAR *CommandLine; - int i; - WCHAR * p; - - /* - * Initialize the PAL and return FAILURE if this fails - */ - - if(0 != (PAL_Initialize(argc, argv))) - { - return FAIL; - } - - CommandLine = (WCHAR*)malloc(1024); - wcscpy(CommandLine,convert(argv[0])); - - for(i=1;i +#include +#endif // TARGET_UNIX && !DACCESS_COMPILE + #include "CachedInterfaceDispatchPal.h" #include "CachedInterfaceDispatch.h" @@ -3637,23 +3642,43 @@ BOOL Module::FixupNativeEntry(READYTORUN_IMPORT_SECTION* pSection, SIZE_T fixupI static LPCWSTR s_pCommandLine = NULL; -// Retrieve the full command line for the current process. -LPCWSTR GetManagedCommandLine() +#ifdef TARGET_UNIX +static LPWSTR s_pExePath = NULL; + +static LPWSTR GetExePath() { - LIMITED_METHOD_CONTRACT; - return s_pCommandLine; + LPWSTR pExePath = VolatileLoadWithoutBarrier(&s_pExePath); + + if (pExePath == nullptr) + { + char* exePath = minipal_getexepath(); + size_t exePathLen = minipal_get_length_utf8_to_utf16(exePath, strlen(exePath), 0); + pExePath = new WCHAR[exePathLen + 1]; + minipal_convert_utf8_to_utf16(exePath, strlen(exePath), (CHAR16_T*)pExePath, exePathLen + 1, 0); + pExePath[exePathLen] = W('\0'); + free(exePath); + s_pExePath = pExePath; + } + + return pExePath; } +#endif // TARGET_UNIX LPCWSTR GetCommandLineForDiagnostics() { // Get the managed command line. - LPCWSTR pCmdLine = GetManagedCommandLine(); + LPCWSTR pCmdLine = VolatileLoadWithoutBarrier(&s_pCommandLine); - // Checkout https://github.com/dotnet/coreclr/pull/24433 for more information about this fall back. + // GetCommandLineForDiagnostics can be called without s_pCommandLine being initialized + // when the runtime is hosted without entrypoint assembly if (pCmdLine == nullptr) { +#ifdef TARGET_WINDOWS // Use the result from GetCommandLineW() instead pCmdLine = GetCommandLineW(); +#else + pCmdLine = GetExePath(); +#endif // TARGET_WINDOWS } return pCmdLine; @@ -3697,18 +3722,17 @@ void SaveManagedCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv) } CONTRACTL_END; - // Get the command line. - LPCWSTR osCommandLine = GetCommandLineW(); - #ifndef TARGET_UNIX - // On Windows, osCommandLine contains the executable and all arguments. - s_pCommandLine = osCommandLine; + // On Windows, GetCommandLineW contains the executable and all arguments. + s_pCommandLine = GetCommandLineW(); #else // On UNIX, the PAL doesn't have the command line arguments, so we must build the command line. - // osCommandLine contains the full path to the executable. - SIZE_T commandLineLen = (u16_strlen(osCommandLine) + 1); + // exePath contains the full path to the executable. + LPCWSTR exePath = GetExePath(); + SIZE_T commandLineLen = (u16_strlen(exePath) + 1); - // We will append pwzAssemblyPath to the 'corerun' osCommandLine + // Append assembly path to approximate the command line for generic hosts like `dotnet`. + // This isn't quite correct for apphost, as the app name will be duplicated. commandLineLen += (u16_strlen(pwzAssemblyPath) + 1); for (int i = 0; i < argc; i++) @@ -3722,7 +3746,7 @@ void SaveManagedCommandLine(LPCWSTR pwzAssemblyPath, int argc, LPCWSTR *argv) SIZE_T remainingLen = commandLineLen; LPWSTR pCursor = pNewCommandLine; - Append_Next_Item(&pCursor, &remainingLen, osCommandLine, true); + Append_Next_Item(&pCursor, &remainingLen, exePath, true); Append_Next_Item(&pCursor, &remainingLen, pwzAssemblyPath, (argc > 0)); for (int i = 0; i < argc; i++) diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h index bc331427218e0b..846f02bcfc72d0 100644 --- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h +++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h @@ -1735,7 +1735,9 @@ ep_rt_diagnostics_command_line_get (void) { STATIC_CONTRACT_NOTHROW; - // In coreclr, this value can change over time, specifically before vs after suspension in diagnostics server. + // This value is an approximation of the command line for diagnostic purposes, and it may not match + // the actual command line used to launch the process. + // This value can change over time, specifically before vs after suspension in diagnostics server. // The host initializes the runtime in two phases, init and exec assembly. On non-Windows platforms the commandline returned by the runtime // is different during each phase. We suspend during init where the runtime has populated the commandline with a // mock value (the full path of the executing assembly) and the actual value isn't populated till the exec assembly phase.