diff --git a/src/coreclr/inc/clrconfig.h b/src/coreclr/inc/clrconfig.h index f067824d241b5c..4348afe68696c9 100644 --- a/src/coreclr/inc/clrconfig.h +++ b/src/coreclr/inc/clrconfig.h @@ -126,10 +126,7 @@ class CLRConfig static HRESULT GetConfigValue(const ConfigStringInfo & info, __deref_out_z LPWSTR * outVal); // - // Check whether an option is specified (e.g. explicitly listed) in any of the CLRConfig - // locations: environment or registry (with or without COMPlus_) or any config file. - // The result is therefore a conservative approximation (some settings do not actually - // take effect everywhere and no setting is valid both with and without COMPlus_) + // Check whether an option is specified (e.g. explicitly listed) in the CLRConfig. // static BOOL IsConfigOptionSpecified(LPCWSTR name); diff --git a/src/coreclr/inc/clrconfignocache.h b/src/coreclr/inc/clrconfignocache.h new file mode 100644 index 00000000000000..46bc2182686b23 --- /dev/null +++ b/src/coreclr/inc/clrconfignocache.h @@ -0,0 +1,94 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +// -------------------------------------------------------------------------------------------------- +// clrconfignocache.h +// +// Logic for resolving configuration names. +// + +#ifndef StrLen +#define StrLen(STR) ((sizeof(STR) / sizeof(STR[0])) - 1) +#endif // !StrLen + +// Config prefixes +#define COMPLUS_PREFIX_A "COMPlus_" +#define COMPLUS_PREFIX W("COMPlus_") +#define LEN_OF_COMPLUS_PREFIX StrLen(COMPLUS_PREFIX_A) + +#define DOTNET_PREFIX_A "DOTNET_" +#define DOTNET_PREFIX W("DOTNET_") +#define LEN_OF_DOTNET_PREFIX StrLen(DOTNET_PREFIX_A) + +class CLRConfigNoCache +{ + const char* _value; + + CLRConfigNoCache() = default; + CLRConfigNoCache(LPCSTR cfg) : _value { cfg } + { } + +public: + bool IsSet() const { return _value != NULL; } + + LPCSTR AsString() const + { + _ASSERTE(IsSet()); + return _value; + } + + bool TryAsInteger(int radix, DWORD& result) const + { + _ASSERTE(IsSet()); + + errno = 0; + LPSTR endPtr; + result = strtoul(_value, &endPtr, radix); + bool fSuccess = (errno != ERANGE) && (endPtr != _value); + return fSuccess; + } + + static CLRConfigNoCache Get(LPCSTR cfg, bool noPrefix = false, char*(*getEnvFptr)(const char*) = nullptr) + { + char nameBuffer[64]; + const char* fallbackPrefix = NULL; + const size_t namelen = strlen(cfg); + + if (noPrefix) + { + if (namelen >= _countof(nameBuffer)) + { + _ASSERTE(!"Environment variable name too long."); + return {}; + } + + *nameBuffer = W('\0'); + } + else + { + bool dotnetValid = namelen < (size_t)(_countof(nameBuffer) - 1 - LEN_OF_DOTNET_PREFIX); + bool complusValid = namelen < (size_t)(_countof(nameBuffer) - 1 - LEN_OF_COMPLUS_PREFIX); + if (!dotnetValid || !complusValid) + { + _ASSERTE(!"Environment variable name too long."); + return {}; + } + + // Priority order is DOTNET_ and then COMPlus_. + strcpy_s(nameBuffer, _countof(nameBuffer), DOTNET_PREFIX_A); + fallbackPrefix = COMPLUS_PREFIX_A; + } + + strcat_s(nameBuffer, _countof(nameBuffer), cfg); + + LPCSTR val = getEnvFptr != NULL ? getEnvFptr(nameBuffer) : getenv(nameBuffer); + if (val == NULL && fallbackPrefix != NULL) + { + strcpy_s(nameBuffer, _countof(nameBuffer), fallbackPrefix); + strcat_s(nameBuffer, _countof(nameBuffer), cfg); + val = getEnvFptr != NULL ? getEnvFptr(nameBuffer) : getenv(nameBuffer); + } + + return { val }; + } +}; diff --git a/src/coreclr/inc/clrconfigvalues.h b/src/coreclr/inc/clrconfigvalues.h index 60457fd5fa455a..312017742f9992 100644 --- a/src/coreclr/inc/clrconfigvalues.h +++ b/src/coreclr/inc/clrconfigvalues.h @@ -677,6 +677,11 @@ RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeCircularMB, W("EventPipeCircularMB"), RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeProcNumbers, W("EventPipeProcNumbers"), 0, "Enable/disable capturing processor numbers in EventPipe event headers") RETAIL_CONFIG_DWORD_INFO(INTERNAL_EventPipeOutputStreaming, W("EventPipeOutputStreaming"), 0, "Enable/disable streaming for trace file set in COMPlus_EventPipeOutputPath. Non-zero values enable streaming.") +#ifdef FEATURE_AUTO_TRACE +RETAIL_CONFIG_DWORD_INFO_EX(INTERNAL_AutoTrace_N_Tracers, W("AutoTrace_N_Tracers"), 0, "", CLRConfig::LookupOptions::ParseIntegerAsBase10) +RETAIL_CONFIG_STRING_INFO(INTERNAL_AutoTrace_Command, W("AutoTrace_Command"), "") +#endif // FEATURE_AUTO_TRACE + // // Generational Aware Analysis // diff --git a/src/coreclr/inc/cor.h b/src/coreclr/inc/cor.h index a77a9f10777424..ee82e433695ebe 100644 --- a/src/coreclr/inc/cor.h +++ b/src/coreclr/inc/cor.h @@ -1634,12 +1634,6 @@ DECLARE_INTERFACE_(IMetaDataInfo, IUnknown) // Native Link method custom value definitions. This is for N-direct support. // -#define COR_NATIVE_LINK_CUSTOM_VALUE L"COMPLUS_NativeLink" -#define COR_NATIVE_LINK_CUSTOM_VALUE_ANSI "COMPLUS_NativeLink" - -// count of chars for COR_NATIVE_LINK_CUSTOM_VALUE(_ANSI) -#define COR_NATIVE_LINK_CUSTOM_VALUE_CC 18 - #include typedef struct { diff --git a/src/coreclr/pal/src/exception/signal.cpp b/src/coreclr/pal/src/exception/signal.cpp index 59b513b87204e9..521150530fa33e 100644 --- a/src/coreclr/pal/src/exception/signal.cpp +++ b/src/coreclr/pal/src/exception/signal.cpp @@ -31,6 +31,8 @@ SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do #include "pal/palinternal.h" +#include + #include #include @@ -145,9 +147,15 @@ BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags) TRACE("Initializing signal handlers %04x\n", flags); #if !HAVE_MACH_EXCEPTIONS - char* enableAlternateStackCheck = getenv("COMPlus_EnableAlternateStackCheck"); + g_enable_alternate_stack_check = false; - g_enable_alternate_stack_check = enableAlternateStackCheck && (strtoul(enableAlternateStackCheck, NULL, 10) != 0); + CLRConfigNoCache stackCheck = CLRConfigNoCache::Get("EnableAlternateStackCheck", /*noprefix*/ false, &getenv); + if (stackCheck.IsSet()) + { + DWORD value; + if (stackCheck.TryAsInteger(10, value)) + g_enable_alternate_stack_check = (value != 0); + } #endif if (flags & PAL_INITIALIZE_REGISTER_SIGNALS) diff --git a/src/coreclr/pal/src/init/pal.cpp b/src/coreclr/pal/src/init/pal.cpp index fee6957306635e..0774ca7bf696ac 100644 --- a/src/coreclr/pal/src/init/pal.cpp +++ b/src/coreclr/pal/src/init/pal.cpp @@ -89,6 +89,7 @@ int CacheLineSize; #endif #include +#include using namespace CorUnix; @@ -268,17 +269,13 @@ EnsureStackSize(SIZE_T stackSize) void InitializeDefaultStackSize() { - char* defaultStackSizeStr = getenv("COMPlus_DefaultStackSize"); - if (defaultStackSizeStr != NULL) + CLRConfigNoCache defStackSize = CLRConfigNoCache::Get("DefaultStackSize", /*noprefix*/ false, &getenv); + if (defStackSize.IsSet()) { - errno = 0; - // Like all numeric values specific by the COMPlus_xxx variables, it is a - // hexadecimal string without any prefix. - long int size = strtol(defaultStackSizeStr, NULL, 16); - - if (errno == 0) + DWORD size; + if (defStackSize.TryAsInteger(16, size)) { - g_defaultStackSize = std::max(size, (long int)PTHREAD_STACK_MIN); + g_defaultStackSize = std::max(size, (DWORD)PTHREAD_STACK_MIN); } } @@ -406,15 +403,11 @@ Initialize( #endif // ENSURE_PRIMARY_STACK_SIZE #ifdef FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION - char* useDefaultBaseAddr = getenv("COMPlus_UseDefaultBaseAddr"); - if (useDefaultBaseAddr != NULL) + CLRConfigNoCache useDefaultBaseAddr = CLRConfigNoCache::Get("UseDefaultBaseAddr", /*noprefix*/ false, &getenv); + if (useDefaultBaseAddr.IsSet()) { - errno = 0; - // Like all numeric values specific by the COMPlus_xxx variables, it is a - // hexadecimal string without any prefix. - long int flag = strtol(useDefaultBaseAddr, NULL, 16); - - if (errno == 0) + DWORD flag; + if (useDefaultBaseAddr.TryAsInteger(16, flag)) { g_useDefaultBaseAddr = (BOOL) flag; } diff --git a/src/coreclr/pal/src/misc/tracepointprovider.cpp b/src/coreclr/pal/src/misc/tracepointprovider.cpp index 125654d4488dd3..3cfc5e0690e20e 100644 --- a/src/coreclr/pal/src/misc/tracepointprovider.cpp +++ b/src/coreclr/pal/src/misc/tracepointprovider.cpp @@ -30,6 +30,10 @@ Revision History: SET_DEFAULT_DEBUG_CHANNEL(MISC); +// clrconfignocache.h uses macro _ASSERTE, which needd to use variable +// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. +#include + /*++ Initialization logic for LTTng tracepoint providers. @@ -62,10 +66,12 @@ PAL_InitializeTracing(void) // Check if loading the LTTng providers should be disabled. // Note: this env var is formally declared in clrconfigvalues.h, but // this code is executed too early to use the mechanics that come with that definition. - char *disableValue = getenv("COMPlus_LTTng"); - if (disableValue != NULL) + CLRConfigNoCache cfgLTTng = CLRConfigNoCache::Get("LTTng", /*noprefix*/ false, &getenv); + if (cfgLTTng.IsSet()) { - fShouldLoad = strtol(disableValue, NULL, 10); + DWORD value; + if (cfgLTTng.TryAsInteger(10, value)) + fShouldLoad = (int)value; } // Get the path to the currently executing shared object (libcoreclr.so). diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index 0ae3f2eecafd05..4272105c91b53d 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -37,6 +37,8 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d #include "pal/stackstring.hpp" #include "pal/signal.hpp" +#include + #include #if HAVE_POLL #include @@ -3108,6 +3110,8 @@ PROCFormatInt(ULONG32 value) return buffer; } +static const INT UndefinedDumpType = 0; + /*++ Function PROCBuildCreateDumpCommandLine @@ -3124,8 +3128,8 @@ PROCBuildCreateDumpCommandLine( std::vector& argv, char** pprogram, char** ppidarg, - char* dumpName, - char* dumpType, + const char* dumpName, + INT dumpType, BOOL diag, BOOL crashReport) { @@ -3170,24 +3174,19 @@ PROCBuildCreateDumpCommandLine( argv.push_back(dumpName); } - if (dumpType != nullptr) + switch (dumpType) { - if (strcmp(dumpType, "1") == 0) - { - argv.push_back("--normal"); - } - else if (strcmp(dumpType, "2") == 0) - { - argv.push_back("--withheap"); - } - else if (strcmp(dumpType, "3") == 0) - { - argv.push_back("--triage"); - } - else if (strcmp(dumpType, "4") == 0) - { - argv.push_back("--full"); - } + case 1: argv.push_back("--normal"); + break; + case 2: argv.push_back("--withheap"); + break; + case 3: argv.push_back("--triage"); + break; + case 4: argv.push_back("--full"); + break; + case UndefinedDumpType: + default: + break; } if (diag) @@ -3277,19 +3276,37 @@ Return BOOL PROCAbortInitialize() { - char* enabled = getenv("COMPlus_DbgEnableMiniDump"); - if (enabled != nullptr && _stricmp(enabled, "1") == 0) + CLRConfigNoCache enabledCfg= CLRConfigNoCache::Get("DbgEnableMiniDump", /*noprefix*/ false, &getenv); + + DWORD enabled = 0; + if (enabledCfg.IsSet() + && enabledCfg.TryAsInteger(10, enabled) + && enabled) { - char* dumpName = getenv("COMPlus_DbgMiniDumpName"); - char* dumpType = getenv("COMPlus_DbgMiniDumpType"); - char* diagStr = getenv("COMPlus_CreateDumpDiagnostics"); - BOOL diag = diagStr != nullptr && strcmp(diagStr, "1") == 0; - char* crashReportStr = getenv("COMPlus_EnableCrashReport"); - BOOL crashReport = crashReportStr != nullptr && strcmp(crashReportStr, "1") == 0; + CLRConfigNoCache dmpNameCfg = CLRConfigNoCache::Get("DbgMiniDumpName", /*noprefix*/ false, &getenv); + + CLRConfigNoCache dmpTypeCfg = CLRConfigNoCache::Get("DbgMiniDumpType", /*noprefix*/ false, &getenv); + DWORD dumpType = UndefinedDumpType; + if (dmpTypeCfg.IsSet()) + { + (void)dmpTypeCfg.TryAsInteger(10, dumpType); + if (dumpType < 1 || dumpType > 4) + { + dumpType = UndefinedDumpType; + } + } + + CLRConfigNoCache createDumpCfg = CLRConfigNoCache::Get("CreateDumpDiagnostics", /*noprefix*/ false, &getenv); + DWORD val = 0; + BOOL diag = createDumpCfg.IsSet() && createDumpCfg.TryAsInteger(10, val) && val == 1; + + CLRConfigNoCache enabldReportCfg = CLRConfigNoCache::Get("EnableCrashReport", /*noprefix*/ false, &getenv); + val = 0; + BOOL crashReport = enabldReportCfg.IsSet() && enabldReportCfg.TryAsInteger(10, val) && val == 1; char* program = nullptr; char* pidarg = nullptr; - if (!PROCBuildCreateDumpCommandLine(g_argvCreateDump, &program, &pidarg, dumpName, dumpType, diag, crashReport)) + if (!PROCBuildCreateDumpCommandLine(g_argvCreateDump, &program, &pidarg, dmpNameCfg.AsString(), dumpType, diag, crashReport)) { return FALSE; } @@ -3325,23 +3342,18 @@ PAL_GenerateCoreDump( BOOL diag) { std::vector argvCreateDump; - char dumpTypeStr[16]; if (dumpType < 1 || dumpType > 4) { return FALSE; } - if (_itoa_s(dumpType, dumpTypeStr, sizeof(dumpTypeStr), 10) != 0) - { - return FALSE; - } if (dumpName != nullptr && dumpName[0] == '\0') { dumpName = nullptr; } char* program = nullptr; char* pidarg = nullptr; - BOOL result = PROCBuildCreateDumpCommandLine(argvCreateDump, &program, &pidarg, (char*)dumpName, dumpTypeStr, diag, false); + BOOL result = PROCBuildCreateDumpCommandLine(argvCreateDump, &program, &pidarg, dumpName, dumpType, diag, false); if (result) { result = PROCCreateCrashDump(argvCreateDump); diff --git a/src/coreclr/utilcode/clrconfig.cpp b/src/coreclr/utilcode/clrconfig.cpp index 59d32c0c43091d..98518c4dd8ebc1 100644 --- a/src/coreclr/utilcode/clrconfig.cpp +++ b/src/coreclr/utilcode/clrconfig.cpp @@ -9,12 +9,7 @@ #include "sstring.h" #include "ex.h" -// Config prefixes -#define COMPLUS_PREFIX W("COMPlus_") -#define LEN_OF_COMPLUS_PREFIX StrLen(COMPLUS_PREFIX) - -#define DOTNET_PREFIX W("DOTNET_") -#define LEN_OF_DOTNET_PREFIX StrLen(DOTNET_PREFIX) +#include "clrconfignocache.h" using ConfigDWORDInfo = CLRConfig::ConfigDWORDInfo; using ConfigStringInfo = CLRConfig::ConfigStringInfo; @@ -199,7 +194,23 @@ namespace } if (len != 0) + { ret = temp.GetCopyOfUnicodeString(); + +#if defined(DEBUG) && !defined(SELF_NO_HOST) + // Validate the cache and no-cache logic result in the same answer + SString nameToConvert(name); + SString nameAsUTF8; + nameToConvert.ConvertToUTF8(nameAsUTF8); + SString valueAsUTF8; + temp.ConvertToUTF8(valueAsUTF8); + + CLRConfigNoCache nonCache = CLRConfigNoCache::Get(nameAsUTF8.GetUTF8NoConvert(), noPrefix); + LPCSTR valueNoCache = nonCache.AsString(); + + _ASSERTE(SString::_stricmp(valueNoCache, valueAsUTF8.GetUTF8NoConvert()) == 0); +#endif // defined(DEBUG) && !defined(SELF_NO_HOST) + } } EX_CATCH_HRESULT(hr); @@ -405,6 +416,13 @@ namespace #undef CONFIG_DWORD_INFO_EX #undef CONFIG_STRING_INFO_EX +BOOL CLRConfig::IsConfigEnabled(const ConfigDWORDInfo & info) +{ + WRAPPER_NO_CONTRACT; + + return IsConfigOptionSpecified(info.name); +} + // // Look up a DWORD config value. // @@ -471,6 +489,8 @@ DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info, DWORD defaultValue // static DWORD CLRConfig::GetConfigValue(const ConfigDWORDInfo & info) { + WRAPPER_NO_CONTRACT; + bool unused; return GetConfigValue(info, &unused); } diff --git a/src/coreclr/vm/autotrace.cpp b/src/coreclr/vm/autotrace.cpp index 8ebfdd90766631..9d266d3d9f893d 100644 --- a/src/coreclr/vm/autotrace.cpp +++ b/src/coreclr/vm/autotrace.cpp @@ -27,20 +27,19 @@ HANDLE auto_trace_event; static size_t g_n_tracers = 1; -static const WCHAR* command_format = W("%hs -p %d"); +static const WCHAR* command_format = W("%s -p %d"); static WCHAR* command = nullptr; void auto_trace_init() { - char *nAutoTracersValue = getenv("COMPlus_AutoTrace_N_Tracers"); - if (nAutoTracersValue != NULL) + if (CLRConfig::IsConfigEnabled(CLRConfig::INTERNAL_AutoTrace_N_Tracers)) { - g_n_tracers = strtoul(nAutoTracersValue, NULL, 10); + g_n_tracers = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AutoTrace_N_Tracers); } // Get the command to run auto-trace. Note that the `-p ` option // will be automatically added for you - char *commandTextValue = getenv("COMPlus_AutoTrace_Command"); + LPWSTR commandTextValue = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AutoTrace_Command); if (commandTextValue != NULL) { DWORD currentProcessId = GetCurrentProcessId(); diff --git a/src/coreclr/vm/perfmap.cpp b/src/coreclr/vm/perfmap.cpp index f79460fc4fce3f..31da16cac5586d 100644 --- a/src/coreclr/vm/perfmap.cpp +++ b/src/coreclr/vm/perfmap.cpp @@ -7,6 +7,7 @@ #include "common.h" #if defined(FEATURE_PERFMAP) && !defined(DACCESS_COMPILE) +#include #include "perfmap.h" #include "perfinfo.h" #include "pal.h" @@ -49,16 +50,18 @@ void PerfMap::Initialize() s_enabled = true; - char jitdumpPath[4096]; + const char* jitdumpPath; + char jitdumpPathBuffer[4096]; - // CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_PerfMapJitDumpPath) returns a LPWSTR - // Use GetEnvironmentVariableA because it is simpler. - // Keep comment here to make it searchable. - DWORD len = GetEnvironmentVariableA("COMPlus_PerfMapJitDumpPath", jitdumpPath, sizeof(jitdumpPath) - 1); - - if (len == 0) + CLRConfigNoCache value = CLRConfigNoCache::Get("PerfMapJitDumpPath"); + if (value.IsSet()) + { + jitdumpPath = value.AsString(); + } + else { - GetTempPathA(sizeof(jitdumpPath) - 1, jitdumpPath); + GetTempPathA(sizeof(jitdumpPathBuffer) - 1, jitdumpPathBuffer); + jitdumpPath = jitdumpPathBuffer; } PAL_PerfJitDump_Start(jitdumpPath);