1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4// EEConfig.CPP
5//
6
7//
8// Fetched configuration data from the registry (should we Jit, run GC checks ...)
9//
10//
11
12
13#include "common.h"
14#ifdef FEATURE_COMINTEROP
15#include <appxutil.h>
16#endif
17#include "eeconfig.h"
18#include "method.hpp"
19#include "eventtrace.h"
20#include "eehash.h"
21#include "eemessagebox.h"
22#include "corhost.h"
23#include "regex_util.h"
24#include "clr/fs/path.h"
25#include "configuration.h"
26
27using namespace clr;
28
29#define DEFAULT_ZAP_SET W("")
30
31#define DEFAULT_APP_DOMAIN_LEAKS 0
32
33
34#ifdef STRESS_HEAP
35// Global counter to disable GCStress. This is needed so we can inhibit
36// GC stres collections without resetting the global GCStressLevel, which
37// is relied on by the EH code and the JIT code (for handling patched
38// managed code, and GC stress exception) after GC stress is dynamically
39// turned off.
40Volatile<DWORD> GCStressPolicy::InhibitHolder::s_nGcStressDisabled = 0;
41#endif // STRESS_HEAP
42
43
44ConfigSource::ConfigSource()
45{
46 CONTRACTL {
47 NOTHROW;
48 GC_NOTRIGGER;
49 MODE_ANY;
50 FORBID_FAULT;
51 } CONTRACTL_END;
52
53 m_pNext = this;
54 m_pPrev = this;
55}// ConfigSource::ConfigSource
56
57ConfigSource::~ConfigSource()
58{
59 CONTRACTL {
60 NOTHROW;
61 FORBID_FAULT;
62 GC_NOTRIGGER;
63 MODE_ANY;
64 } CONTRACTL_END;
65
66 for(ConfigStringHashtable::Iterator iter = m_Table.Begin(), end = m_Table.End(); iter != end; iter++)
67 {
68 ConfigStringKeyValuePair * pair = *(iter);
69 delete[] pair->key;
70 delete[] pair->value;
71 delete pair;
72 }
73}// ConfigSource::~ConfigSource
74
75ConfigStringHashtable * ConfigSource::Table()
76{
77 LIMITED_METHOD_CONTRACT;
78 return &(m_Table);
79}// ConfigSource::Table
80
81void ConfigSource::Add(ConfigSource* prev)
82{
83 CONTRACTL {
84 NOTHROW;
85 GC_NOTRIGGER;
86 MODE_ANY;
87 PRECONDITION(CheckPointer(prev));
88 PRECONDITION(CheckPointer(prev->m_pNext));
89 } CONTRACTL_END;
90
91 m_pPrev = prev;
92 m_pNext = prev->m_pNext;
93
94 m_pNext->m_pPrev = this;
95 prev->m_pNext = this;
96}// ConfigSource::Add
97
98
99
100/**************************************************************/
101// Poor mans narrow
102LPUTF8 NarrowWideChar(__inout_z LPWSTR str)
103{
104 CONTRACT (LPUTF8)
105 {
106 NOTHROW;
107 GC_NOTRIGGER;
108 MODE_ANY;
109 PRECONDITION(CheckPointer(str, NULL_OK));
110 POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
111 } CONTRACT_END;
112
113 if (str != 0) {
114 LPWSTR fromPtr = str;
115 LPUTF8 toPtr = (LPUTF8) str;
116 LPUTF8 result = toPtr;
117 while(*fromPtr != 0)
118 *toPtr++ = (char) *fromPtr++;
119 *toPtr = 0;
120 RETURN result;
121 }
122 RETURN NULL;
123}
124
125extern void UpdateGCSettingFromHost ();
126
127HRESULT EEConfig::Setup()
128{
129 STANDARD_VM_CONTRACT;
130
131 ETWOnStartup (EEConfigSetup_V1,EEConfigSetupEnd_V1);
132
133 // This 'new' uses EEConfig's overloaded new, which uses a static memory buffer and will
134 // not fail
135 EEConfig *pConfig = new EEConfig();
136
137 HRESULT hr = pConfig->Init();
138
139 if (FAILED(hr))
140 return hr;
141
142 EEConfig *pConfigOld = NULL;
143 pConfigOld = InterlockedCompareExchangeT(&g_pConfig, pConfig, NULL);
144
145 _ASSERTE(pConfigOld == NULL && "EEConfig::Setup called multiple times!");
146
147 UpdateGCSettingFromHost();
148
149 return S_OK;
150}
151
152/**************************************************************/
153// For in-place constructor
154BYTE g_EEConfigMemory[sizeof(EEConfig)];
155
156void *EEConfig::operator new(size_t size)
157{
158 CONTRACT(void*) {
159 FORBID_FAULT;
160 GC_NOTRIGGER;
161 NOTHROW;
162 MODE_ANY;
163 POSTCONDITION(CheckPointer(RETVAL));
164 } CONTRACT_END;
165
166 RETURN g_EEConfigMemory;
167}
168
169/**************************************************************/
170HRESULT EEConfig::Init()
171{
172 STANDARD_VM_CONTRACT;
173
174 fInited = false;
175
176#ifdef VERIFY_HEAP
177 iGCHeapVerify = 0; // Heap Verification OFF by default
178#endif
179
180#if defined(STRESS_HEAP) || defined(_DEBUG)
181 iGCStress = 0;
182#endif
183
184#ifdef STRESS_HEAP
185 iGCStressMix = 0;
186 iGCStressStep = 1;
187#endif
188
189 fGCBreakOnOOM = false;
190 iGCgen0size = 0;
191 iGCSegmentSize = 0;
192 iGCconcurrent = 0;
193#ifdef _DEBUG
194 iGCLatencyMode = -1;
195#endif //_DEBUG
196 iGCForceCompact = 0;
197 iGCHoardVM = 0;
198 iGCLOHCompactionMode = 0;
199 iGCLOHThreshold = 0;
200 iGCHeapCount = 0;
201 iGCNoAffinitize = 0;
202 iGCAffinityMask = 0;
203
204#ifdef GCTRIMCOMMIT
205 iGCTrimCommit = 0;
206#endif
207
208 m_fFreepZapSet = false;
209
210 dwSpinInitialDuration = 0x32;
211 dwSpinBackoffFactor = 0x3;
212 dwSpinLimitProcCap = 0xFFFFFFFF;
213 dwSpinLimitProcFactor = 0x4E20;
214 dwSpinLimitConstant = 0x0;
215 dwSpinRetryCount = 0xA;
216 dwMonitorSpinCount = 0;
217
218 iJitOptimizeType = OPT_DEFAULT;
219 fJitFramed = false;
220 fJitAlignLoops = false;
221 fAddRejitNops = false;
222 fJitMinOpts = false;
223 fPInvokeRestoreEsp = (DWORD)-1;
224
225 fLegacyNullReferenceExceptionPolicy = false;
226 fLegacyUnhandledExceptionPolicy = false;
227
228#ifdef FEATURE_CORRUPTING_EXCEPTIONS
229 // By default, there is not pre-V4 CSE policy
230 fLegacyCorruptedStateExceptionsPolicy = false;
231#endif // FEATURE_CORRUPTING_EXCEPTIONS
232
233 fNgenBindOptimizeNonGac = false;
234 fStressLog = false;
235 fProbeForStackOverflow = true;
236
237 INDEBUG(fStressLog = true;)
238
239#ifdef _DEBUG
240 fExpandAllOnLoad = false;
241 fDebuggable = false;
242 fStressOn = false;
243 apiThreadStressCount = 0;
244 pPrestubHalt = 0;
245 pPrestubGC = 0;
246 pszBreakOnClassLoad = 0;
247 pszBreakOnClassBuild = 0;
248 pszBreakOnMethodName = 0;
249 pszDumpOnClassLoad = 0;
250 pszBreakOnInteropStubSetup = 0;
251 pszBreakOnComToClrNativeInfoInit = 0;
252 pszBreakOnStructMarshalSetup = 0;
253 fJitVerificationDisable= false;
254 fVerifierOff = false;
255
256#ifdef ENABLE_STARTUP_DELAY
257 iStartupDelayMS = 0;
258#endif
259 iPerfNumAllocsThreshold = 0;
260 iPerfAllocsSizeThreshold = 0;
261 pPerfTypesToLog = NULL;
262 iFastGCStress = 0;
263 iInjectFatalError = 0;
264 fSaveThreadInfo = FALSE;
265 dwSaveThreadInfoMask = (DWORD)-1;
266#ifdef TEST_DATA_CONSISTENCY
267 // indicates whether to run the self test to determine that we are detecting when a lock is held by the
268 // LS in DAC builds. Initialized via the environment variable TestDataConsistency
269 fTestDataConsistency = false;
270#endif
271
272 // In Thread::SuspendThread(), default the timeout to 2 seconds. If the suspension
273 // takes longer, assert (but keep trying).
274 m_SuspendThreadDeadlockTimeoutMs = 2000;
275
276 // For now, give our suspension attempts 40 seconds to succeed before trapping to
277 // the debugger. Note that we should probably lower this when the JIT is run in
278 // preemtive mode, as we really should not be starving the GC for 10's of seconds
279 m_SuspendDeadlockTimeout = 40000;
280#endif // _DEBUG
281
282#ifdef FEATURE_COMINTEROP
283 bLogCCWRefCountChange = false;
284 pszLogCCWRefCountChange = NULL;
285#endif // FEATURE_COMINTEROP
286
287#ifdef _DEBUG
288 m_fAssertOnBadImageFormat = false;
289 m_fAssertOnFailFast = true;
290
291 fSuppressChecks = false;
292 fConditionalContracts = false;
293 fEnableFullDebug = false;
294#endif
295
296#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
297 DoubleArrayToLargeObjectHeapThreshold = 1000;
298#endif
299
300 iRequireZaps = REQUIRE_ZAPS_NONE;
301
302 pZapSet = DEFAULT_ZAP_SET;
303
304#if defined(_TARGET_X86_) || defined(_TARGET_AMD64_)
305 dwDisableStackwalkCache = 0;
306#else // _TARGET_X86_
307 dwDisableStackwalkCache = 1;
308#endif // _TARGET_X86_
309
310 szZapBBInstr = NULL;
311 szZapBBInstrDir = NULL;
312
313 fAppDomainUnload = true;
314 dwADURetryCount=1000;
315
316#ifdef _DEBUG
317 // interop logging
318 m_pTraceIUnknown = NULL;
319 m_TraceWrapper = 0;
320#endif
321
322#ifdef _DEBUG
323 dwNgenForceFailureMask = 0;
324 dwNgenForceFailureCount = 0;
325 dwNgenForceFailureKind = 0;
326#endif
327
328 iGCPollType = GCPOLL_TYPE_DEFAULT;
329
330#ifdef _DEBUG
331 fShouldInjectFault = 0;
332 testThreadAbort = 0;
333#endif
334
335 m_fInteropValidatePinnedObjects = false;
336 m_fInteropLogArguments = false;
337
338#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
339 fStubLinkerUnwindInfoVerificationOn = FALSE;
340#endif
341
342#if defined(_DEBUG) && defined(WIN64EXCEPTIONS)
343 fSuppressLockViolationsOnReentryFromOS = false;
344#endif
345
346#if defined(_DEBUG) && defined(_TARGET_AMD64_)
347 // For determining if we should force generation of long jump dispatch stubs.
348 m_cGenerateLongJumpDispatchStubRatio = (size_t)(-1);
349 m_cDispatchStubsGenerated = 0;
350#endif
351
352#if defined(_DEBUG)
353 bDiagnosticSuspend = false;
354#endif
355
356#if defined(FEATURE_TIERED_COMPILATION)
357 fTieredCompilation = false;
358 fTieredCompilation_CallCounting = false;
359 fTieredCompilation_OptimizeTier0 = false;
360 tieredCompilation_tier1CallCountThreshold = 1;
361 tieredCompilation_tier1CallCountingDelayMs = 0;
362#endif
363
364#if defined(FEATURE_GDBJIT) && defined(_DEBUG)
365 pszGDBJitElfDump = NULL;
366#endif // FEATURE_GDBJIT && _DEBUG
367
368#if defined(FEATURE_GDBJIT_FRAME)
369 fGDBJitEmitDebugFrame = false;
370#endif
371
372 // After initialization, register the code:#GetConfigValueCallback method with code:CLRConfig to let
373 // CLRConfig access config files. This is needed because CLRConfig lives outside the VM and can't
374 // statically link to EEConfig.
375 CLRConfig::RegisterGetConfigValueCallback(&GetConfigValueCallback);
376
377 return S_OK;
378}
379
380#ifdef _DEBUG
381static int DumpConfigTable(ConfigStringHashtable* table, __in_z LPCSTR label, int count)
382{
383 LIMITED_METHOD_CONTRACT;
384 LOG((LF_ALWAYS, LL_ALWAYS, label, count++));
385 LOG((LF_ALWAYS, LL_ALWAYS, "*********************************\n", count++));
386 for(ConfigStringHashtable::Iterator iter = table->Begin(), end = table->End(); iter != end; iter++)
387 {
388 ConfigStringKeyValuePair * pair = *(iter);
389 LPCWSTR keyString = pair->key;
390 LPCWSTR data = pair->value;
391 LOG((LF_ALWAYS, LL_ALWAYS, "%S = %S\n", keyString, data));
392 }
393 LOG((LF_ALWAYS, LL_ALWAYS, "\n"));
394 return count;
395}
396#endif
397
398/**************************************************************/
399HRESULT EEConfig::Cleanup()
400{
401 CONTRACTL {
402 FORBID_FAULT;
403 NOTHROW;
404 GC_NOTRIGGER;
405 MODE_ANY;
406 } CONTRACTL_END;
407
408#ifdef _DEBUG
409 if (g_pConfig) {
410 // TODO: Do we even need this? CLRConfig::GetConfigValue has FORBID_FAULT in its contract.
411 FAULT_NOT_FATAL(); // If GetConfigValue fails the alloc, that's ok.
412
413 DWORD setting = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpConfiguration);
414 if (setting != 0)
415 {
416 ConfigList::ConfigIter iter(&m_Configuration);
417 int count = 0;
418 for(ConfigStringHashtable* table = iter.Next();table; table = iter.Next())
419 {
420 count = DumpConfigTable(table, "\nSystem Configuration Table: %d\n", count);
421 }
422 ConfigList::ConfigIter iter2(&m_Configuration);
423 count = 0;
424 for (ConfigStringHashtable* table = iter2.Previous();table; table = iter2.Previous())
425 {
426 count = DumpConfigTable(table, "\nApplication Configuration Table: %d\n", count);
427 }
428 }
429 }
430#endif
431
432 if (m_fFreepZapSet)
433 delete[] pZapSet;
434 delete[] szZapBBInstr;
435
436 if (pRequireZapsList)
437 delete pRequireZapsList;
438
439 if (pRequireZapsExcludeList)
440 delete pRequireZapsExcludeList;
441
442 if (pReadyToRunExcludeList)
443 delete pReadyToRunExcludeList;
444
445#ifdef _DEBUG
446 if (pForbidZapsList)
447 delete pForbidZapsList;
448
449 if (pForbidZapsExcludeList)
450 delete pForbidZapsExcludeList;
451#endif
452
453#ifdef FEATURE_COMINTEROP
454 if (pszLogCCWRefCountChange)
455 delete [] pszLogCCWRefCountChange;
456#endif // FEATURE_COMINTEROP
457
458#ifdef _DEBUG
459 if (pPrestubHalt)
460 {
461 DestroyMethList(pPrestubHalt);
462 pPrestubHalt = NULL;
463 }
464 if (pPrestubGC)
465 {
466 DestroyMethList(pPrestubGC);
467 pPrestubGC = NULL;
468 }
469 if (pSkipGCCoverageList)
470 {
471 delete pSkipGCCoverageList;
472 pSkipGCCoverageList = NULL;
473 }
474
475 delete [] pszBreakOnClassLoad;
476 delete [] pszBreakOnClassBuild;
477 delete [] pszBreakOnInstantiation;
478 delete [] pszBreakOnMethodName;
479 delete [] pszDumpOnClassLoad;
480 delete [] pszBreakOnInteropStubSetup;
481 delete [] pszBreakOnComToClrNativeInfoInit;
482 delete [] pszBreakOnStructMarshalSetup;
483 delete [] pszGcCoverageOnMethod;
484#endif
485#ifdef _DEBUG
486 if (pPerfTypesToLog)
487 {
488 DestroyTypeList(pPerfTypesToLog);
489 pPerfTypesToLog = NULL;
490 }
491#endif
492
493 return S_OK;
494}
495
496
497//
498// NOTE: This function is deprecated; use the CLRConfig class instead.
499// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
500//
501HRESULT EEConfig::GetConfigString_DontUse_(__in_z LPCWSTR name, __deref_out_z LPWSTR *outVal, BOOL fPrependCOMPLUS, ConfigSearch direction)
502{
503 CONTRACT(HRESULT) {
504 NOTHROW;
505 GC_NOTRIGGER;
506 MODE_ANY;
507 INJECT_FAULT (CONTRACT_RETURN E_OUTOFMEMORY);
508 PRECONDITION(CheckPointer(name));
509 POSTCONDITION(CheckPointer(outVal, NULL_OK));
510 } CONTRACT_END;
511
512 LPWSTR pvalue = REGUTIL::GetConfigString_DontUse_(name, fPrependCOMPLUS);
513 if(pvalue == NULL && g_pConfig != NULL)
514 {
515 LPCWSTR pResult;
516 if(SUCCEEDED(g_pConfig->GetConfiguration_DontUse_(name, direction, &pResult)) && pResult != NULL)
517 {
518 size_t len = wcslen(pResult) + 1;
519 pvalue = new (nothrow) WCHAR[len];
520 if (pvalue == NULL)
521 {
522 RETURN E_OUTOFMEMORY;
523 }
524
525 wcscpy_s(pvalue,len,pResult);
526 }
527 }
528
529 *outVal = pvalue;
530
531 RETURN S_OK;
532}
533
534
535//
536// NOTE: This function is deprecated; use the CLRConfig class instead.
537// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
538//
539DWORD EEConfig::GetConfigDWORD_DontUse_(__in_z LPCWSTR name, DWORD defValue, DWORD level, BOOL fPrependCOMPLUS, ConfigSearch direction)
540{
541 CONTRACTL {
542 NOTHROW;
543 GC_NOTRIGGER;
544 MODE_ANY;
545 PRECONDITION(CheckPointer(name));
546 } CONTRACTL_END;
547
548 // <TODO>@TODO: After everyone has moved off registry, key remove the following line in golden</TODO>
549 DWORD result = REGUTIL::GetConfigDWORD_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
550 if(result == defValue && g_pConfig != NULL)
551 {
552 LPCWSTR pvalue;
553 if(SUCCEEDED(g_pConfig->GetConfiguration_DontUse_(name, direction, &pvalue)) && pvalue != NULL)
554 {
555 WCHAR *end;
556 errno = 0;
557 result = wcstoul(pvalue, &end, 0);
558 // errno is ERANGE if the number is out of range, and end is set to pvalue if
559 // no valid conversion exists.
560 if (errno == ERANGE || end == pvalue)
561 {
562 result = defValue;
563 }
564 }
565 }
566
567 return result;
568}
569
570//
571// NOTE: This function is deprecated; use the CLRConfig class instead.
572// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
573//
574// Note for PAL: right now PAL does not have a _wcstoui64 API, so I am temporarily reading in all numbers as
575// a 32-bit number. When we have the _wcstoui64 API on MAC we will use that instead of wcstoul.
576ULONGLONG EEConfig::GetConfigULONGLONG_DontUse_(__in_z LPCWSTR name, ULONGLONG defValue, DWORD level, BOOL fPrependCOMPLUS, ConfigSearch direction)
577{
578 CONTRACTL {
579 NOTHROW;
580 GC_NOTRIGGER;
581 MODE_ANY;
582 PRECONDITION(CheckPointer(name));
583 } CONTRACTL_END;
584
585 // <TODO>@TODO: After everyone has moved off registry, key remove the following line in golden</TODO>
586 ULONGLONG result = REGUTIL::GetConfigULONGLONG_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
587 if(result == defValue && g_pConfig != NULL)
588 {
589 LPCWSTR pvalue;
590 if(SUCCEEDED(g_pConfig->GetConfiguration_DontUse_(name, direction, &pvalue)) && pvalue != NULL)
591 {
592 WCHAR *end;
593 errno = 0;
594 result = _wcstoui64(pvalue, &end, 0);
595 // errno is ERANGE if the number is out of range, and end is set to pvalue if
596 // no valid conversion exists.
597 if (errno == ERANGE || end == pvalue)
598 {
599 result = defValue;
600 }
601 }
602 }
603
604 return result;
605}
606
607//
608// NOTE: This function is deprecated; use the CLRConfig class instead.
609// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
610//
611// This is very similar to GetConfigDWORD, except that it favors the settings in config files over those in the
612// registry. This is the Shim's policy with configuration flags, and there are a few flags in EEConfig that adhere
613// to this policy.
614//
615DWORD EEConfig::GetConfigDWORDFavoringConfigFile_DontUse_(__in_z LPCWSTR name,
616 DWORD defValue,
617 DWORD level,
618 BOOL fPrependCOMPLUS,
619 ConfigSearch direction)
620{
621 CONTRACTL
622 {
623 NOTHROW;
624 GC_NOTRIGGER;
625 MODE_ANY;
626 PRECONDITION(CheckPointer(name));
627 } CONTRACTL_END;
628
629 DWORD result = defValue;
630
631 if (g_pConfig != NULL)
632 {
633 LPCWSTR pvalue;
634 if (SUCCEEDED(g_pConfig->GetConfiguration_DontUse_(name, direction, &pvalue)) && pvalue != NULL)
635 {
636 WCHAR *end = NULL;
637 errno = 0;
638 result = wcstoul(pvalue, &end, 0);
639 // errno is ERANGE if the number is out of range, and end is set to pvalue if
640 // no valid conversion exists.
641 if (errno == ERANGE || end == pvalue)
642 {
643 result = defValue;
644 }
645 }
646 else
647 {
648 result = REGUTIL::GetConfigDWORD_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
649 }
650 }
651
652 return result;
653}
654
655//
656// NOTE: This function is deprecated; use the CLRConfig class instead.
657// To use the CLRConfig class, add an entry in file:../inc/CLRConfigValues.h.
658//
659DWORD EEConfig::GetConfigDWORDInternal_DontUse_(__in_z LPCWSTR name, DWORD defValue, DWORD level, BOOL fPrependCOMPLUS, ConfigSearch direction)
660{
661 CONTRACTL {
662 NOTHROW;
663 GC_NOTRIGGER;
664 MODE_ANY;
665 PRECONDITION(CheckPointer(name));
666 } CONTRACTL_END;
667
668 // <TODO>@TODO: After everyone has moved off registry, key remove the following line in golden</TODO>
669 DWORD result = REGUTIL::GetConfigDWORD_DontUse_(name, defValue, (REGUTIL::CORConfigLevel)level, fPrependCOMPLUS);
670 if(result == defValue)
671 {
672 LPCWSTR pvalue;
673 if(SUCCEEDED(GetConfiguration_DontUse_(name, direction, &pvalue)) && pvalue != NULL)
674 {
675 WCHAR *end = NULL;
676 errno = 0;
677 result = wcstoul(pvalue, &end, 0);
678 // errno is ERANGE if the number is out of range, and end is set to pvalue if
679 // no valid conversion exists.
680 if (errno == ERANGE || end == pvalue)
681 {
682 result = defValue;
683 }
684 }
685 }
686 return result;
687}
688
689/**************************************************************/
690
691HRESULT EEConfig::sync()
692{
693 CONTRACTL {
694 THROWS;
695 GC_NOTRIGGER;
696 MODE_ANY;
697 INJECT_FAULT (return E_OUTOFMEMORY);
698 } CONTRACTL_END;
699
700 ETWOnStartup (EEConfigSync_V1, EEConfigSyncEnd_V1);
701
702 HRESULT hr = S_OK;
703
704 // Note the global variable is not updated directly by the GetRegKey function
705 // so we only update it once (to avoid reentrancy windows)
706
707#ifdef _DEBUG
708 iFastGCStress = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_FastGCStress, iFastGCStress);
709
710 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GcCoverage, (LPWSTR*)&pszGcCoverageOnMethod));
711 pszGcCoverageOnMethod = NarrowWideChar((LPWSTR)pszGcCoverageOnMethod);
712 iGCLatencyMode = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GCLatencyMode, iGCLatencyMode);
713#endif
714
715 if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_ARMEnabled))
716 {
717 g_fEnableARM = TRUE;
718 }
719
720 bool gcConcurrentWasForced = false;
721 // The CLRConfig value for UNSUPPORTED_gcConcurrent defaults to -1, and treats any
722 // positive value as 'forcing' concurrent GC to be on. Because the standard logic
723 // for mapping a DWORD CLRConfig to a boolean configuration treats -1 as true (just
724 // like any other nonzero value), we will explicitly check the DWORD later if this
725 // check returns false.
726 gcConcurrentWasForced = Configuration::GetKnobBooleanValue(W("System.GC.Concurrent"), false);
727
728 int gcConcurrentConfigVal = 0;
729 if (!gcConcurrentWasForced)
730 {
731 gcConcurrentConfigVal = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcConcurrent);
732 gcConcurrentWasForced = (gcConcurrentConfigVal > 0);
733 }
734
735 if (gcConcurrentWasForced || (gcConcurrentConfigVal == -1 && g_IGCconcurrent))
736 iGCconcurrent = TRUE;
737
738 // Disable concurrent GC during ngen for the rare case a GC gets triggered, causing problems
739 if (IsCompilationProcess())
740 iGCconcurrent = FALSE;
741
742#if defined(STRESS_HEAP) || defined(_DEBUG)
743 iGCStress = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCStress);
744#endif
745
746#ifdef STRESS_HEAP
747 BOOL bGCStressAndHeapVerifyAllowed = true;
748 iGCStressMix = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GCStressMix);
749 iGCStressStep = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GCStressStep);
750
751 // For GC stress mix mode ensure reasonable defaults
752 if (iGCStressMix != 0)
753 {
754 if (iGCStress == 0)
755 iGCStress |= int(GCSTRESS_ALLOC) | int(GCSTRESS_TRANSITION);
756 if (iGCStressStep == 0 || iGCStressStep == 1)
757 iGCStressStep = 0x10;
758 }
759
760 if (iGCStress)
761 {
762 LPWSTR pszGCStressExe = NULL;
763
764 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_RestrictedGCStressExe, &pszGCStressExe));
765 if (pszGCStressExe != NULL)
766 {
767 if (*pszGCStressExe != W('\0'))
768 {
769 bGCStressAndHeapVerifyAllowed = false;
770
771 PathString wszFileName;
772 if (WszGetModuleFileName(NULL, wszFileName) != 0)
773 {
774 // just keep the name
775 LPCWSTR pwszName = wcsrchr(wszFileName, W('\\'));
776 pwszName = (pwszName == NULL) ? wszFileName.GetUnicode() : (pwszName + 1);
777
778 if (SString::_wcsicmp(pwszName,pszGCStressExe) == 0)
779 {
780 bGCStressAndHeapVerifyAllowed = true;
781 }
782 }
783 }
784 delete [] pszGCStressExe;
785 }
786
787 if (bGCStressAndHeapVerifyAllowed)
788 {
789 if (gcConcurrentWasForced)
790 {
791#ifdef _DEBUG
792 iFastGCStress = 0;
793#endif
794 iGCStress |= int(GCSTRESS_ALLOC) | int(GCSTRESS_TRANSITION);
795 }
796 else
797 {
798 // If GCStress was enabled, and
799 // If GcConcurrent was NOT explicitly specified in the environment, and
800 // If GSCtressMix was NOT specified
801 // Then let's turn off concurrent GC since it make objects move less
802 if (iGCStressMix == 0)
803 {
804 iGCconcurrent =
805 g_IGCconcurrent = 0;
806 }
807 }
808 }
809 else
810 {
811 iGCStress = 0;
812 iGCStressMix = 0;
813 iGCStressStep = 1;
814 }
815 }
816
817#ifdef VERIFY_HEAP
818 if (bGCStressAndHeapVerifyAllowed)
819 {
820 iGCHeapVerify = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_HeapVerify, iGCHeapVerify);
821 }
822#endif
823
824#endif //STRESS_HEAP
825
826#ifdef _WIN64
827 iGCAffinityMask = GetConfigULONGLONG_DontUse_(CLRConfig::EXTERNAL_GCHeapAffinitizeMask, iGCAffinityMask);
828 if (!iGCAffinityMask) iGCAffinityMask = Configuration::GetKnobULONGLONGValue(W("System.GC.HeapAffinitizeMask"));
829 if (!iGCSegmentSize) iGCSegmentSize = GetConfigULONGLONG_DontUse_(CLRConfig::UNSUPPORTED_GCSegmentSize, iGCSegmentSize);
830 if (!iGCgen0size) iGCgen0size = GetConfigULONGLONG_DontUse_(CLRConfig::UNSUPPORTED_GCgen0size, iGCgen0size);
831#else
832 iGCAffinityMask = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_GCHeapAffinitizeMask, iGCAffinityMask);
833 if (!iGCAffinityMask) iGCAffinityMask = Configuration::GetKnobDWORDValue(W("System.GC.HeapAffinitizeMask"), 0);
834 if (!iGCSegmentSize) iGCSegmentSize = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCSegmentSize, iGCSegmentSize);
835 if (!iGCgen0size) iGCgen0size = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCgen0size, iGCgen0size);
836#endif //_WIN64
837
838 if (g_IGCHoardVM)
839 iGCHoardVM = g_IGCHoardVM;
840 else
841 iGCHoardVM = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCRetainVM);
842
843 if (!iGCLOHThreshold)
844 {
845 iGCLOHThreshold = Configuration::GetKnobDWORDValue(W("System.GC.LOHThreshold"), CLRConfig::EXTERNAL_GCLOHThreshold);
846 iGCLOHThreshold = max (iGCLOHThreshold, LARGE_OBJECT_SIZE);
847 }
848
849 if (!iGCLOHCompactionMode) iGCLOHCompactionMode = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCLOHCompact, iGCLOHCompactionMode);
850
851#ifdef GCTRIMCOMMIT
852 if (g_IGCTrimCommit)
853 iGCTrimCommit = g_IGCTrimCommit;
854 else
855 iGCTrimCommit = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_gcTrimCommitOnLowMemory, iGCTrimCommit);
856#endif
857
858#ifdef FEATURE_CONSERVATIVE_GC
859 iGCConservative = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_gcConservative) != 0);
860#endif // FEATURE_CONSERVATIVE_GC
861
862#ifdef _WIN64
863 iGCAllowVeryLargeObjects = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_gcAllowVeryLargeObjects) != 0);
864#endif
865
866 fGCBreakOnOOM = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCBreakOnOOM, fGCBreakOnOOM) != 0);
867
868#ifdef TRACE_GC
869 iGCtraceStart = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCtraceStart, iGCtraceStart);
870 iGCtraceEnd = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCtraceEnd, iGCtraceEnd);
871 iGCtraceFac = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GCtraceFacility, iGCtraceFac);
872 iGCprnLvl = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_GCprnLvl, iGCprnLvl);
873#endif
874
875#ifdef _DEBUG
876 iInjectFatalError = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_InjectFatalError, iInjectFatalError);
877
878 fSaveThreadInfo = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SaveThreadInfo, fSaveThreadInfo) != 0);
879
880 dwSaveThreadInfoMask = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SaveThreadInfoMask, dwSaveThreadInfoMask);
881
882 {
883 LPWSTR wszSkipGCCoverageList = NULL;
884 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SkipGCCoverage, &wszSkipGCCoverageList));
885
886 EX_TRY
887 {
888 if (wszSkipGCCoverageList)
889 pSkipGCCoverageList = new AssemblyNamesList(wszSkipGCCoverageList);
890 }
891 EX_CATCH_HRESULT(hr);
892 IfFailRet(hr);
893 }
894#endif
895
896 iGCForceCompact = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_gcForceCompact, iGCForceCompact);
897 iGCNoAffinitize = Configuration::GetKnobBooleanValue(W("System.GC.NoAffinitize"),
898 CLRConfig::EXTERNAL_GCNoAffinitize);
899 iGCHeapCount = Configuration::GetKnobDWORDValue(W("System.GC.HeapCount"), CLRConfig::EXTERNAL_GCHeapCount);
900
901 fStressLog = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_StressLog, fStressLog) != 0;
902 fForceEnc = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_ForceEnc, fForceEnc) != 0;
903
904 iRequireZaps = RequireZapsType(GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_ZapRequire, iRequireZaps));
905 if (IsCompilationProcess() || iRequireZaps >= REQUIRE_ZAPS_COUNT)
906 iRequireZaps = REQUIRE_ZAPS_NONE;
907
908 if (iRequireZaps != REQUIRE_ZAPS_NONE)
909 {
910 {
911 NewArrayHolder<WCHAR> wszZapRequireList;
912 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapRequireList, &wszZapRequireList));
913 if (wszZapRequireList)
914 pRequireZapsList = new AssemblyNamesList(wszZapRequireList);
915 }
916
917 {
918 NewArrayHolder<WCHAR> wszZapRequireExcludeList;
919 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapRequireExcludeList, &wszZapRequireExcludeList));
920 if (wszZapRequireExcludeList)
921 pRequireZapsExcludeList = new AssemblyNamesList(wszZapRequireExcludeList);
922 }
923 }
924
925 pReadyToRunExcludeList = NULL;
926#if defined(FEATURE_READYTORUN)
927 if (ReadyToRunInfo::IsReadyToRunEnabled())
928 {
929 NewArrayHolder<WCHAR> wszReadyToRunExcludeList;
930 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ReadyToRunExcludeList, &wszReadyToRunExcludeList));
931 if (wszReadyToRunExcludeList)
932 pReadyToRunExcludeList = new AssemblyNamesList(wszReadyToRunExcludeList);
933 }
934#endif // defined(FEATURE_READYTORUN)
935
936#ifdef _DEBUG
937 iForbidZaps = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenBind_ZapForbid) != 0;
938 if (iForbidZaps != 0)
939 {
940 {
941 NewArrayHolder<WCHAR> wszZapForbidList;
942 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenBind_ZapForbidList, &wszZapForbidList));
943 if (wszZapForbidList)
944 pForbidZapsList = new AssemblyNamesList(wszZapForbidList);
945 }
946
947 {
948 NewArrayHolder<WCHAR> wszZapForbidExcludeList;
949 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenBind_ZapForbidExcludeList, &wszZapForbidExcludeList));
950 if (wszZapForbidExcludeList)
951 pForbidZapsExcludeList = new AssemblyNamesList(wszZapForbidExcludeList);
952 }
953 }
954#endif
955
956#ifdef FEATURE_DOUBLE_ALIGNMENT_HINT
957 DoubleArrayToLargeObjectHeapThreshold = GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_DoubleArrayToLargeObjectHeap, DoubleArrayToLargeObjectHeapThreshold);
958#endif
959
960#ifdef FEATURE_PREJIT
961 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ZapBBInstr, (LPWSTR*)&szZapBBInstr));
962 if (szZapBBInstr)
963 {
964 szZapBBInstr = NarrowWideChar((LPWSTR)szZapBBInstr);
965
966 // If szZapBBInstr only contains white space, then there's nothing to instrument (this
967 // is the case with some test cases, and it's easier to fix all of them here).
968 LPWSTR pStr = (LPWSTR) szZapBBInstr;
969 while (*pStr == W(' ')) pStr++;
970 if (*pStr == 0)
971 szZapBBInstr = NULL;
972 }
973
974 if (szZapBBInstr != NULL)
975 {
976 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_ZapBBInstrDir, &szZapBBInstrDir));
977 g_IBCLogger.EnableAllInstr();
978 }
979 else
980 g_IBCLogger.DisableAllInstr();
981#endif
982
983
984 dwDisableStackwalkCache = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_DisableStackwalkCache, dwDisableStackwalkCache);
985
986
987#ifdef _DEBUG
988 IfFailRet (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnClassLoad, (LPWSTR*) &pszBreakOnClassLoad));
989 pszBreakOnClassLoad = NarrowWideChar((LPWSTR)pszBreakOnClassLoad);
990#endif
991
992 dwSpinInitialDuration = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinInitialDuration);
993 if (dwSpinInitialDuration < 1)
994 {
995 dwSpinInitialDuration = 1;
996 }
997 dwSpinBackoffFactor = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinBackoffFactor);
998 if (dwSpinBackoffFactor < 2)
999 {
1000 dwSpinBackoffFactor = 2;
1001 }
1002 dwSpinLimitProcCap = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinLimitProcCap);
1003 dwSpinLimitProcFactor = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinLimitProcFactor);
1004 dwSpinLimitConstant = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinLimitConstant);
1005 dwSpinRetryCount = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_SpinRetryCount);
1006 dwMonitorSpinCount = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_Monitor_SpinCount);
1007
1008 fJitFramed = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JitFramed, fJitFramed) != 0);
1009 fJitAlignLoops = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JitAlignLoops, fJitAlignLoops) != 0);
1010 fJitMinOpts = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_JITMinOpts, fJitMinOpts) == 1);
1011 iJitOptimizeType = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_JitOptimizeType, iJitOptimizeType);
1012 if (iJitOptimizeType > OPT_RANDOM) iJitOptimizeType = OPT_DEFAULT;
1013
1014#ifdef FEATURE_REJIT
1015 fAddRejitNops = (GetConfigDWORD_DontUse_(CLRConfig::UNSUPPORTED_AddRejitNops, fAddRejitNops) != 0);
1016#endif
1017
1018#ifdef _TARGET_X86_
1019 fPInvokeRestoreEsp = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Jit_NetFx40PInvokeStackResilience);
1020#endif
1021
1022
1023#ifdef _DEBUG
1024 fDebuggable = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_JitDebuggable, fDebuggable) != 0);
1025 fStressOn = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_StressOn, fStressOn) != 0);
1026 apiThreadStressCount = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_APIThreadStress, apiThreadStressCount);
1027
1028 LPWSTR wszPreStubStuff = NULL;
1029
1030 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PrestubHalt, &wszPreStubStuff));
1031 IfFailRet(ParseMethList(wszPreStubStuff, &pPrestubHalt));
1032
1033 LPWSTR wszInvokeStuff = NULL;
1034 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InvokeHalt, &wszInvokeStuff));
1035 IfFailRet(ParseMethList(wszInvokeStuff, &pInvokeHalt));
1036
1037 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PrestubGC, &wszPreStubStuff));
1038 IfFailRet(ParseMethList(wszPreStubStuff, &pPrestubGC));
1039
1040 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnClassBuild, (LPWSTR*)&pszBreakOnClassBuild));
1041 pszBreakOnClassBuild = NarrowWideChar((LPWSTR)pszBreakOnClassBuild);
1042
1043 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnInstantiation, (LPWSTR*)&pszBreakOnInstantiation));
1044 pszBreakOnInstantiation = NarrowWideChar((LPWSTR)pszBreakOnInstantiation);
1045
1046 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnMethodName, (LPWSTR*)&pszBreakOnMethodName));
1047 pszBreakOnMethodName = NarrowWideChar((LPWSTR)pszBreakOnMethodName);
1048
1049 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DumpOnClassLoad, (LPWSTR*)&pszDumpOnClassLoad));
1050 pszDumpOnClassLoad = NarrowWideChar((LPWSTR)pszDumpOnClassLoad);
1051
1052 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnInteropStubSetup, (LPWSTR*)&pszBreakOnInteropStubSetup));
1053 pszBreakOnInteropStubSetup = NarrowWideChar((LPWSTR)pszBreakOnInteropStubSetup);
1054
1055 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnComToClrNativeInfoInit, (LPWSTR*)&pszBreakOnComToClrNativeInfoInit));
1056 pszBreakOnComToClrNativeInfoInit = NarrowWideChar((LPWSTR)pszBreakOnComToClrNativeInfoInit);
1057
1058 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_BreakOnStructMarshalSetup, (LPWSTR*)&pszBreakOnStructMarshalSetup));
1059 pszBreakOnStructMarshalSetup = NarrowWideChar((LPWSTR)pszBreakOnStructMarshalSetup);
1060
1061 m_fAssertOnBadImageFormat = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnBadImageFormat, m_fAssertOnBadImageFormat) != 0);
1062 m_fAssertOnFailFast = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_AssertOnFailFast, m_fAssertOnFailFast) != 0);
1063
1064 fSuppressChecks = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_SuppressChecks, fSuppressChecks) != 0);
1065 CHECK::SetAssertEnforcement(!fSuppressChecks);
1066
1067 fConditionalContracts = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ConditionalContracts, fConditionalContracts) != 0);
1068
1069#ifdef ENABLE_CONTRACTS_IMPL
1070 Contract::SetUnconditionalContractEnforcement(!fConditionalContracts);
1071#endif
1072
1073 fEnableFullDebug = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_EnableFullDebug, fEnableFullDebug) != 0);
1074
1075 fVerifierOff = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_VerifierOff, fVerifierOff) != 0);
1076
1077 fJitVerificationDisable = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_JitVerificationDisable, fJitVerificationDisable) != 0);
1078
1079 iExposeExceptionsInCOM = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ExposeExceptionsInCOM, iExposeExceptionsInCOM);
1080#endif
1081
1082#ifdef FEATURE_COMINTEROP
1083 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_LogCCWRefCountChange, (LPWSTR*)&pszLogCCWRefCountChange));
1084 pszLogCCWRefCountChange = NarrowWideChar((LPWSTR)pszLogCCWRefCountChange);
1085 if (pszLogCCWRefCountChange != NULL)
1086 bLogCCWRefCountChange = true;
1087
1088 fEnableRCWCleanupOnSTAShutdown = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_EnableRCWCleanupOnSTAShutdown) != 0);
1089#endif // FEATURE_COMINTEROP
1090
1091#ifdef _DEBUG
1092 fExpandAllOnLoad = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_ExpandAllOnLoad, fExpandAllOnLoad) != 0);
1093#endif //_DEBUG
1094
1095
1096#ifdef AD_NO_UNLOAD
1097 fAppDomainUnload = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_AppDomainNoUnload) == 0);
1098#endif
1099 dwADURetryCount=GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_ADURetryCount, dwADURetryCount);
1100 if (dwADURetryCount==(DWORD)-1)
1101 {
1102 _ASSERTE(!"Reserved value");
1103 dwADURetryCount=(DWORD)-2;
1104 }
1105
1106#ifdef ENABLE_STARTUP_DELAY
1107 {
1108 //I want this string in decimal
1109 WCHAR * end;
1110 WCHAR * str;
1111 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_StartupDelayMS, &str));
1112 if( str )
1113 {
1114 errno = 0;
1115 iStartupDelayMS = wcstoul(str, &end, 10);
1116 if (errno == ERANGE || end == str)
1117 iStartupDelayMS = 0;
1118 }
1119 }
1120#endif
1121
1122#ifdef _DEBUG
1123
1124#ifdef TEST_DATA_CONSISTENCY
1125 fTestDataConsistency = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TestDataConsistency) !=0);
1126#endif
1127
1128 m_SuspendThreadDeadlockTimeoutMs = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuspendThreadDeadlockTimeoutMs);
1129 m_SuspendDeadlockTimeout = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuspendDeadlockTimeout);
1130#endif // _DEBUG
1131 fInited = true;
1132
1133#ifdef _DEBUG
1134 m_pTraceIUnknown = (IUnknown*)(DWORD_PTR)(GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_TraceIUnknown, (DWORD)(DWORD_PTR)(m_pTraceIUnknown))); // <TODO> WIN64 - conversion from DWORD to IUnknown* of greater size</TODO>
1135 m_TraceWrapper = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_TraceWrap, m_TraceWrapper);
1136
1137 // can't have both
1138 if (m_pTraceIUnknown != 0)
1139 {
1140 m_TraceWrapper = 0;
1141 }
1142 else
1143 if (m_TraceWrapper != 0)
1144 {
1145 m_pTraceIUnknown = (IUnknown*)-1;
1146 }
1147#endif
1148
1149#ifdef _DEBUG
1150
1151 LPWSTR wszPerfTypes = NULL;
1152 IfFailRet(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerfTypesToLog, &wszPerfTypes));
1153 IfFailRet(ParseTypeList(wszPerfTypes, &pPerfTypesToLog));
1154
1155 iPerfNumAllocsThreshold = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerfNumAllocsThreshold);
1156 iPerfAllocsSizeThreshold = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PerfAllocsSizeThreshold);
1157
1158 fShouldInjectFault = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InjectFault);
1159
1160 testThreadAbort = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_HostTestThreadAbort);
1161
1162#endif //_DEBUG
1163
1164 m_fInteropValidatePinnedObjects = (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_InteropValidatePinnedObjects) != 0);
1165 m_fInteropLogArguments = (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_InteropLogArguments) != 0);
1166
1167#ifdef FEATURE_PREJIT
1168#ifdef _DEBUG
1169 dwNgenForceFailureMask = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenForceFailureMask);
1170 dwNgenForceFailureCount = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenForceFailureCount);
1171 dwNgenForceFailureKind = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_NgenForceFailureKind);
1172#endif
1173#endif // FEATURE_PREJIT
1174
1175 DWORD iGCPollTypeOverride = GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_GCPollType, iGCPollType);
1176
1177#ifndef FEATURE_HIJACK
1178 // Platforms that do not support hijacking MUST support GC polling.
1179 // Reject attempts by the user to configure the GC polling type as
1180 // GCPOLL_TYPE_HIJACK.
1181 _ASSERTE(EEConfig::GCPOLL_TYPE_HIJACK != iGCPollTypeOverride);
1182 if (EEConfig::GCPOLL_TYPE_HIJACK == iGCPollTypeOverride)
1183 iGCPollTypeOverride = EEConfig::GCPOLL_TYPE_DEFAULT;
1184#endif
1185
1186 _ASSERTE(iGCPollTypeOverride < GCPOLL_TYPE_COUNT);
1187 if (iGCPollTypeOverride < GCPOLL_TYPE_COUNT)
1188 iGCPollType = GCPollType(iGCPollTypeOverride);
1189
1190#if defined(_DEBUG) && defined(WIN64EXCEPTIONS)
1191 fSuppressLockViolationsOnReentryFromOS = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_SuppressLockViolationsOnReentryFromOS) != 0);
1192#endif
1193
1194#if defined(_DEBUG) && defined(STUBLINKER_GENERATES_UNWIND_INFO)
1195 fStubLinkerUnwindInfoVerificationOn = (GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_StubLinkerUnwindInfoVerificationOn, fStubLinkerUnwindInfoVerificationOn) != 0);
1196#endif
1197
1198 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_UseMethodDataCache) != 0) {
1199 MethodTable::AllowMethodDataCaching();
1200 }
1201
1202 if (CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_UseParentMethodData) != 0) {
1203 MethodTable::AllowParentMethodDataCopy();
1204 }
1205
1206
1207#if defined(_DEBUG) && defined(_TARGET_AMD64_)
1208 m_cGenerateLongJumpDispatchStubRatio = GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_GenerateLongJumpDispatchStubRatio,
1209 static_cast<DWORD>(m_cGenerateLongJumpDispatchStubRatio));
1210#endif
1211
1212#if defined(_DEBUG)
1213 bDiagnosticSuspend = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_DiagnosticSuspend) != 0);
1214#endif
1215
1216 dwSleepOnExit = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_SleepOnExit);
1217
1218#if defined(FEATURE_TIERED_COMPILATION)
1219 fTieredCompilation = Configuration::GetKnobBooleanValue(W("System.Runtime.TieredCompilation"), CLRConfig::EXTERNAL_TieredCompilation) != 0;
1220
1221 fTieredCompilation_CallCounting = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Test_CallCounting) != 0;
1222 fTieredCompilation_OptimizeTier0 = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Test_OptimizeTier0) != 0;
1223
1224 tieredCompilation_tier1CallCountThreshold =
1225 CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Tier1CallCountThreshold);
1226 if (tieredCompilation_tier1CallCountThreshold < 1)
1227 {
1228 tieredCompilation_tier1CallCountThreshold = 1;
1229 }
1230
1231 tieredCompilation_tier1CallCountingDelayMs =
1232 CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Tier1CallCountingDelayMs);
1233 if (CPUGroupInfo::HadSingleProcessorAtStartup())
1234 {
1235 DWORD delayMultiplier =
1236 CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_TieredCompilation_Tier1DelaySingleProcMultiplier);
1237 if (delayMultiplier > 1)
1238 {
1239 DWORD newDelay = tieredCompilation_tier1CallCountingDelayMs * delayMultiplier;
1240 if (newDelay / delayMultiplier == tieredCompilation_tier1CallCountingDelayMs)
1241 {
1242 tieredCompilation_tier1CallCountingDelayMs = newDelay;
1243 }
1244 }
1245 }
1246#endif
1247
1248#if defined(FEATURE_GDBJIT) && defined(_DEBUG)
1249 {
1250 LPWSTR pszGDBJitElfDumpW = NULL;
1251 CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GDBJitElfDump, &pszGDBJitElfDumpW);
1252 pszGDBJitElfDump = NarrowWideChar(pszGDBJitElfDumpW);
1253 }
1254#endif // FEATURE_GDBJIT && _DEBUG
1255
1256#if defined(FEATURE_GDBJIT_FRAME)
1257 fGDBJitEmitDebugFrame = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_GDBJitEmitDebugFrame) != 0;
1258#endif
1259 return hr;
1260}
1261
1262//
1263// #GetConfigValueCallback
1264// Provides a way for code:CLRConfig to access configuration file values.
1265//
1266// static
1267HRESULT EEConfig::GetConfigValueCallback(__in_z LPCWSTR pKey, __deref_out_opt LPCWSTR* pValue, BOOL systemOnly, BOOL applicationFirst)
1268{
1269 CONTRACT (HRESULT) {
1270 NOTHROW;
1271 GC_NOTRIGGER;
1272 MODE_ANY;
1273 SO_TOLERANT;
1274 PRECONDITION(CheckPointer(pValue));
1275 PRECONDITION(CheckPointer(pKey));
1276 } CONTRACT_END;
1277
1278 // Ensure that both options aren't set.
1279 _ASSERTE(!(systemOnly && applicationFirst));
1280
1281 if(g_pConfig != NULL)
1282 {
1283 ConfigSearch direction = CONFIG_SYSTEM;
1284 if(systemOnly)
1285 {
1286 direction = CONFIG_SYSTEMONLY;
1287 }
1288 else if(applicationFirst)
1289 {
1290 direction = CONFIG_APPLICATION;
1291 }
1292
1293 RETURN g_pConfig->GetConfiguration_DontUse_(pKey, direction, pValue);
1294 }
1295 else
1296 {
1297 RETURN E_FAIL;
1298 }
1299}
1300
1301HRESULT EEConfig::GetConfiguration_DontUse_(__in_z LPCWSTR pKey, ConfigSearch direction, __deref_out_opt LPCWSTR* pValue)
1302{
1303 CONTRACT (HRESULT) {
1304 NOTHROW;
1305 GC_NOTRIGGER;
1306 MODE_ANY;
1307 SO_TOLERANT; // TODO: Verify this does not do anything that would make it so_intolerant
1308 PRECONDITION(CheckPointer(pValue));
1309 PRECONDITION(CheckPointer(pKey));
1310 } CONTRACT_END;
1311
1312 Thread *pThread = GetThread();
1313 ConfigStringKeyValuePair * pair = NULL;
1314
1315 *pValue = NULL;
1316 ConfigList::ConfigIter iter(&m_Configuration);
1317
1318 switch(direction) {
1319 case CONFIG_SYSTEMONLY:
1320 {
1321 // for things that only admin should be able to set
1322 ConfigStringHashtable* table = iter.Next();
1323 if(table != NULL)
1324 {
1325 BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, RETURN E_FAIL;)
1326 pair = table->Lookup(pKey);
1327 END_SO_INTOLERANT_CODE
1328 if(pair != NULL)
1329 {
1330 *pValue = pair->value;
1331 RETURN S_OK;
1332 }
1333 }
1334 RETURN E_FAIL;
1335 }
1336 case CONFIG_SYSTEM:
1337 {
1338 for(ConfigStringHashtable* table = iter.Next();
1339 table != NULL;
1340 table = iter.Next())
1341 {
1342 BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, RETURN E_FAIL;)
1343 pair = table->Lookup(pKey);
1344 END_SO_INTOLERANT_CODE
1345 if(pair != NULL)
1346 {
1347 *pValue = pair->value;
1348 RETURN S_OK;
1349 }
1350 }
1351 RETURN E_FAIL;
1352 }
1353 case CONFIG_APPLICATION: {
1354 for(ConfigStringHashtable* table = iter.Previous();
1355 table != NULL;
1356 table = iter.Previous())
1357 {
1358 BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, RETURN E_FAIL;)
1359 pair = table->Lookup(pKey);
1360 END_SO_INTOLERANT_CODE
1361 if(pair != NULL)
1362 {
1363 *pValue = pair->value;
1364 RETURN S_OK;
1365 }
1366 }
1367 RETURN E_FAIL;
1368 }
1369 default:
1370 RETURN E_FAIL;
1371 }
1372}
1373
1374bool EEConfig::RequireZap(LPCUTF8 assemblyName) const
1375{
1376 LIMITED_METHOD_CONTRACT;
1377 if (iRequireZaps == REQUIRE_ZAPS_NONE)
1378 return false;
1379
1380 if (pRequireZapsExcludeList != NULL && pRequireZapsExcludeList->IsInList(assemblyName))
1381 return false;
1382
1383 if (pRequireZapsList == NULL || pRequireZapsList->IsInList(assemblyName))
1384 return true;
1385
1386 return false;
1387}
1388
1389#ifdef _DEBUG
1390bool EEConfig::ForbidZap(LPCUTF8 assemblyName) const
1391{
1392 LIMITED_METHOD_CONTRACT;
1393 if (iForbidZaps == 0)
1394 return false;
1395
1396 if (pForbidZapsExcludeList != NULL && pForbidZapsExcludeList->IsInList(assemblyName))
1397 return false;
1398
1399 if (pForbidZapsList == NULL || pForbidZapsList->IsInList(assemblyName))
1400 return true;
1401
1402 return false;
1403}
1404#endif
1405
1406bool EEConfig::ExcludeReadyToRun(LPCUTF8 assemblyName) const
1407{
1408 LIMITED_METHOD_CONTRACT;
1409
1410 if (pReadyToRunExcludeList != NULL && pReadyToRunExcludeList->IsInList(assemblyName))
1411 return true;
1412
1413 return false;
1414}
1415
1416/**************************************************************/
1417#ifdef _DEBUG
1418/**************************************************************/
1419
1420// Ownership of the string buffer passes to ParseMethList
1421
1422/* static */
1423HRESULT EEConfig::ParseMethList(__in_z LPWSTR str, MethodNamesList** out) {
1424 CONTRACTL {
1425 NOTHROW;
1426 GC_NOTRIGGER;
1427 MODE_ANY;
1428 INJECT_FAULT(return E_OUTOFMEMORY);
1429 PRECONDITION(CheckPointer(str, NULL_OK));
1430 PRECONDITION(CheckPointer(out));
1431 } CONTRACTL_END;
1432
1433 HRESULT hr = S_OK;
1434
1435 *out = NULL;
1436
1437 // we are now done with the string passed in
1438 if (str == NULL)
1439 {
1440 return S_OK;
1441 }
1442
1443 EX_TRY
1444 {
1445 *out = new MethodNamesList(str);
1446 } EX_CATCH_HRESULT(hr);
1447
1448 delete [] str;
1449
1450 return hr;
1451}
1452
1453/**************************************************************/
1454/* static */
1455void EEConfig::DestroyMethList(MethodNamesList* list) {
1456 CONTRACTL {
1457 NOTHROW;
1458 GC_NOTRIGGER;
1459 MODE_ANY;
1460 PRECONDITION(CheckPointer(list));
1461 } CONTRACTL_END;
1462
1463 if (list == 0)
1464 return;
1465 delete list;
1466}
1467
1468/**************************************************************/
1469/* static */
1470bool EEConfig::IsInMethList(MethodNamesList* list, MethodDesc* pMD)
1471{
1472 CONTRACTL {
1473 THROWS;
1474 GC_TRIGGERS;
1475 MODE_ANY;
1476 PRECONDITION(CheckPointer(list, NULL_OK));
1477 PRECONDITION(CheckPointer(pMD));
1478 } CONTRACTL_END;
1479
1480 if (list == 0)
1481 return(false);
1482 else
1483 {
1484 DefineFullyQualifiedNameForClass();
1485
1486 LPCUTF8 name = pMD->GetName();
1487 if (name == NULL)
1488 {
1489 return false;
1490 }
1491 LPCUTF8 className = GetFullyQualifiedNameForClass(pMD->GetMethodTable());
1492 if (className == NULL)
1493 {
1494 return false;
1495 }
1496 PCCOR_SIGNATURE sig = pMD->GetSig();
1497
1498 return list->IsInList(name, className, sig);
1499 }
1500}
1501
1502// Ownership of the string buffer passes to ParseTypeList
1503/* static */
1504HRESULT EEConfig::ParseTypeList(__in_z LPWSTR str, TypeNamesList** out)
1505{
1506 CONTRACTL {
1507 NOTHROW;
1508 GC_NOTRIGGER;
1509 MODE_ANY;
1510 PRECONDITION(CheckPointer(out));
1511 PRECONDITION(CheckPointer(str, NULL_OK));
1512 INJECT_FAULT(return E_OUTOFMEMORY);
1513 } CONTRACTL_END;
1514
1515 HRESULT hr = S_OK;
1516
1517 *out = NULL;
1518
1519 if (str == NULL)
1520 return S_OK;
1521
1522 NewHolder<TypeNamesList> newTypeNameList(new (nothrow) TypeNamesList());
1523 if (newTypeNameList != NULL)
1524 IfFailRet(newTypeNameList->Init(str));
1525
1526 delete [] str;
1527
1528 newTypeNameList.SuppressRelease();
1529 *out = newTypeNameList;
1530
1531 return (*out != NULL)?S_OK:E_OUTOFMEMORY;
1532}
1533
1534void EEConfig::DestroyTypeList(TypeNamesList* list) {
1535
1536 CONTRACTL {
1537 NOTHROW;
1538 GC_NOTRIGGER;
1539 MODE_ANY;
1540 PRECONDITION(CheckPointer(list));
1541 } CONTRACTL_END;
1542
1543 if (list == 0)
1544 return;
1545 delete list;
1546}
1547
1548TypeNamesList::TypeNamesList()
1549{
1550 LIMITED_METHOD_CONTRACT;
1551}
1552
1553bool EEConfig::RegexOrExactMatch(LPCUTF8 regex, LPCUTF8 input)
1554{
1555 CONTRACTL
1556 {
1557 NOTHROW;
1558 GC_NOTRIGGER;
1559 MODE_ANY;
1560 }
1561 CONTRACTL_END;
1562
1563 if (regex == NULL || input == NULL)
1564 return false;
1565
1566 if (*regex == '/')
1567 {
1568 // Debug only, so we can live with it.
1569 CONTRACT_VIOLATION(ThrowsViolation);
1570
1571 regex::STRRegEx::GroupingContainer groups;
1572 if (regex::STRRegEx::Match("^/(.*)/(i?)$", regex, groups))
1573 {
1574 regex::STRRegEx::MatchFlags flags = regex::STRRegEx::DefaultMatchFlags;
1575 if (groups[2].Length() != 0)
1576 flags = (regex::STRRegEx::MatchFlags)(flags | regex::STRRegEx::MF_CASE_INSENSITIVE);
1577
1578 return regex::STRRegEx::Matches(groups[1].Begin(), groups[1].End(),
1579 input, input + strlen(input), flags);
1580 }
1581 }
1582 return strcmp(regex, input) == 0;
1583}
1584
1585HRESULT TypeNamesList::Init(__in_z LPCWSTR str)
1586{
1587 CONTRACTL {
1588 NOTHROW;
1589 GC_NOTRIGGER;
1590 MODE_ANY;
1591 PRECONDITION(CheckPointer(str));
1592 INJECT_FAULT(return E_OUTOFMEMORY);
1593 } CONTRACTL_END;
1594
1595 pNames = NULL;
1596
1597 LPCWSTR currentType = str;
1598 int length = 0;
1599 bool typeFound = false;
1600
1601 for (; *str != '\0'; str++)
1602 {
1603 switch(*str)
1604 {
1605 case ' ':
1606 {
1607 if (!typeFound)
1608 break;
1609
1610 NewHolder<TypeName> tn(new (nothrow) TypeName());
1611 if (tn == NULL)
1612 return E_OUTOFMEMORY;
1613
1614 tn->typeName = new (nothrow) char[length + 1];
1615 if (tn->typeName == NULL)
1616 return E_OUTOFMEMORY;
1617
1618 tn.SuppressRelease();
1619 MAKE_UTF8PTR_FROMWIDE_NOTHROW(temp, currentType);
1620 if (temp == NULL)
1621 return E_OUTOFMEMORY;
1622
1623 memcpy(tn->typeName, temp, length * sizeof(char));
1624 tn->typeName[length] = '\0';
1625
1626 tn->next = pNames;
1627 pNames = tn;
1628
1629 typeFound = false;
1630 length = 0;
1631
1632 break;
1633 }
1634
1635 default:
1636 if (!typeFound)
1637 currentType = str;
1638
1639 typeFound = true;
1640 length++;
1641 break;
1642 }
1643 }
1644
1645 if (typeFound)
1646 {
1647 NewHolder<TypeName> tn(new (nothrow) TypeName());
1648 if (tn == NULL)
1649 return E_OUTOFMEMORY;
1650
1651 tn->typeName = new (nothrow) char[length + 1];
1652
1653 if (tn->typeName == NULL)
1654 return E_OUTOFMEMORY;
1655
1656 tn.SuppressRelease();
1657 MAKE_UTF8PTR_FROMWIDE_NOTHROW(temp, currentType);
1658 if (temp == NULL)
1659 return E_OUTOFMEMORY;
1660
1661 memcpy(tn->typeName, temp, length * sizeof(char));
1662 tn->typeName[length] = '\0';
1663
1664 tn->next = pNames;
1665 pNames = tn;
1666 }
1667 return S_OK;
1668}
1669
1670TypeNamesList::~TypeNamesList()
1671{
1672 CONTRACTL {
1673 NOTHROW;
1674 FORBID_FAULT;
1675 GC_NOTRIGGER;
1676 MODE_ANY;
1677 } CONTRACTL_END;
1678
1679
1680 while (pNames)
1681 {
1682 delete [] pNames->typeName;
1683
1684 TypeName *tmp = pNames;
1685 pNames = pNames->next;
1686
1687 delete tmp;
1688 }
1689}
1690
1691bool TypeNamesList::IsInList(LPCUTF8 typeName)
1692{
1693 CONTRACTL {
1694 NOTHROW;
1695 GC_NOTRIGGER;
1696 MODE_ANY;
1697 CANNOT_TAKE_LOCK;
1698 PRECONDITION(CheckPointer(typeName));
1699 } CONTRACTL_END;
1700
1701 TypeName *tnTemp = pNames;
1702 while (tnTemp)
1703 {
1704 if (strstr(typeName, tnTemp->typeName) != typeName)
1705 tnTemp = tnTemp->next;
1706 else
1707 return true;
1708 }
1709
1710 return false;
1711}
1712#endif // _DEBUG
1713
1714#ifdef FEATURE_COMINTEROP
1715void EEConfig::SetLogCCWRefCountChangeEnabled(bool newVal)
1716{
1717 LIMITED_METHOD_CONTRACT;
1718
1719 // logically we want pszLogCCWRefCountChange != NULL to force bLogCCWRefCountChange to be true
1720 bLogCCWRefCountChange = (newVal || pszLogCCWRefCountChange != NULL);
1721}
1722
1723bool EEConfig::ShouldLogCCWRefCountChange(LPCUTF8 pszClassName, LPCUTF8 pszNamespace) const
1724{
1725 CONTRACTL {
1726 NOTHROW;
1727 GC_NOTRIGGER;
1728 } CONTRACTL_END
1729
1730 if (pszLogCCWRefCountChange == NULL)
1731 return false;
1732
1733 // check simple class name
1734 if (strcmp(pszLogCCWRefCountChange, "*") == 0 ||
1735 strcmp(pszLogCCWRefCountChange, pszClassName) == 0)
1736 return true;
1737
1738 // check namespace DOT class name
1739 LPCUTF8 dot = strrchr(pszLogCCWRefCountChange, '.');
1740 if (dot != NULL)
1741 {
1742 if (strncmp(pszLogCCWRefCountChange, pszNamespace, dot - pszLogCCWRefCountChange) == 0 &&
1743 strcmp(dot + 1, pszClassName) == 0)
1744 return true;
1745 }
1746 return false;
1747}
1748#endif // FEATURE_COMINTEROP
1749