[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / utilcode / util.cpp
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 //*****************************************************************************
5 //  util.cpp
6 //
7
8 //
9 //  This contains a bunch of C++ utility classes.
10 //
11 //*****************************************************************************
12 #include "stdafx.h"                     // Precompiled header key.
13 #include "utilcode.h"
14 #include "metadata.h"
15 #include "ex.h"
16 #include "pedecoder.h"
17 #include "loaderheap.h"
18 #include "sigparser.h"
19 #include "cor.h"
20 #include "corinfo.h"
21 #include "volatile.h"
22
23 #ifndef DACCESS_COMPILE
24 UINT32 g_nClrInstanceId = 0;
25 #endif //!DACCESS_COMPILE
26
27 //********** Code. ************************************************************
28
29 #if defined(FEATURE_COMINTEROP) && !defined(FEATURE_CORESYSTEM)
30 extern WinRTStatusEnum gWinRTStatus = WINRT_STATUS_UNINITED;
31 #endif // FEATURE_COMINTEROP && !FEATURE_CORESYSTEM
32
33 #if defined(FEATURE_COMINTEROP) && !defined(FEATURE_CORESYSTEM)
34 //------------------------------------------------------------------------------
35 //
36 // Attempt to detect the presense of Windows Runtime support on the current OS.
37 // Our algorithm to do this is to ensure that:
38 //      1. combase.dll exists
39 //      2. combase.dll contains a RoInitialize export
40 //
41
42 void InitWinRTStatus()
43 {
44     STATIC_CONTRACT_NOTHROW;
45     STATIC_CONTRACT_GC_NOTRIGGER;
46     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
47
48     WinRTStatusEnum winRTStatus = WINRT_STATUS_UNSUPPORTED;
49
50     const WCHAR wszComBaseDll[] = W("\\combase.dll");
51     const SIZE_T cchComBaseDll = _countof(wszComBaseDll);
52
53     WCHAR wszComBasePath[MAX_LONGPATH + 1];
54     const SIZE_T cchComBasePath = _countof(wszComBasePath);
55
56     ZeroMemory(wszComBasePath, cchComBasePath * sizeof(wszComBasePath[0]));
57
58     UINT cchSystemDirectory = WszGetSystemDirectory(wszComBasePath, MAX_LONGPATH);
59
60     // Make sure that we're only probing in the system directory.  If we can't find the system directory, or
61     // we find it but combase.dll doesn't fit into it, we'll fall back to a safe default of saying that WinRT
62     // is simply not present.
63     if (cchSystemDirectory > 0 && cchComBasePath - cchSystemDirectory >= cchComBaseDll)
64     {
65         if (wcscat_s(wszComBasePath, wszComBaseDll) == 0)
66         {
67             HModuleHolder hComBase(WszLoadLibrary(wszComBasePath));
68             if (hComBase != NULL)
69             {
70                 FARPROC activateInstace = GetProcAddress(hComBase, "RoInitialize");
71                 if (activateInstace != NULL)
72                 {
73                     winRTStatus = WINRT_STATUS_SUPPORTED;
74                 }
75             }
76         }
77     }
78
79     gWinRTStatus = winRTStatus;
80 }
81 #endif // FEATURE_COMINTEROP && !FEATURE_CORESYSTEM
82 //*****************************************************************************
83 // Convert a string of hex digits into a hex value of the specified # of bytes.
84 //*****************************************************************************
85 HRESULT GetHex(                         // Return status.
86     LPCSTR      szStr,                  // String to convert.
87     int         size,                   // # of bytes in pResult.
88     void        *pResult)               // Buffer for result.
89 {
90     CONTRACTL
91     {
92         NOTHROW;
93     }
94     CONTRACTL_END;
95     
96     int         count = size * 2;       // # of bytes to take from string.
97     unsigned int Result = 0;           // Result value.
98     char          ch;
99
100     _ASSERTE(size == 1 || size == 2 || size == 4);
101
102     while (count-- && (ch = *szStr++) != '\0')
103     {
104         switch (ch)
105         {
106             case '0': case '1': case '2': case '3': case '4': 
107             case '5': case '6': case '7': case '8': case '9': 
108             Result = 16 * Result + (ch - '0');
109             break;
110
111             case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
112             Result = 16 * Result + 10 + (ch - 'A');
113             break;
114
115             case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
116             Result = 16 * Result + 10 + (ch - 'a');
117             break;
118
119             default:
120             return (E_FAIL);
121         }
122     }
123
124     // Set the output.
125     switch (size)
126     {
127         case 1:
128         *((BYTE *) pResult) = (BYTE) Result;
129         break;
130
131         case 2:
132         *((WORD *) pResult) = (WORD) Result;
133         break;
134
135         case 4:
136         *((DWORD *) pResult) = Result;
137         break;
138
139         default:
140         _ASSERTE(0);
141         break;
142     }
143     return (S_OK);
144 }
145
146 //*****************************************************************************
147 // Convert a pointer to a string into a GUID.
148 //*****************************************************************************
149 HRESULT LPCSTRToGuid(                   // Return status.
150     LPCSTR      szGuid,                 // String to convert.
151     GUID        *psGuid)                // Buffer for converted GUID.
152 {
153     CONTRACTL
154     {
155         NOTHROW;
156     }
157     CONTRACTL_END;
158     
159     int i;
160
161     // Verify the surrounding syntax.
162     if (strlen(szGuid) != 38 || szGuid[0] != '{' || szGuid[9] != '-' ||
163         szGuid[14] != '-' || szGuid[19] != '-' || szGuid[24] != '-' || szGuid[37] != '}')
164     {
165         return (E_FAIL);
166     }
167
168     // Parse the first 3 fields.
169     if (FAILED(GetHex(szGuid + 1, 4, &psGuid->Data1)))
170         return E_FAIL;
171     if (FAILED(GetHex(szGuid + 10, 2, &psGuid->Data2)))
172         return E_FAIL;
173     if (FAILED(GetHex(szGuid + 15, 2, &psGuid->Data3)))
174         return E_FAIL;
175
176     // Get the last two fields (which are byte arrays).
177     for (i = 0; i < 2; ++i)
178     {
179         if (FAILED(GetHex(szGuid + 20 + (i * 2), 1, &psGuid->Data4[i])))
180         {
181             return E_FAIL;
182         }
183     }
184     for (i=0; i < 6; ++i)
185     {
186         if (FAILED(GetHex(szGuid + 25 + (i * 2), 1, &psGuid->Data4[i+2])))
187         {
188             return E_FAIL;
189         }
190     }
191     return S_OK;
192 }
193
194 //
195 //
196 // Global utility functions.
197 //
198 //
199
200
201
202 typedef HRESULT __stdcall DLLGETCLASSOBJECT(REFCLSID rclsid,
203                                             REFIID   riid,
204                                             void   **ppv);
205
206 EXTERN_C const IID _IID_IClassFactory = 
207     {0x00000001, 0x0000, 0x0000, {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}};
208
209 namespace
210 {
211     HRESULT FakeCoCallDllGetClassObject(
212         REFCLSID rclsid,
213         LPCWSTR wszDllPath,
214         REFIID riid,
215         void **ppv,
216         HMODULE *phmodDll)
217     {
218         CONTRACTL
219         {
220             THROWS;
221         }
222         CONTRACTL_END;
223
224         _ASSERTE(ppv != nullptr);
225
226         HRESULT hr = S_OK;
227
228         // Initialize [out] HMODULE (if it was requested)
229         if (phmodDll != nullptr)
230             *phmodDll = nullptr;
231
232         bool fIsDllPathPrefix = (wszDllPath != nullptr) && (wcslen(wszDllPath) > 0) && (wszDllPath[wcslen(wszDllPath) - 1] == W('\\'));
233
234         // - An empty string will be treated as NULL.
235         // - A string ending will a backslash will be treated as a prefix for where to look for the DLL
236         //   if the InProcServer32 value is just a DLL name and not a full path.
237         StackSString ssDllName;
238         if ((wszDllPath == nullptr) || (wszDllPath[0] == W('\0')) || fIsDllPathPrefix)
239         {
240 #ifndef FEATURE_PAL
241             IfFailRet(Clr::Util::Com::FindInprocServer32UsingCLSID(rclsid, ssDllName));
242
243             EX_TRY
244             {
245                 if (fIsDllPathPrefix)
246                 {
247                     SString::Iterator i = ssDllName.Begin();
248                     if (!ssDllName.Find(i, W('\\')))
249                     {   // If the InprocServer32 is just a DLL name (not a fully qualified path), then
250                         // prefix wszFilePath with wszDllPath.
251                         ssDllName.Insert(i, wszDllPath);
252                     }
253                 }
254             }
255             EX_CATCH_HRESULT(hr);
256             IfFailRet(hr);
257
258             wszDllPath = ssDllName.GetUnicode();
259 #else // !FEATURE_PAL
260             return E_FAIL;
261 #endif // !FEATURE_PAL
262         }
263         _ASSERTE(wszDllPath != nullptr);
264
265         // We've got the name of the DLL to load, so load it.
266         HModuleHolder hDll = WszLoadLibraryEx(wszDllPath, nullptr, GetLoadWithAlteredSearchPathFlag());
267         if (hDll == nullptr)
268             return HRESULT_FROM_GetLastError();
269
270         // We've loaded the DLL, so find the DllGetClassObject function.
271         DLLGETCLASSOBJECT *dllGetClassObject = (DLLGETCLASSOBJECT*)GetProcAddress(hDll, "DllGetClassObject");
272         if (dllGetClassObject == nullptr)
273             return HRESULT_FROM_GetLastError();
274
275         // Call the function to get a class object for the rclsid and riid passed in.
276         IfFailRet(dllGetClassObject(rclsid, riid, ppv));
277
278         hDll.SuppressRelease();
279
280         if (phmodDll != nullptr)
281             *phmodDll = hDll.GetValue();
282
283         return hr;
284     }
285 }
286
287 // ----------------------------------------------------------------------------
288 // FakeCoCreateInstanceEx
289 // 
290 // Description:
291 //     A private function to do the equivalent of a CoCreateInstance in cases where we
292 //     can't make the real call. Use this when, for instance, you need to create a symbol
293 //     reader in the Runtime but we're not CoInitialized. Obviously, this is only good
294 //     for COM objects for which CoCreateInstance is just a glorified find-and-load-me
295 //     operation.
296 //     
297 // Arguments:
298 //    * rclsid - [in] CLSID of object to instantiate
299 //    * wszDllPath [in] - Path to profiler DLL.  If wszDllPath is NULL, FakeCoCreateInstanceEx 
300 //        will look up the registry to find the path of the COM dll associated with rclsid.
301 //        If the path ends in a backslash, FakeCoCreateInstanceEx will treat this as a prefix
302 //        if the InprocServer32 found in the registry is a simple filename (not a full path).
303 //        This allows the caller to specify the directory in which the InprocServer32 should
304 //        be found.
305 //    * riid - [in] IID of interface on object to return in ppv
306 //    * ppv - [out] Pointer to implementation of requested interface
307 //    * phmodDll - [out] HMODULE of DLL that was loaded to instantiate the COM object.
308 //        The caller may eventually call FreeLibrary() on this if it can be determined
309 //        that we no longer reference the generated COM object or dependencies. Else, the
310 //        caller may ignore this and the DLL will stay loaded forever. If caller
311 //        specifies phmodDll==NULL, then this parameter is ignored and the HMODULE is not
312 //        returned.
313 //        
314 // Return Value:
315 //    HRESULT indicating success or failure.
316 //    
317 // Notes:
318 //    * (*phmodDll) on [out] may always be trusted, even if this function returns an
319 //        error. Therefore, even if creation of the COM object failed, if (*phmodDll !=
320 //        NULL), then the DLL was actually loaded. The caller may wish to call
321 //        FreeLibrary on (*phmodDll) in such a case.
322 HRESULT FakeCoCreateInstanceEx(REFCLSID       rclsid,
323                                LPCWSTR        wszDllPath,
324                                REFIID         riid,
325                                void **        ppv,
326                                HMODULE *      phmodDll)
327 {
328     CONTRACTL
329     {
330         THROWS;
331     }
332     CONTRACTL_END;
333
334     HRESULT hr = S_OK;
335
336     // Call the function to get a class factory for the rclsid passed in.
337     HModuleHolder hDll;
338     ReleaseHolder<IClassFactory> classFactory;
339     IfFailRet(FakeCoCallDllGetClassObject(rclsid, wszDllPath, _IID_IClassFactory, (void**)&classFactory, &hDll));
340
341     // Ask the class factory to create an instance of the
342     // necessary object.
343     IfFailRet(classFactory->CreateInstance(NULL, riid, ppv));
344
345     hDll.SuppressRelease();
346
347     if (phmodDll != NULL)
348     {
349         *phmodDll = hDll.GetValue();
350     }
351
352     return hr;
353 }
354
355 #if USE_UPPER_ADDRESS
356 static BYTE * s_CodeMinAddr;        // Preferred region to allocate the code in.
357 static BYTE * s_CodeMaxAddr;
358 static BYTE * s_CodeAllocStart;
359 static BYTE * s_CodeAllocHint;      // Next address to try to allocate for code in the preferred region.
360 #endif
361
362 //
363 // Use this function to initialize the s_CodeAllocHint
364 // during startup. base is runtime .dll base address,
365 // size is runtime .dll virtual size.
366 //
367 void InitCodeAllocHint(SIZE_T base, SIZE_T size, int randomPageOffset)
368 {
369 #if USE_UPPER_ADDRESS
370
371 #ifdef _DEBUG
372     // If GetForceRelocs is enabled we don't constrain the pMinAddr
373     if (PEDecoder::GetForceRelocs())
374         return;
375 #endif
376     
377 //
378     // If we are using the UPPER_ADDRESS space (on Win64)
379     // then for any code heap that doesn't specify an address
380     // range using [pMinAddr..pMaxAddr] we place it in the
381     // upper address space
382     // This enables us to avoid having to use long JumpStubs
383     // to reach the code for our ngen-ed images.
384     // Which are also placed in the UPPER_ADDRESS space.
385     //
386     SIZE_T reach = 0x7FFF0000u;
387     
388     // We will choose the preferred code region based on the address of clr.dll. The JIT helpers
389     // in clr.dll are the most heavily called functions.
390     s_CodeMinAddr = (base + size > reach) ? (BYTE *)(base + size - reach) : (BYTE *)0;
391     s_CodeMaxAddr = (base + reach > base) ? (BYTE *)(base + reach) : (BYTE *)-1;
392
393     BYTE * pStart;
394
395     if (s_CodeMinAddr <= (BYTE *)CODEHEAP_START_ADDRESS && 
396         (BYTE *)CODEHEAP_START_ADDRESS < s_CodeMaxAddr)
397     {
398         // clr.dll got loaded at its preferred base address? (OS without ASLR - pre-Vista)
399         // Use the code head start address that does not cause collisions with NGen images.
400         // This logic is coupled with scripts that we use to assign base addresses.
401         pStart = (BYTE *)CODEHEAP_START_ADDRESS;
402     }
403     else
404     if (base > UINT32_MAX)
405     {
406         // clr.dll got address assigned by ASLR?
407         // Try to occupy the space as far as possible to minimize collisions with other ASLR assigned
408         // addresses. Do not start at s_CodeMinAddr exactly so that we can also reach common native images 
409         // that can be placed at higher addresses than clr.dll.
410         pStart = s_CodeMinAddr + (s_CodeMaxAddr - s_CodeMinAddr) / 8;
411     }
412     else
413     {
414         // clr.dll missed the base address?
415         // Try to occupy the space right after it.
416         pStart = (BYTE *)(base + size);
417     }
418
419     // Randomize the adddress space
420     pStart += GetOsPageSize() * randomPageOffset;
421
422     s_CodeAllocStart = pStart;
423     s_CodeAllocHint = pStart;
424 #endif
425 }
426
427 //
428 // Use this function to reset the s_CodeAllocHint
429 // after unloading an AppDomain
430 //
431 void ResetCodeAllocHint()
432 {
433     LIMITED_METHOD_CONTRACT;
434 #if USE_UPPER_ADDRESS
435     s_CodeAllocHint = s_CodeAllocStart;
436 #endif
437 }
438
439 //
440 // Returns TRUE if p is located in near clr.dll that allows us
441 // to use rel32 IP-relative addressing modes.
442 //
443 BOOL IsPreferredExecutableRange(void * p)
444 {
445     LIMITED_METHOD_CONTRACT;
446 #if USE_UPPER_ADDRESS
447     if (s_CodeMinAddr <= (BYTE *)p && (BYTE *)p < s_CodeMaxAddr)
448         return TRUE;
449 #endif
450     return FALSE;
451 }
452
453 //
454 // Allocate free memory that will be used for executable code
455 // Handles the special requirements that we have on 64-bit platforms
456 // where we want the executable memory to be located near clr.dll
457 //
458 BYTE * ClrVirtualAllocExecutable(SIZE_T dwSize, 
459                                  DWORD flAllocationType,
460                                  DWORD flProtect)
461 {
462     CONTRACTL
463     {
464         NOTHROW;
465     }
466     CONTRACTL_END;
467
468 #if USE_UPPER_ADDRESS
469     //
470     // If we are using the UPPER_ADDRESS space (on Win64)
471     // then for any heap that will contain executable code
472     // we will place it in the upper address space
473     //
474     // This enables us to avoid having to use JumpStubs
475     // to reach the code for our ngen-ed images on x64,
476     // since they are also placed in the UPPER_ADDRESS space.
477     //
478     BYTE * pHint = s_CodeAllocHint;
479  
480     if (dwSize <= (SIZE_T)(s_CodeMaxAddr - s_CodeMinAddr) && pHint != NULL)
481     {
482         // Try to allocate in the preferred region after the hint
483         BYTE * pResult = ClrVirtualAllocWithinRange(pHint, s_CodeMaxAddr, dwSize, flAllocationType, flProtect);
484
485         if (pResult != NULL)
486         {
487             s_CodeAllocHint = pResult + dwSize;
488             return pResult;
489         }
490
491         // Try to allocate in the preferred region before the hint
492         pResult = ClrVirtualAllocWithinRange(s_CodeMinAddr, pHint + dwSize, dwSize, flAllocationType, flProtect);
493
494         if (pResult != NULL)
495         {
496             s_CodeAllocHint = pResult + dwSize;
497             return pResult;
498         }
499
500         s_CodeAllocHint = NULL;
501     }
502
503     // Fall through to 
504 #endif // USE_UPPER_ADDRESS
505
506 #ifdef FEATURE_PAL
507     // Tell PAL to use the executable memory allocator to satisfy this request for virtual memory.
508     // This will allow us to place JIT'ed code close to the coreclr library
509     // and thus improve performance by avoiding jump stubs in managed code.
510     flAllocationType |= MEM_RESERVE_EXECUTABLE;
511 #endif // FEATURE_PAL
512
513     return (BYTE *) ClrVirtualAlloc (NULL, dwSize, flAllocationType, flProtect);
514
515 }
516
517 //
518 // Allocate free memory with specific alignment.                         
519 //
520 LPVOID ClrVirtualAllocAligned(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect, SIZE_T alignment)
521 {
522     // Verify that the alignment is a power of 2
523     _ASSERTE(alignment != 0);
524     _ASSERTE((alignment & (alignment - 1)) == 0);
525
526 #ifndef FEATURE_PAL
527
528     // The VirtualAlloc on Windows ensures 64kB alignment
529     _ASSERTE(alignment <= 0x10000);
530     return ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
531
532 #else // !FEATURE_PAL
533
534     if(alignment < GetOsPageSize()) alignment = GetOsPageSize();
535
536     // UNIXTODO: Add a specialized function to PAL so that we don't have to waste memory
537     dwSize += alignment;
538     SIZE_T addr = (SIZE_T)ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
539     return (LPVOID)((addr + (alignment - 1)) & ~(alignment - 1));
540
541 #endif // !FEATURE_PAL
542 }
543
544 #ifdef _DEBUG
545 static DWORD ShouldInjectFaultInRange()
546 {
547     static DWORD fInjectFaultInRange = 99;
548
549     if (fInjectFaultInRange == 99)
550         fInjectFaultInRange = (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_InjectFault) & 0x40);
551     return fInjectFaultInRange;
552 }
553 #endif
554
555 // Reserves free memory within the range [pMinAddr..pMaxAddr] using
556 // ClrVirtualQuery to find free memory and ClrVirtualAlloc to reserve it.
557 //
558 // This method only supports the flAllocationType of MEM_RESERVE, and expects that the memory
559 // is being reserved for the purpose of eventually storing executable code.
560 //
561 // Callers also should set dwSize to a multiple of sysInfo.dwAllocationGranularity (64k).
562 // That way they can reserve a large region and commit smaller sized pages
563 // from that region until it fills up.  
564 //
565 // This functions returns the reserved memory block upon success
566 //
567 // It returns NULL when it fails to find any memory that satisfies
568 // the range.
569 //
570
571 BYTE * ClrVirtualAllocWithinRange(const BYTE *pMinAddr,
572                                   const BYTE *pMaxAddr,
573                                   SIZE_T dwSize, 
574                                   DWORD flAllocationType,
575                                   DWORD flProtect)
576 {
577     CONTRACTL
578     {
579         NOTHROW;
580         PRECONDITION(dwSize != 0);
581         PRECONDITION(flAllocationType == MEM_RESERVE);
582     }
583     CONTRACTL_END;
584
585     BYTE *pResult = nullptr;  // our return value;
586
587     static unsigned countOfCalls = 0;  // We log the number of tims we call this method
588     countOfCalls++;                    // increment the call counter
589
590     if (dwSize == 0)
591     {
592         return nullptr;
593     }
594
595     //
596     // First lets normalize the pMinAddr and pMaxAddr values
597     //
598     // If pMinAddr is NULL then set it to BOT_MEMORY
599     if ((pMinAddr == 0) || (pMinAddr < (BYTE *) BOT_MEMORY))
600     {
601         pMinAddr = (BYTE *) BOT_MEMORY;
602     }
603
604     // If pMaxAddr is NULL then set it to TOP_MEMORY
605     if ((pMaxAddr == 0) || (pMaxAddr > (BYTE *) TOP_MEMORY))
606     {
607         pMaxAddr = (BYTE *) TOP_MEMORY;
608     }
609
610     // If pMaxAddr is not greater than pMinAddr we can not make an allocation
611     if (pMaxAddr <= pMinAddr)
612     {
613         return nullptr;
614     }
615
616     // If pMinAddr is BOT_MEMORY and pMaxAddr is TOP_MEMORY
617     // then we can call ClrVirtualAlloc instead 
618     if ((pMinAddr == (BYTE *) BOT_MEMORY) && (pMaxAddr == (BYTE *) TOP_MEMORY))
619     {
620         return (BYTE*) ClrVirtualAlloc(nullptr, dwSize, flAllocationType, flProtect);
621     }
622
623 #ifdef FEATURE_PAL
624     pResult = (BYTE *)PAL_VirtualReserveFromExecutableMemoryAllocatorWithinRange(pMinAddr, pMaxAddr, dwSize);
625     if (pResult != nullptr)
626     {
627         return pResult;
628     }
629 #endif // FEATURE_PAL
630
631     // We will do one scan from [pMinAddr .. pMaxAddr]
632     // First align the tryAddr up to next 64k base address. 
633     // See docs for VirtualAllocEx and lpAddress and 64k alignment for reasons.
634     //
635     BYTE *   tryAddr            = (BYTE *)ALIGN_UP((BYTE *)pMinAddr, VIRTUAL_ALLOC_RESERVE_GRANULARITY);
636     bool     virtualQueryFailed = false;
637     bool     faultInjected      = false;
638     unsigned virtualQueryCount  = 0;
639
640     // Now scan memory and try to find a free block of the size requested.
641     while ((tryAddr + dwSize) <= (BYTE *) pMaxAddr)
642     {
643         MEMORY_BASIC_INFORMATION mbInfo;
644             
645         // Use VirtualQuery to find out if this address is MEM_FREE
646         //
647         virtualQueryCount++;
648         if (!ClrVirtualQuery((LPCVOID)tryAddr, &mbInfo, sizeof(mbInfo)))
649         {
650             // Exit and return nullptr if the VirtualQuery call fails.
651             virtualQueryFailed = true;
652             break;
653         }
654             
655         // Is there enough memory free from this start location?
656         // Note that for most versions of UNIX the mbInfo.RegionSize returned will always be 0
657         if ((mbInfo.State == MEM_FREE) && 
658             (mbInfo.RegionSize >= (SIZE_T) dwSize || mbInfo.RegionSize == 0)) 
659         {
660             // Try reserving the memory using VirtualAlloc now
661             pResult = (BYTE*)ClrVirtualAlloc(tryAddr, dwSize, MEM_RESERVE, flProtect);
662
663             // Normally this will be successful
664             //
665             if (pResult != nullptr)
666             {
667                 // return pResult
668                 break;
669             }
670
671 #ifdef _DEBUG
672             if (ShouldInjectFaultInRange())
673             {
674                 // return nullptr (failure)
675                 faultInjected = true;
676                 break;
677             }
678 #endif // _DEBUG
679
680             // On UNIX we can also fail if our request size 'dwSize' is larger than 64K and
681             // and our tryAddr is pointing at a small MEM_FREE region (smaller than 'dwSize')
682             // However we can't distinguish between this and the race case.
683
684             // We might fail in a race.  So just move on to next region and continue trying
685             tryAddr = tryAddr + VIRTUAL_ALLOC_RESERVE_GRANULARITY;
686         }
687         else
688         {
689             // Try another section of memory
690             tryAddr = max(tryAddr + VIRTUAL_ALLOC_RESERVE_GRANULARITY,
691                           (BYTE*) mbInfo.BaseAddress + mbInfo.RegionSize);
692         }
693     }
694
695     STRESS_LOG7(LF_JIT, LL_INFO100,
696                 "ClrVirtualAllocWithinRange request #%u for %08x bytes in [ %p .. %p ], query count was %u - returned %s: %p\n",
697                 countOfCalls, (DWORD)dwSize, pMinAddr, pMaxAddr,
698                 virtualQueryCount, (pResult != nullptr) ? "success" : "failure", pResult);
699
700     // If we failed this call the process will typically be terminated
701     // so we log any additional reason for failing this call.
702     //
703     if (pResult == nullptr)
704     {
705         if ((tryAddr + dwSize) > (BYTE *)pMaxAddr)
706         {
707             // Our tryAddr reached pMaxAddr
708             STRESS_LOG0(LF_JIT, LL_INFO100, "Additional reason: Address space exhausted.\n");
709         }
710
711         if (virtualQueryFailed)
712         {
713             STRESS_LOG0(LF_JIT, LL_INFO100, "Additional reason: VirtualQuery operation failed.\n");
714         }
715
716         if (faultInjected)
717         {
718             STRESS_LOG0(LF_JIT, LL_INFO100, "Additional reason: fault injected.\n");
719         }
720     }
721
722     return pResult;
723 }
724
725 //******************************************************************************
726 // NumaNodeInfo 
727 //******************************************************************************
728 #if !defined(FEATURE_REDHAWK)
729
730 /*static*/ LPVOID NumaNodeInfo::VirtualAllocExNuma(HANDLE hProc, LPVOID lpAddr, SIZE_T dwSize,
731                          DWORD allocType, DWORD prot, DWORD node)
732 {
733     return ::VirtualAllocExNuma(hProc, lpAddr, dwSize, allocType, prot, node);
734 }
735
736 #ifndef FEATURE_PAL
737 /*static*/ BOOL NumaNodeInfo::GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no)
738 {
739     return ::GetNumaProcessorNodeEx(proc_no, node_no);
740 }
741 /*static*/ bool NumaNodeInfo::GetNumaInfo(PUSHORT total_nodes, DWORD* max_procs_per_node)
742 {
743     if (m_enableGCNumaAware)
744     {
745         DWORD currentProcsOnNode = 0;
746         for (int i = 0; i < m_nNodes; i++)
747         {
748             GROUP_AFFINITY processorMask;
749             if (GetNumaNodeProcessorMaskEx(i, &processorMask))
750             {
751                 DWORD procsOnNode = 0;
752                 uintptr_t mask = (uintptr_t)processorMask.Mask;
753                 while (mask)
754                 {
755                     procsOnNode++;
756                     mask &= mask - 1;
757                 }
758
759                 currentProcsOnNode = max(currentProcsOnNode, procsOnNode);
760             }
761         }
762
763         *max_procs_per_node = currentProcsOnNode;
764         *total_nodes = m_nNodes;
765         return true;
766     }
767
768     return false;
769 }
770 #else // !FEATURE_PAL
771 /*static*/ BOOL NumaNodeInfo::GetNumaProcessorNodeEx(USHORT proc_no, PUSHORT node_no)
772 {
773     return PAL_GetNumaProcessorNode(proc_no, node_no);
774 }
775 #endif // !FEATURE_PAL
776 #endif
777
778 /*static*/ BOOL NumaNodeInfo::m_enableGCNumaAware = FALSE;
779 /*static*/ uint16_t NumaNodeInfo::m_nNodes = 0;
780 /*static*/ BOOL NumaNodeInfo::InitNumaNodeInfoAPI()
781 {
782 #if !defined(FEATURE_REDHAWK)
783     //check for numa support if multiple heaps are used
784     ULONG highest = 0;
785     
786     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCNumaAware) == 0)
787         return FALSE;
788
789     // fail to get the highest numa node number
790     if (!::GetNumaHighestNodeNumber(&highest) || (highest == 0))
791         return FALSE;
792
793     m_nNodes = (USHORT)(highest + 1);
794
795     return TRUE;
796 #else
797     return FALSE;
798 #endif
799 }
800
801 /*static*/ BOOL NumaNodeInfo::CanEnableGCNumaAware()
802 {
803     return m_enableGCNumaAware;
804 }
805
806 /*static*/ void NumaNodeInfo::InitNumaNodeInfo()
807 {
808     m_enableGCNumaAware = InitNumaNodeInfoAPI();
809 }
810
811 #ifndef FEATURE_PAL
812
813 //******************************************************************************
814 // CPUGroupInfo 
815 //******************************************************************************
816 #if !defined(FEATURE_REDHAWK)
817 /*static*/ //CPUGroupInfo::PNTQSIEx CPUGroupInfo::m_pNtQuerySystemInformationEx = NULL;
818
819 /*static*/ BOOL CPUGroupInfo::GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP relationship,
820                          SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *slpiex, PDWORD count)
821 {
822     LIMITED_METHOD_CONTRACT;
823     return ::GetLogicalProcessorInformationEx(relationship, slpiex, count);
824 }
825
826 /*static*/ BOOL CPUGroupInfo::SetThreadGroupAffinity(HANDLE h, 
827                         GROUP_AFFINITY *groupAffinity, GROUP_AFFINITY *previousGroupAffinity)
828 {
829     LIMITED_METHOD_CONTRACT;
830     return ::SetThreadGroupAffinity(h, groupAffinity, previousGroupAffinity);
831 }
832
833 /*static*/ BOOL CPUGroupInfo::GetThreadGroupAffinity(HANDLE h, GROUP_AFFINITY *groupAffinity)
834 {
835     LIMITED_METHOD_CONTRACT;
836     return ::GetThreadGroupAffinity(h, groupAffinity);
837 }
838
839 /*static*/ BOOL CPUGroupInfo::GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime)
840 {
841     LIMITED_METHOD_CONTRACT;
842
843 #ifndef FEATURE_PAL    
844     return ::GetSystemTimes(idleTime, kernelTime, userTime);
845 #else
846     return FALSE;
847 #endif
848 }
849 #endif
850
851 /*static*/ BOOL CPUGroupInfo::m_enableGCCPUGroups = FALSE;
852 /*static*/ BOOL CPUGroupInfo::m_threadUseAllCpuGroups = FALSE;
853 /*static*/ WORD CPUGroupInfo::m_nGroups = 0;
854 /*static*/ WORD CPUGroupInfo::m_nProcessors = 0;
855 /*static*/ WORD CPUGroupInfo::m_initialGroup = 0;
856 /*static*/ CPU_Group_Info *CPUGroupInfo::m_CPUGroupInfoArray = NULL;
857 /*static*/ LONG CPUGroupInfo::m_initialization = 0;
858 /*static*/ bool CPUGroupInfo::s_hadSingleProcessorAtStartup = false;
859
860 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
861 // Calculate greatest common divisor
862 DWORD GCD(DWORD u, DWORD v)
863 {
864     while (v != 0)
865     {
866         DWORD dwTemp = v;
867         v = u % v;
868         u = dwTemp;
869     }
870
871     return u;
872 }
873
874 // Calculate least common multiple
875 DWORD LCM(DWORD u, DWORD v)
876 {
877     return u / GCD(u, v) * v;
878 }
879 #endif
880
881 /*static*/ BOOL CPUGroupInfo::InitCPUGroupInfoArray()
882 {
883     CONTRACTL
884     {
885         NOTHROW;
886         GC_NOTRIGGER;
887     }
888     CONTRACTL_END;
889
890 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
891     BYTE *bBuffer = NULL;
892     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pSLPIEx = NULL;
893     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pRecord = NULL;
894     DWORD cbSLPIEx = 0;
895     DWORD byteOffset = 0;
896     DWORD dwNumElements = 0;
897     DWORD dwWeight = 1;
898
899     if (CPUGroupInfo::GetLogicalProcessorInformationEx(RelationGroup, pSLPIEx, &cbSLPIEx) &&
900                       GetLastError() != ERROR_INSUFFICIENT_BUFFER)
901         return FALSE;
902
903     _ASSERTE(cbSLPIEx);
904
905     // Fail to allocate buffer
906     bBuffer = new (nothrow) BYTE[ cbSLPIEx ];
907     if (bBuffer == NULL)
908         return FALSE;
909
910     pSLPIEx = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)bBuffer;
911     if (!::GetLogicalProcessorInformationEx(RelationGroup, pSLPIEx, &cbSLPIEx))
912     {
913         delete[] bBuffer;
914         return FALSE;
915     }
916
917     pRecord = pSLPIEx;
918     while (byteOffset < cbSLPIEx)
919     {
920         if (pRecord->Relationship == RelationGroup)
921         {
922             m_nGroups = pRecord->Group.ActiveGroupCount;
923             break;
924         }
925         byteOffset += pRecord->Size;
926         pRecord = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(bBuffer + byteOffset);
927     }
928
929     m_CPUGroupInfoArray = new (nothrow) CPU_Group_Info[m_nGroups];
930     if (m_CPUGroupInfoArray == NULL) 
931     {
932         delete[] bBuffer;
933         return FALSE;
934     }
935
936     for (DWORD i = 0; i < m_nGroups; i++)
937     {
938         m_CPUGroupInfoArray[i].nr_active   = (WORD)pRecord->Group.GroupInfo[i].ActiveProcessorCount;
939         m_CPUGroupInfoArray[i].active_mask = pRecord->Group.GroupInfo[i].ActiveProcessorMask;
940         m_nProcessors += m_CPUGroupInfoArray[i].nr_active;
941         dwWeight = LCM(dwWeight, (DWORD)m_CPUGroupInfoArray[i].nr_active);
942     }
943
944     // The number of threads per group that can be supported will depend on the number of CPU groups
945     // and the number of LPs within each processor group. For example, when the number of LPs in
946     // CPU groups is the same and is 64, the number of threads per group before weight overflow
947     // would be 2^32/2^6 = 2^26 (64M threads)
948     for (DWORD i = 0; i < m_nGroups; i++)
949     {
950         m_CPUGroupInfoArray[i].groupWeight = dwWeight / (DWORD)m_CPUGroupInfoArray[i].nr_active;
951         m_CPUGroupInfoArray[i].activeThreadWeight = 0;
952     }
953
954     delete[] bBuffer;  // done with it; free it
955     return TRUE;
956 #else
957     return FALSE;
958 #endif
959 }
960
961 /*static*/ BOOL CPUGroupInfo::InitCPUGroupInfoRange()
962 {
963     LIMITED_METHOD_CONTRACT;
964
965 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
966     WORD begin   = 0;
967     WORD nr_proc = 0;
968
969     for (WORD i = 0; i < m_nGroups; i++) 
970     {
971         nr_proc += m_CPUGroupInfoArray[i].nr_active;
972         m_CPUGroupInfoArray[i].begin = begin;
973         m_CPUGroupInfoArray[i].end   = nr_proc - 1;
974         begin = nr_proc;
975     }
976     return TRUE;
977 #else
978     return FALSE;
979 #endif
980 }
981
982 /*static*/ void CPUGroupInfo::InitCPUGroupInfo()
983 {
984     CONTRACTL
985     {
986         NOTHROW;
987         GC_NOTRIGGER;
988     }
989     CONTRACTL_END;
990
991 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
992     BOOL enableGCCPUGroups     = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCCpuGroup) != 0;
993     BOOL threadUseAllCpuGroups = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Thread_UseAllCpuGroups) != 0;
994
995     if (!enableGCCPUGroups)
996         return;
997
998     if (!InitCPUGroupInfoArray())
999         return;
1000
1001     if (!InitCPUGroupInfoRange())
1002         return;
1003
1004     // initalGroup is whatever the CPU group that the main thread is running on
1005     GROUP_AFFINITY groupAffinity;
1006     CPUGroupInfo::GetThreadGroupAffinity(GetCurrentThread(), &groupAffinity);
1007     m_initialGroup = groupAffinity.Group;  
1008
1009         // only enable CPU groups if more than one group exists
1010         BOOL hasMultipleGroups = m_nGroups > 1;
1011         m_enableGCCPUGroups = enableGCCPUGroups && hasMultipleGroups;
1012         m_threadUseAllCpuGroups = threadUseAllCpuGroups && hasMultipleGroups;
1013 #endif // _TARGET_AMD64_ || _TARGET_ARM64_
1014
1015     // Determine if the process is affinitized to a single processor (or if the system has a single processor)
1016     DWORD_PTR processAffinityMask, systemAffinityMask;
1017     if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask))
1018     {
1019         processAffinityMask &= systemAffinityMask;
1020         if (processAffinityMask != 0 && // only one CPU group is involved
1021             (processAffinityMask & (processAffinityMask - 1)) == 0) // only one bit is set
1022         {
1023             s_hadSingleProcessorAtStartup = true;
1024         }
1025     }
1026 }
1027
1028 /*static*/ BOOL CPUGroupInfo::IsInitialized()
1029 {
1030     LIMITED_METHOD_CONTRACT;
1031     return (m_initialization == -1);
1032 }
1033
1034 /*static*/ void CPUGroupInfo::EnsureInitialized()
1035 {
1036     CONTRACTL
1037     {
1038         NOTHROW;
1039         GC_NOTRIGGER;
1040     }
1041     CONTRACTL_END;
1042
1043     // CPUGroupInfo needs to be initialized only once. This could happen in three cases 
1044     // 1. CLR initialization at begining of EEStartup, or
1045     // 2. Sometimes, when hosted by ASP.NET, the hosting process may initialize ThreadPool
1046     //    before initializing CLR, thus require CPUGroupInfo to be initialized to determine
1047     //    if CPU group support should/could be enabled.
1048     // 3. Call into Threadpool functions before Threadpool _and_ CLR is initialized.
1049     // Vast majority of time, CPUGroupInfo is initialized in case 1. or 2. 
1050     // The chance of contention will be extremely small, so the following code should be fine
1051     //
1052 retry:
1053     if (IsInitialized())
1054         return;
1055
1056     if (InterlockedCompareExchange(&m_initialization, 1, 0) == 0)
1057     {
1058         InitCPUGroupInfo();
1059         m_initialization = -1;
1060     }
1061     else //some other thread started initialization, just wait until complete;
1062     {
1063         while (m_initialization != -1)
1064         {
1065             SwitchToThread();
1066         }
1067         goto retry;
1068     }
1069 }
1070
1071 /*static*/ WORD CPUGroupInfo::GetNumActiveProcessors()
1072 {
1073     LIMITED_METHOD_CONTRACT;
1074     return (WORD)m_nProcessors;
1075 }
1076
1077 /*static*/ void CPUGroupInfo::GetGroupForProcessor(WORD processor_number,
1078                                          WORD* group_number, WORD* group_processor_number)
1079 {
1080     LIMITED_METHOD_CONTRACT;
1081
1082 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1083     WORD bTemp = 0;
1084     WORD bDiff = processor_number - bTemp;
1085
1086     for (WORD i=0; i < m_nGroups; i++)
1087     {
1088         bTemp += m_CPUGroupInfoArray[i].nr_active;
1089         if (bTemp > processor_number)
1090         {
1091             *group_number = i;
1092             *group_processor_number = bDiff;
1093
1094             break;
1095         }
1096         bDiff = processor_number - bTemp;
1097     }
1098 #else
1099     *group_number = 0;
1100     *group_processor_number = 0;
1101 #endif
1102 }
1103
1104 /*static*/ DWORD CPUGroupInfo::CalculateCurrentProcessorNumber()
1105 {
1106     CONTRACTL
1107     {
1108         NOTHROW;
1109         GC_NOTRIGGER;
1110     }
1111     CONTRACTL_END;
1112
1113 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1114     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1115     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1116
1117     PROCESSOR_NUMBER proc_no;
1118     proc_no.Group=0;
1119     proc_no.Number=0;
1120     proc_no.Reserved=0;
1121     ::GetCurrentProcessorNumberEx(&proc_no);
1122
1123     DWORD fullNumber = 0;
1124     for (WORD i = 0; i < proc_no.Group; i++)
1125         fullNumber += (DWORD)m_CPUGroupInfoArray[i].nr_active;
1126     fullNumber += (DWORD)(proc_no.Number);
1127
1128     return fullNumber;
1129 #else
1130     return 0;
1131 #endif
1132 }
1133
1134 // There can be different numbers of procs in groups. We take the max.
1135 /*static*/ bool CPUGroupInfo::GetCPUGroupInfo(PUSHORT total_groups, DWORD* max_procs_per_group)
1136 {
1137     if (m_enableGCCPUGroups)
1138     {
1139         *total_groups = m_nGroups;
1140         DWORD currentProcsInGroup = 0;
1141         for (WORD i = 0; i < m_nGroups; i++)
1142         {
1143             currentProcsInGroup = max(currentProcsInGroup, m_CPUGroupInfoArray[i].nr_active);
1144         }
1145         *max_procs_per_group = currentProcsInGroup;
1146         return true;
1147     }
1148
1149     return false;
1150 }
1151
1152 #if !defined(FEATURE_REDHAWK)
1153 //Lock ThreadStore before calling this function, so that updates of weights/counts are consistent
1154 /*static*/ void CPUGroupInfo::ChooseCPUGroupAffinity(GROUP_AFFINITY *gf)
1155 {
1156     CONTRACTL
1157     {
1158         NOTHROW;
1159         GC_NOTRIGGER;
1160     }
1161     CONTRACTL_END;
1162
1163 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1164     WORD i, minGroup = 0;
1165     DWORD minWeight = 0;
1166
1167     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1168     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1169
1170     for (i = 0; i < m_nGroups; i++) 
1171     {
1172         minGroup = (m_initialGroup + i) % m_nGroups;    
1173
1174         // the group is not filled up, use it
1175         if (m_CPUGroupInfoArray[minGroup].activeThreadWeight / m_CPUGroupInfoArray[minGroup].groupWeight
1176                           < (DWORD)m_CPUGroupInfoArray[minGroup].nr_active)
1177             goto found;
1178     }
1179
1180     // all groups filled up, distribute proportionally
1181     minGroup = m_initialGroup;
1182     minWeight = m_CPUGroupInfoArray[m_initialGroup].activeThreadWeight; 
1183     for (i = 0; i < m_nGroups; i++) 
1184     {
1185         if (m_CPUGroupInfoArray[i].activeThreadWeight < minWeight)
1186         {
1187             minGroup = i;
1188             minWeight = m_CPUGroupInfoArray[i].activeThreadWeight;
1189         }
1190     }
1191
1192 found:
1193     gf->Group = minGroup;
1194     gf->Mask = m_CPUGroupInfoArray[minGroup].active_mask;
1195     gf->Reserved[0] = 0;
1196     gf->Reserved[1] = 0;
1197     gf->Reserved[2] = 0;
1198     m_CPUGroupInfoArray[minGroup].activeThreadWeight += m_CPUGroupInfoArray[minGroup].groupWeight;
1199 #endif
1200 }
1201
1202 //Lock ThreadStore before calling this function, so that updates of weights/counts are consistent
1203 /*static*/ void CPUGroupInfo::ClearCPUGroupAffinity(GROUP_AFFINITY *gf)
1204 {
1205     LIMITED_METHOD_CONTRACT;
1206 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1207     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1208     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1209
1210     WORD group = gf->Group;
1211     m_CPUGroupInfoArray[group].activeThreadWeight -= m_CPUGroupInfoArray[group].groupWeight;
1212 #endif
1213 }
1214
1215 BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* group_size)
1216 {
1217     if (group_number >= m_nGroups)
1218     {
1219         return FALSE;
1220     }
1221
1222     *group_begin = m_CPUGroupInfoArray[group_number].begin;
1223     *group_size = m_CPUGroupInfoArray[group_number].nr_active;
1224
1225     return TRUE;
1226 }
1227
1228 #endif
1229
1230 /*static*/ BOOL CPUGroupInfo::CanEnableGCCPUGroups()
1231 {
1232     LIMITED_METHOD_CONTRACT;
1233     return m_enableGCCPUGroups;
1234 }
1235
1236 /*static*/ BOOL CPUGroupInfo::CanEnableThreadUseAllCpuGroups()
1237 {
1238     LIMITED_METHOD_CONTRACT;
1239     return m_threadUseAllCpuGroups;
1240 }
1241 #endif // !FEATURE_PAL
1242
1243 //******************************************************************************
1244 // Returns the number of processors that a process has been configured to run on
1245 //******************************************************************************
1246 int GetCurrentProcessCpuCount()
1247 {
1248     CONTRACTL
1249     {
1250         NOTHROW;
1251         CANNOT_TAKE_LOCK;
1252     }
1253     CONTRACTL_END;
1254     
1255     static int cCPUs = 0;
1256
1257     if (cCPUs != 0)
1258         return cCPUs;
1259
1260     unsigned int count = 0;
1261
1262 #ifndef FEATURE_PAL
1263     DWORD_PTR pmask, smask;
1264
1265     if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
1266     {
1267         count = 1;
1268     }
1269     else
1270     {
1271         pmask &= smask;
1272
1273         while (pmask)
1274         {
1275             pmask &= (pmask - 1);
1276             count++;
1277         }
1278
1279         // GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
1280         // than 64 processors, which would leave us with a count of 0.  Since the GC
1281         // expects there to be at least one processor to run on (and thus at least one
1282         // heap), we'll return 64 here if count is 0, since there are likely a ton of
1283         // processors available in that case.  The GC also cannot (currently) handle
1284         // the case where there are more than 64 processors, so we will return a
1285         // maximum of 64 here.
1286         if (count == 0 || count > 64)
1287             count = 64;
1288     }
1289
1290 #else // !FEATURE_PAL
1291     count = PAL_GetLogicalCpuCountFromOS();
1292
1293     uint32_t cpuLimit;  
1294     if (PAL_GetCpuLimit(&cpuLimit) && cpuLimit < count) 
1295         count = cpuLimit;       
1296 #endif // !FEATURE_PAL
1297
1298     cCPUs = count;
1299
1300     return count;
1301 }
1302
1303 #ifndef FEATURE_PAL
1304 DWORD_PTR GetCurrentProcessCpuMask()
1305 {
1306     CONTRACTL
1307     {
1308         NOTHROW;
1309         CANNOT_TAKE_LOCK;
1310     }
1311     CONTRACTL_END;
1312
1313 #ifndef FEATURE_PAL
1314     DWORD_PTR pmask, smask;
1315
1316     if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
1317         return 1;
1318
1319     pmask &= smask;
1320     return pmask;
1321 #else
1322     return 0;
1323 #endif
1324 }
1325 #endif // !FEATURE_PAL
1326
1327 uint32_t GetOsPageSizeUncached()
1328 {
1329     SYSTEM_INFO sysInfo;
1330     ::GetSystemInfo(&sysInfo);
1331     return sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x1000;
1332 }
1333
1334 namespace
1335 {
1336     Volatile<uint32_t> g_pageSize = 0;
1337 }
1338
1339 uint32_t GetOsPageSize()
1340 {
1341 #ifdef FEATURE_PAL
1342     size_t result = g_pageSize.LoadWithoutBarrier();
1343
1344     if(!result)
1345     {
1346         result = GetOsPageSizeUncached();
1347
1348         g_pageSize.StoreWithoutBarrier(result);
1349     }
1350
1351     return result;
1352 #else
1353     return 0x1000;
1354 #endif
1355 }
1356
1357 /**************************************************************************/
1358
1359 /**************************************************************************/
1360 void ConfigMethodSet::init(const CLRConfig::ConfigStringInfo & info)
1361 {
1362     CONTRACTL
1363     {
1364         THROWS;
1365     }
1366     CONTRACTL_END;
1367     
1368     // make sure that the memory was zero initialized
1369     _ASSERTE(m_inited == 0 || m_inited == 1);
1370
1371     LPWSTR str = CLRConfig::GetConfigValue(info);
1372     if (str) 
1373     {
1374         m_list.Insert(str);
1375         delete[] str;
1376     }
1377     m_inited = 1;
1378 }
1379
1380 /**************************************************************************/
1381 bool ConfigMethodSet::contains(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig)
1382 {
1383     CONTRACTL
1384     {
1385         NOTHROW;
1386     }
1387     CONTRACTL_END;
1388
1389     _ASSERTE(m_inited == 1);
1390
1391     if (m_list.IsEmpty())
1392         return false;
1393     return(m_list.IsInList(methodName, className, sig));
1394 }
1395
1396 /**************************************************************************/
1397 bool ConfigMethodSet::contains(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo)
1398 {
1399     CONTRACTL
1400     {
1401         NOTHROW;
1402     }
1403     CONTRACTL_END;
1404
1405     _ASSERTE(m_inited == 1);
1406
1407     if (m_list.IsEmpty())
1408         return false;
1409     return(m_list.IsInList(methodName, className, pSigInfo));
1410 }
1411
1412 /**************************************************************************/
1413 void ConfigDWORD::init_DontUse_(__in_z LPCWSTR keyName, DWORD defaultVal)
1414 {
1415     CONTRACTL
1416     {
1417         NOTHROW;
1418     }
1419     CONTRACTL_END;
1420     
1421     // make sure that the memory was zero initialized
1422     _ASSERTE(m_inited == 0 || m_inited == 1);
1423
1424     m_value = REGUTIL::GetConfigDWORD_DontUse_(keyName, defaultVal);
1425     m_inited = 1;
1426 }
1427
1428 /**************************************************************************/
1429 void ConfigString::init(const CLRConfig::ConfigStringInfo & info)
1430 {
1431     CONTRACTL
1432     {
1433         NOTHROW;
1434     }
1435     CONTRACTL_END;
1436     
1437     // make sure that the memory was zero initialized
1438     _ASSERTE(m_inited == 0 || m_inited == 1);
1439
1440     // Note: m_value will be leaking
1441     m_value = CLRConfig::GetConfigValue(info);
1442     m_inited = 1;
1443 }
1444
1445 //=============================================================================
1446 // AssemblyNamesList
1447 //=============================================================================
1448 // The string should be of the form
1449 // MyAssembly
1450 // MyAssembly;mscorlib;System
1451 // MyAssembly;mscorlib System
1452
1453 AssemblyNamesList::AssemblyNamesList(__in LPWSTR list)
1454 {
1455     CONTRACTL {
1456         THROWS;
1457     } CONTRACTL_END;
1458
1459     WCHAR prevChar = '?'; // dummy
1460     LPWSTR nameStart = NULL; // start of the name currently being processed. NULL if no current name
1461     AssemblyName ** ppPrevLink = &m_pNames;
1462     
1463     for (LPWSTR listWalk = list; prevChar != '\0'; prevChar = *listWalk, listWalk++)
1464     {
1465         WCHAR curChar = *listWalk;
1466         
1467         if (iswspace(curChar) || curChar == ';' || curChar == '\0' )
1468         {
1469             //
1470             // Found white-space
1471             //
1472             
1473             if (nameStart)
1474             {
1475                 // Found the end of the current name
1476                 
1477                 AssemblyName * newName = new AssemblyName();
1478                 size_t nameLen = listWalk - nameStart;
1479                 
1480                 MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1481                 newName->m_assemblyName = new char[nameLen + 1];
1482                 memcpy(newName->m_assemblyName, temp, nameLen * sizeof(newName->m_assemblyName[0]));
1483                 newName->m_assemblyName[nameLen] = '\0';
1484
1485                 *ppPrevLink = newName;
1486                 ppPrevLink = &newName->m_next;
1487
1488                 nameStart = NULL;
1489             }
1490         }
1491         else if (!nameStart)
1492         {
1493             //
1494             // Found the start of a new name
1495             //
1496             
1497             nameStart = listWalk;
1498         }
1499     }
1500
1501     _ASSERTE(!nameStart); // cannot be in the middle of a name
1502     *ppPrevLink = NULL;
1503 }
1504
1505 AssemblyNamesList::~AssemblyNamesList()
1506 {
1507     CONTRACTL
1508     {
1509         NOTHROW;
1510     }
1511     CONTRACTL_END;
1512
1513     for (AssemblyName * pName = m_pNames; pName; /**/)
1514     {
1515         AssemblyName * cur = pName;
1516         pName = pName->m_next;
1517
1518         delete [] cur->m_assemblyName;
1519         delete cur;
1520     }
1521 }
1522
1523 bool AssemblyNamesList::IsInList(LPCUTF8 assemblyName)
1524 {
1525     if (IsEmpty())
1526         return false;
1527     
1528     for (AssemblyName * pName = m_pNames; pName; pName = pName->m_next)
1529     {
1530         if (_stricmp(pName->m_assemblyName, assemblyName) == 0)
1531             return true;
1532     }
1533
1534     return false;
1535 }
1536
1537 //=============================================================================
1538 // MethodNamesList
1539 //=============================================================================
1540 //  str should be of the form :
1541 // "foo1 MyNamespace.MyClass:foo3 *:foo4 foo5(x,y,z)"
1542 // "MyClass:foo2 MyClass:*" will match under _DEBUG
1543 //
1544
1545 void MethodNamesListBase::Insert(__in_z LPWSTR str)
1546 {
1547     CONTRACTL {
1548         THROWS;
1549     } CONTRACTL_END;
1550
1551     enum State { NO_NAME, CLS_NAME, FUNC_NAME, ARG_LIST }; // parsing state machine
1552
1553     const char   SEP_CHAR = ' ';     // current character use to separate each entry
1554 //  const char   SEP_CHAR = ';';     // better  character use to separate each entry
1555
1556     WCHAR lastChar = '?'; // dummy
1557     LPWSTR nameStart = NULL; // while walking over the classname or methodname, this points to start
1558     MethodName nameBuf; // Buffer used while parsing the current entry
1559     MethodName** lastName = &pNames; // last entry inserted into the list
1560     bool         bQuote   = false;
1561
1562     nameBuf.methodName = NULL;
1563     nameBuf.className = NULL;
1564     nameBuf.numArgs = -1;
1565     nameBuf.next = NULL;
1566
1567     for(State state = NO_NAME; lastChar != '\0'; str++)
1568     {
1569         lastChar = *str;
1570
1571         switch(state)
1572         {
1573         case NO_NAME:
1574             if (*str != SEP_CHAR)
1575             {
1576                 nameStart = str;
1577                 state = CLS_NAME; // we have found the start of the next entry
1578             }
1579             break;
1580
1581         case CLS_NAME:
1582             if (*nameStart == '"')
1583             {
1584                 while (*str && *str!='"')
1585                 {
1586                     str++;
1587                 }
1588                 nameStart++;
1589                 bQuote=true;
1590             }
1591
1592             if (*str == ':')
1593             {
1594                 if (*nameStart == '*' && !bQuote)
1595                 {
1596                     // Is the classname string a wildcard. Then set it to NULL
1597                     nameBuf.className = NULL;
1598                 }
1599                 else
1600                 {
1601                     int len = (int)(str - nameStart);
1602
1603                     // Take off the quote
1604                     if (bQuote) { len--; bQuote=false; }
1605                     
1606                     nameBuf.className = new char[len + 1];
1607                     MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1608                     memcpy(nameBuf.className, temp, len*sizeof(nameBuf.className[0]));
1609                     nameBuf.className[len] = '\0';
1610                 }
1611                 if (str[1] == ':')      // Accept class::name syntax too
1612                     str++;
1613                 nameStart = str + 1;
1614                 state = FUNC_NAME;
1615             }
1616             else if (*str == '\0' || *str == SEP_CHAR || *str == '(')
1617             {
1618                 /* This was actually a method name without any class */
1619                 nameBuf.className = NULL;
1620                 goto DONE_FUNC_NAME;
1621             }
1622             break;
1623
1624         case FUNC_NAME:
1625             if (*nameStart == '"')
1626             {
1627                 while ( (nameStart==str)    || // workaround to handle when className!=NULL
1628                         (*str && *str!='"'))
1629                 {
1630                     str++;
1631                 }
1632                        
1633                 nameStart++;
1634                 bQuote=true;
1635             }
1636
1637             if (*str == '\0' || *str == SEP_CHAR || *str == '(')
1638             {
1639             DONE_FUNC_NAME:
1640                 _ASSERTE(*str == '\0' || *str == SEP_CHAR || *str == '(');
1641
1642                 if (*nameStart == '*' && !bQuote)
1643                 {
1644                     // Is the name string a wildcard. Then set it to NULL
1645                     nameBuf.methodName = NULL;
1646                 }
1647                 else
1648                 {
1649                     int len = (int)(str - nameStart);
1650
1651                     // Take off the quote
1652                     if (bQuote) { len--; bQuote=false; }
1653
1654                     nameBuf.methodName = new char[len + 1];
1655                     MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1656                     memcpy(nameBuf.methodName, temp, len*sizeof(nameBuf.methodName[0]));
1657                     nameBuf.methodName[len] = '\0';
1658                 }
1659
1660                 if (*str == '\0' || *str == SEP_CHAR)
1661                 {
1662                     nameBuf.numArgs = -1;
1663                     goto DONE_ARG_LIST;
1664                 }
1665                 else
1666                 {
1667                     _ASSERTE(*str == '(');
1668                     nameBuf.numArgs = -1;
1669                     state = ARG_LIST;
1670                 }
1671             }
1672             break;
1673
1674         case ARG_LIST:
1675             if (*str == '\0' || *str == ')')
1676             {
1677                 if (nameBuf.numArgs == -1)
1678                     nameBuf.numArgs = 0;
1679
1680             DONE_ARG_LIST:
1681                 _ASSERTE(*str == '\0' || *str == SEP_CHAR || *str == ')');
1682
1683                 // We have parsed an entire method name.
1684                 // Create a new entry in the list for it
1685
1686                 MethodName * newName = new MethodName();
1687                 *newName = nameBuf;
1688                 newName->next = NULL;
1689                 *lastName = newName;
1690                 lastName = &newName->next;
1691                 state = NO_NAME;
1692
1693                 // Skip anything after the argument list until we find the next
1694                 // separator character, otherwise if we see "func(a,b):foo" we
1695                 // create entries for "func(a,b)" as well as ":foo".
1696                 if (*str == ')')
1697                 {
1698                     while (*str && *str != SEP_CHAR)
1699                     {
1700                         str++;
1701                     }
1702                     lastChar = *str;
1703                 }
1704             }
1705             else
1706             {
1707                 if (*str != SEP_CHAR && nameBuf.numArgs == -1)
1708                     nameBuf.numArgs = 1;
1709                 if (*str == ',')
1710                     nameBuf.numArgs++;
1711             }
1712             break;
1713
1714         default: _ASSERTE(!"Bad state"); break;
1715         }
1716     }
1717 }
1718
1719 /**************************************************************/
1720
1721 void MethodNamesListBase::Destroy() 
1722 {
1723     CONTRACTL
1724     {
1725         NOTHROW;
1726     }
1727     CONTRACTL_END;
1728     
1729     for(MethodName * pName = pNames; pName; /**/)
1730     {
1731         if (pName->className)
1732             delete [] pName->className;
1733         if (pName->methodName)
1734             delete [] pName->methodName;
1735
1736         MethodName * curName = pName;
1737         pName = pName->next;
1738         delete curName;
1739     }
1740 }
1741
1742 /**************************************************************/
1743 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, PCCOR_SIGNATURE sig) 
1744 {
1745     CONTRACTL
1746     {
1747         NOTHROW;
1748     }
1749     CONTRACTL_END;
1750
1751     int numArgs = -1;
1752     if (sig != NULL)
1753     {
1754         sig++;      // Skip calling convention
1755         numArgs = CorSigUncompressData(sig);  
1756     }
1757
1758     return IsInList(methName, clsName, numArgs);
1759 }
1760
1761 /**************************************************************/
1762 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, CORINFO_SIG_INFO* pSigInfo)
1763 {
1764     CONTRACTL
1765     {
1766         NOTHROW;
1767     }
1768     CONTRACTL_END;
1769
1770     int numArgs = -1;
1771     if (pSigInfo != NULL)
1772     {
1773         numArgs = pSigInfo->numArgs;
1774     }
1775
1776     return IsInList(methName, clsName, numArgs);
1777 }
1778
1779 /**************************************************************/
1780 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, int numArgs) 
1781 {
1782     CONTRACTL
1783     {
1784         NOTHROW;
1785     }
1786     CONTRACTL_END;
1787
1788     // Try to match all the entries in the list
1789
1790     for(MethodName * pName = pNames; pName; pName = pName->next)
1791     {
1792         // If numArgs is valid, check for mismatch
1793         if (pName->numArgs != -1 && pName->numArgs != numArgs)
1794             continue;
1795
1796         // If methodName is valid, check for mismatch
1797         if (pName->methodName) {
1798             if (strcmp(pName->methodName, methName) != 0) {
1799
1800                 // C++ embeds the class name into the method name,
1801                 // deal with that here (workaround)
1802                 const char* ptr = strchr(methName, ':');
1803                 if (ptr != 0 && ptr[1] == ':' && strcmp(&ptr[2], pName->methodName) == 0) {
1804                     unsigned clsLen = (unsigned)(ptr - methName);
1805                     if (pName->className == 0 || strncmp(pName->className, methName, clsLen) == 0)
1806                         return true;
1807                 }
1808                 continue;
1809             }
1810         }
1811
1812         // check for class Name exact match
1813         if (clsName == 0 || pName->className == 0 || strcmp(pName->className, clsName) == 0)
1814             return true;
1815
1816         // check for suffix wildcard like System.*
1817         unsigned len = (unsigned)strlen(pName->className);
1818         if (len > 0 && pName->className[len-1] == '*' && strncmp(pName->className, clsName, len-1) == 0)
1819             return true;
1820
1821 #ifdef _DEBUG
1822             // Maybe className doesnt include namespace. Try to match that
1823         LPCUTF8 onlyClass = ns::FindSep(clsName);
1824         if (onlyClass && strcmp(pName->className, onlyClass+1) == 0)
1825             return true;
1826 #endif
1827     }
1828     return(false);
1829 }
1830
1831 //=============================================================================
1832 // Signature Validation Functions (scaled down version from MDValidator
1833 //=============================================================================
1834
1835 //*****************************************************************************
1836 // This function validates one argument given an offset into the signature
1837 // where the argument begins.  This function assumes that the signature is well
1838 // formed as far as the compression scheme is concerned.
1839 // <TODO>@todo: Validate tokens embedded.</TODO>
1840 //*****************************************************************************
1841 HRESULT validateOneArg(
1842     mdToken     tk,                     // [IN] Token whose signature needs to be validated.
1843     SigParser  *pSig, 
1844     ULONG       *pulNSentinels,         // [IN/OUT] Number of sentinels
1845     IMDInternalImport*  pImport,        // [IN] Internal MD Import interface ptr
1846     BOOL        bNoVoidAllowed)         // [IN] Flag indicating whether "void" is disallowed for this arg
1847
1848 {
1849     CONTRACTL
1850     {
1851         NOTHROW;
1852     }
1853     CONTRACTL_END;
1854     
1855     BYTE        elementType;          // Current element type being processed.
1856     mdToken     token;                  // Embedded token.
1857     ULONG       ulArgCnt;               // Argument count for function pointer.
1858     ULONG       ulIndex;                // Index for type parameters
1859     ULONG       ulRank;                 // Rank of the array.
1860     ULONG       ulSizes;                // Count of sized dimensions of the array.
1861     ULONG       ulLbnds;                // Count of lower bounds of the array.
1862     ULONG       ulCallConv;
1863     
1864     HRESULT     hr = S_OK;              // Value returned.
1865     BOOL        bRepeat = TRUE;         // MODOPT and MODREQ belong to the arg after them
1866     
1867     while(bRepeat)
1868     {
1869         bRepeat = FALSE;
1870         // Validate that the argument is not missing.
1871         
1872         // Get the element type.
1873         if (FAILED(pSig->GetByte(&elementType)))
1874         {
1875             IfFailGo(VLDTR_E_SIG_MISSARG);
1876         }
1877         
1878         // Walk past all the modifier types.
1879         while (elementType & ELEMENT_TYPE_MODIFIER)
1880         {
1881             if (elementType == ELEMENT_TYPE_SENTINEL)
1882             {
1883                 if(pulNSentinels) *pulNSentinels+=1;
1884                 if(TypeFromToken(tk) != mdtMemberRef) IfFailGo(VLDTR_E_SIG_SENTINMETHODDEF);
1885             }
1886             if (FAILED(pSig->GetByte(&elementType)))
1887             {
1888                 IfFailGo(VLDTR_E_SIG_MISSELTYPE);
1889             }
1890         }
1891         
1892         switch (elementType)
1893         {
1894             case ELEMENT_TYPE_VOID:
1895                 if(bNoVoidAllowed) IfFailGo(VLDTR_E_SIG_BADVOID);
1896                 
1897             case ELEMENT_TYPE_BOOLEAN:
1898             case ELEMENT_TYPE_CHAR:
1899             case ELEMENT_TYPE_I1:
1900             case ELEMENT_TYPE_U1:
1901             case ELEMENT_TYPE_I2:
1902             case ELEMENT_TYPE_U2:
1903             case ELEMENT_TYPE_I4:
1904             case ELEMENT_TYPE_U4:
1905             case ELEMENT_TYPE_I8:
1906             case ELEMENT_TYPE_U8:
1907             case ELEMENT_TYPE_R4:
1908             case ELEMENT_TYPE_R8:
1909             case ELEMENT_TYPE_STRING:
1910             case ELEMENT_TYPE_OBJECT:
1911             case ELEMENT_TYPE_TYPEDBYREF:
1912             case ELEMENT_TYPE_U:
1913             case ELEMENT_TYPE_I:
1914                 break;
1915             case ELEMENT_TYPE_PTR:
1916                 // Validate the referenced type.
1917                 if(FAILED(hr = validateOneArg(tk, pSig, pulNSentinels, pImport, FALSE))) IfFailGo(hr);
1918                 break;
1919             case ELEMENT_TYPE_BYREF:  //fallthru
1920                 if(TypeFromToken(tk)==mdtFieldDef) IfFailGo(VLDTR_E_SIG_BYREFINFIELD);
1921             case ELEMENT_TYPE_PINNED:
1922             case ELEMENT_TYPE_SZARRAY:
1923                 // Validate the referenced type.
1924                 if(FAILED(hr = validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE))) IfFailGo(hr);
1925                 break;
1926             case ELEMENT_TYPE_CMOD_OPT:
1927             case ELEMENT_TYPE_CMOD_REQD:
1928                 bRepeat = TRUE; // go on validating, we're not done with this arg
1929             case ELEMENT_TYPE_VALUETYPE: //fallthru
1930             case ELEMENT_TYPE_CLASS:
1931                 // See if the token is missing.
1932                 if (FAILED(pSig->GetToken(&token)))
1933                 {
1934                     IfFailGo(VLDTR_E_SIG_MISSTKN);
1935                 }
1936                 // Token validation .
1937                 if(pImport)
1938                 {
1939                     ULONG   rid = RidFromToken(token);
1940                     ULONG   typ = TypeFromToken(token);
1941                     ULONG   maxrid = pImport->GetCountWithTokenKind(typ);
1942                     if(typ == mdtTypeDef) maxrid++;
1943                     if((rid==0)||(rid > maxrid)) IfFailGo(VLDTR_E_SIG_TKNBAD);
1944                 }
1945                 break;
1946                 
1947             case ELEMENT_TYPE_FNPTR: 
1948                 // <TODO>@todo: More function pointer validation?</TODO>
1949                 // Validate that calling convention is present.
1950                 if (FAILED(pSig->GetCallingConvInfo(&ulCallConv)))
1951                 {
1952                     IfFailGo(VLDTR_E_SIG_MISSFPTR);
1953                 }
1954                 if(((ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK) >= IMAGE_CEE_CS_CALLCONV_MAX) 
1955                     ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
1956                     &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS)))) IfFailGo(VLDTR_E_MD_BADCALLINGCONV);
1957                 
1958                 // Validate that argument count is present.
1959                 if (FAILED(pSig->GetData(&ulArgCnt)))
1960                 {
1961                     IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
1962                 }
1963                 
1964                 // FNPTR signature must follow the rules of MethodDef
1965                 // Validate and consume return type.
1966                 IfFailGo(validateOneArg(mdtMethodDef, pSig, NULL, pImport, FALSE));
1967                 
1968                 // Validate and consume the arguments.
1969                 while(ulArgCnt--)
1970                 {
1971                     IfFailGo(validateOneArg(mdtMethodDef, pSig, NULL, pImport, TRUE));
1972                 }
1973                 break;
1974                 
1975             case ELEMENT_TYPE_ARRAY:
1976                 // Validate and consume the base type.
1977                 IfFailGo(validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE));
1978                 
1979                 // Validate that the rank is present.
1980                 if (FAILED(pSig->GetData(&ulRank)))
1981                 {
1982                     IfFailGo(VLDTR_E_SIG_MISSRANK);
1983                 }
1984                 
1985                 // Process the sizes.
1986                 if (ulRank)
1987                 {
1988                     // Validate that the count of sized-dimensions is specified.
1989                     if (FAILED(pSig->GetData(&ulSizes)))
1990                     {
1991                         IfFailGo(VLDTR_E_SIG_MISSNSIZE);
1992                     }
1993                     
1994                     // Loop over the sizes.
1995                     while(ulSizes--)
1996                     {
1997                         // Validate the current size.
1998                         if (FAILED(pSig->GetData(NULL)))
1999                         {
2000                             IfFailGo(VLDTR_E_SIG_MISSSIZE);
2001                         }
2002                     }
2003                     
2004                     // Validate that the count of lower bounds is specified.
2005                     if (FAILED(pSig->GetData(&ulLbnds)))
2006                     {
2007                         IfFailGo(VLDTR_E_SIG_MISSNLBND);
2008                     }
2009                     
2010                     // Loop over the lower bounds.
2011                     while(ulLbnds--)
2012                     {
2013                         // Validate the current lower bound.
2014                         if (FAILED(pSig->GetData(NULL)))
2015                         {
2016                             IfFailGo(VLDTR_E_SIG_MISSLBND);
2017                         }
2018                     }
2019                 }
2020                 break;
2021                 case ELEMENT_TYPE_VAR:
2022                 case ELEMENT_TYPE_MVAR:
2023                     // Validate that index is present.
2024                     if (FAILED(pSig->GetData(&ulIndex)))
2025                     {
2026                         IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
2027                     }
2028                     
2029                     //@todo GENERICS: check that index is in range
2030                     break;
2031                     
2032                 case ELEMENT_TYPE_GENERICINST:
2033                     // Validate the generic type.
2034                     IfFailGo(validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE));
2035                     
2036                     // Validate that parameter count is present.
2037                     if (FAILED(pSig->GetData(&ulArgCnt)))
2038                     {
2039                         IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
2040                     }
2041                     
2042                 //@todo GENERICS: check that number of parameters matches definition?
2043                     
2044                     // Validate and consume the parameters.
2045                     while(ulArgCnt--)
2046                     {
2047                         IfFailGo(validateOneArg(tk, pSig, NULL, pImport, TRUE));
2048                     }
2049                     break;
2050                     
2051             case ELEMENT_TYPE_SENTINEL: // this case never works because all modifiers are skipped before switch
2052                 if(TypeFromToken(tk) == mdtMethodDef) IfFailGo(VLDTR_E_SIG_SENTINMETHODDEF);
2053                 break;
2054                 
2055             default:
2056                 IfFailGo(VLDTR_E_SIG_BADELTYPE);
2057                 break;
2058         }   // switch (ulElementType)
2059     } // end while(bRepeat)
2060 ErrExit:
2061     return hr;
2062 }   // validateOneArg()
2063
2064 //*****************************************************************************
2065 // This function validates the given Method/Field/Standalone signature.  
2066 //@todo GENERICS: MethodInstantiation?
2067 //*****************************************************************************
2068 HRESULT validateTokenSig(
2069     mdToken             tk,                     // [IN] Token whose signature needs to be validated.
2070     PCCOR_SIGNATURE     pbSig,                  // [IN] Signature.
2071     ULONG               cbSig,                  // [IN] Size in bytes of the signature.
2072     DWORD               dwFlags,                // [IN] Method flags.
2073     IMDInternalImport*  pImport)               // [IN] Internal MD Import interface ptr
2074 {
2075     CONTRACTL
2076     {
2077         NOTHROW;
2078     }
2079     CONTRACTL_END;
2080     
2081     ULONG       ulCallConv;             // Calling convention.
2082     ULONG       ulArgCount = 1;         // Count of arguments (1 because of the return type)
2083     ULONG       ulTyArgCount = 0;         // Count of type arguments
2084     ULONG       ulArgIx = 0;            // Starting index of argument (standalone sig: 1)
2085     ULONG       i;                      // Looping index.
2086     HRESULT     hr = S_OK;              // Value returned.
2087     ULONG       ulNSentinels = 0;
2088     SigParser   sig(pbSig, cbSig);
2089     
2090     _ASSERTE(TypeFromToken(tk) == mdtMethodDef ||
2091              TypeFromToken(tk) == mdtMemberRef ||
2092              TypeFromToken(tk) == mdtSignature ||
2093              TypeFromToken(tk) == mdtFieldDef);
2094
2095     // Check for NULL signature.
2096     if (!pbSig || !cbSig) return VLDTR_E_SIGNULL;
2097
2098     // Validate the calling convention.
2099     
2100     // Moves behind calling convention
2101     IfFailRet(sig.GetCallingConvInfo(&ulCallConv));
2102     i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
2103     switch(TypeFromToken(tk))
2104     {
2105         case mdtMethodDef: // MemberRefs have no flags available
2106             // If HASTHIS is set on the calling convention, the method should not be static.
2107             if ((ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
2108                 IsMdStatic(dwFlags)) return VLDTR_E_MD_THISSTATIC;
2109             
2110             // If HASTHIS is not set on the calling convention, the method should be static.
2111             if (!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
2112                 !IsMdStatic(dwFlags)) return VLDTR_E_MD_NOTTHISNOTSTATIC;
2113             // fall thru to callconv check;
2114             
2115         case mdtMemberRef:
2116             if(i == IMAGE_CEE_CS_CALLCONV_FIELD) return validateOneArg(tk, &sig, NULL, pImport, TRUE);
2117             
2118             // EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)
2119             if(((i != IMAGE_CEE_CS_CALLCONV_DEFAULT)&&( i != IMAGE_CEE_CS_CALLCONV_VARARG))
2120                 || (ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)) return VLDTR_E_MD_BADCALLINGCONV;
2121             break;
2122             
2123         case mdtSignature:
2124             if(i != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) // then it is function sig for calli
2125             {
2126                 if((i >= IMAGE_CEE_CS_CALLCONV_MAX) 
2127                     ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
2128                     &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS)))) return VLDTR_E_MD_BADCALLINGCONV;
2129             }
2130             else
2131                 ulArgIx = 1;        // Local variable signatures don't have a return type 
2132             break;
2133             
2134         case mdtFieldDef:
2135             if(i != IMAGE_CEE_CS_CALLCONV_FIELD) return VLDTR_E_MD_BADCALLINGCONV;
2136             return validateOneArg(tk, &sig, NULL, pImport, TRUE);
2137     }
2138     // Is there any sig left for arguments?
2139     
2140     // Get the type argument count
2141     if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2142     {
2143         if (FAILED(sig.GetData(&ulTyArgCount)))
2144         {
2145             return VLDTR_E_MD_NOARGCNT;
2146         }
2147     }
2148     
2149     // Get the argument count.
2150     if (FAILED(sig.GetData(&ulArgCount)))
2151     {
2152         return VLDTR_E_MD_NOARGCNT;
2153     }
2154     
2155     // Validate the return type and the arguments.
2156     // (at this moment ulArgCount = num.args+1, ulArgIx = (standalone sig. ? 1 :0); )
2157     for(; ulArgIx < ulArgCount; ulArgIx++)
2158     {
2159         if(FAILED(hr = validateOneArg(tk, &sig, &ulNSentinels, pImport, (ulArgIx!=0)))) return hr;
2160     }
2161     
2162     // <TODO>@todo: we allow junk to be at the end of the signature (we may not consume it all)
2163     // do we care?</TODO>
2164     
2165     if((ulNSentinels != 0) && ((ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_VARARG ))
2166         return VLDTR_E_SIG_SENTMUSTVARARG;
2167     if(ulNSentinels > 1) return VLDTR_E_SIG_MULTSENTINELS;
2168     return S_OK;
2169 }   // validateTokenSig()
2170
2171 HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString)
2172 {
2173     CONTRACTL
2174     {
2175         NOTHROW;
2176     }
2177     CONTRACTL_END;
2178     
2179     _ASSERTE(pString);
2180     STORAGESIGNATURE* pSig = (STORAGESIGNATURE*) pMetaData;
2181
2182     // Verify the signature.
2183
2184     // If signature didn't match, you shouldn't be here.
2185     if (pSig->GetSignature() != STORAGE_MAGIC_SIG)
2186         return CLDB_E_FILE_CORRUPT;
2187
2188     // The version started in version 1.1
2189     if (pSig->GetMajorVer() < 1)
2190         return CLDB_E_FILE_OLDVER;
2191
2192     if (pSig->GetMajorVer() == 1 && pSig->GetMinorVer() < 1)
2193         return CLDB_E_FILE_OLDVER;
2194     
2195     // Header data starts after signature.
2196     *pString = (LPCSTR) pSig->pVersion;
2197     return S_OK;
2198 }
2199
2200 //*****************************************************************************
2201 // Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>.
2202 //*****************************************************************************
2203 HRESULT Utf2Quick(
2204     LPCUTF8     pStr,                   // The string to convert.
2205     CQuickArray<WCHAR> &rStr,           // The QuickArray<WCHAR> to convert it into.
2206     int         iCurLen)                // Inital characters in the array to leave (default 0).
2207 {
2208     CONTRACTL
2209     {
2210         NOTHROW;
2211     }
2212     CONTRACTL_END;
2213     
2214     HRESULT     hr = S_OK;              // A result.
2215     int         iReqLen;                // Required additional length.
2216     int         iActLen;
2217     int         bAlloc = 0;             // If non-zero, allocation was required.
2218
2219     if (iCurLen < 0 )
2220     {
2221         _ASSERTE_MSG(false, "Invalid current length");
2222         return E_INVALIDARG;
2223     }
2224
2225     // Calculate the space available
2226     S_SIZE_T cchAvail = S_SIZE_T(rStr.MaxSize()) - S_SIZE_T(iCurLen);
2227     if (cchAvail.IsOverflow() || cchAvail.Value() > INT_MAX)
2228     {
2229         _ASSERTE_MSG(false, "Integer overflow/underflow");
2230         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2231     }
2232
2233     // Attempt the conversion.
2234     LPWSTR rNewStr = rStr.Ptr()+iCurLen;
2235     if(rNewStr < rStr.Ptr())
2236     {
2237         _ASSERTE_MSG(false, "Integer overflow/underflow");
2238         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2239     }
2240     iReqLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, rNewStr, (int)(cchAvail.Value()));
2241
2242     // If the buffer was too small, determine what is required.
2243     if (iReqLen == 0) 
2244         bAlloc = iReqLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, 0, 0);
2245     // Resize the buffer.  If the buffer was large enough, this just sets the internal
2246     //  counter, but if it was too small, this will attempt a reallocation.  Note that 
2247     //  the length includes the terminating W('/0').
2248     IfFailGo(rStr.ReSizeNoThrow(iCurLen+iReqLen));
2249     // If we had to realloc, then do the conversion again, now that the buffer is 
2250     //  large enough.
2251     if (bAlloc) {
2252         //recalculating cchAvail since MaxSize could have been changed.
2253         cchAvail = S_SIZE_T(rStr.MaxSize()) - S_SIZE_T(iCurLen);
2254         if (cchAvail.IsOverflow() || cchAvail.Value() > INT_MAX)
2255         {
2256             _ASSERTE_MSG(false, "Integer overflow/underflow");
2257             return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2258         }
2259         //reculculating rNewStr
2260         rNewStr = rStr.Ptr()+iCurLen;
2261         
2262         if(rNewStr < rStr.Ptr())
2263         {
2264         _ASSERTE_MSG(false, "Integer overflow/underflow");
2265         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2266         }
2267         iActLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, rNewStr, (int)(cchAvail.Value()));
2268         _ASSERTE(iReqLen == iActLen);
2269     }
2270 ErrExit:
2271     return hr;
2272 } // HRESULT Utf2Quick()
2273
2274
2275 //*****************************************************************************
2276 //  Extract the movl 64-bit unsigned immediate from an IA64 bundle
2277 //  (Format X2)
2278 //*****************************************************************************
2279 UINT64 GetIA64Imm64(UINT64 * pBundle)
2280 {
2281     WRAPPER_NO_CONTRACT;
2282     
2283     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2284     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2285
2286     return GetIA64Imm64(temp0, temp1);
2287 }
2288
2289 UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1)
2290 {
2291     LIMITED_METHOD_CONTRACT;
2292     
2293     UINT64 imm64 = 0;
2294     
2295 #ifdef _DEBUG_IMPL
2296     //
2297     // make certain we're decoding a movl opcode, with template 4 or 5
2298     //
2299     UINT64    templa = (qword0 >>  0) & 0x1f;
2300     UINT64    opcode = (qword1 >> 60) & 0xf;
2301     
2302     _ASSERTE((opcode == 0x6) && ((templa == 0x4) || (templa == 0x5)));
2303 #endif        
2304
2305     imm64  = (qword1 >> 59) << 63;       //  1 i
2306     imm64 |= (qword1 << 41) >>  1;       // 23 high bits of imm41 
2307     imm64 |= (qword0 >> 46) << 22;       // 18 low  bits of imm41
2308     imm64 |= (qword1 >> 23) & 0x200000;  //  1 ic
2309     imm64 |= (qword1 >> 29) & 0x1F0000;  //  5 imm5c
2310     imm64 |= (qword1 >> 43) & 0xFF80;    //  9 imm9d
2311     imm64 |= (qword1 >> 36) & 0x7F;      //  7 imm7b
2312
2313     return imm64;
2314 }
2315
2316 //*****************************************************************************
2317 //  Deposit the movl 64-bit unsigned immediate into an IA64 bundle
2318 //  (Format X2)
2319 //*****************************************************************************
2320 void PutIA64Imm64(UINT64 * pBundle, UINT64 imm64)
2321 {
2322     LIMITED_METHOD_CONTRACT;
2323     
2324 #ifdef _DEBUG_IMPL
2325     //
2326     // make certain we're decoding a movl opcode, with template 4 or 5
2327     //
2328     UINT64    templa = (pBundle[0] >>  0) & 0x1f;
2329     UINT64    opcode = (pBundle[1] >> 60) & 0xf ;
2330     
2331     _ASSERTE((opcode == 0x6) && ((templa == 0x4) || (templa == 0x5)));
2332 #endif        
2333
2334     const UINT64 mask0 = UI64(0x00003FFFFFFFFFFF);
2335     const UINT64 mask1 = UI64(0xF000080FFF800000);
2336
2337     /* Clear all bits used as part of the imm64 */
2338     pBundle[0] &= mask0;
2339     pBundle[1] &= mask1;
2340
2341     UINT64 temp0;
2342     UINT64 temp1;
2343
2344     temp1  = (imm64 >> 63)      << 59;  //  1 i
2345     temp1 |= (imm64 & 0xFF80)   << 43;  //  9 imm9d
2346     temp1 |= (imm64 & 0x1F0000) << 29;  //  5 imm5c
2347     temp1 |= (imm64 & 0x200000) << 23;  //  1 ic
2348     temp1 |= (imm64 & 0x7F)     << 36;  //  7 imm7b
2349     temp1 |= (imm64 <<  1)      >> 41;  // 23 high bits of imm41
2350     temp0  = (imm64 >> 22)      << 46;  // 18 low bits of imm41
2351
2352     /* Or in the new bits used in the imm64 */
2353     pBundle[0] |= temp0;
2354     pBundle[1] |= temp1;
2355     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2356 }
2357
2358 //*****************************************************************************
2359 //  Extract the IP-Relative signed 25-bit immediate from an IA64 bundle 
2360 //  (Formats B1, B2 or B3)
2361 //  Note that due to branch target alignment requirements 
2362 //       the lowest four bits in the result will always be zero.
2363 //*****************************************************************************
2364 INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot)
2365 {
2366     WRAPPER_NO_CONTRACT;
2367     
2368     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2369     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2370
2371     return GetIA64Rel25(temp0, temp1, slot);
2372 }
2373
2374 INT32 GetIA64Rel25(UINT64 qword0, UINT64 qword1, UINT32 slot)
2375 {
2376     LIMITED_METHOD_CONTRACT;
2377     
2378     INT32 imm25 = 0;
2379     
2380     if (slot == 2)
2381     {
2382         if ((qword1 >> 59) & 1)
2383             imm25 = 0xFF000000;
2384         imm25 |= (qword1 >> 32) & 0x00FFFFF0;    // 20 imm20b
2385     }
2386     else if (slot == 1)
2387     {
2388         if ((qword1 >> 18) & 1)
2389             imm25 = 0xFF000000;
2390         imm25 |= (qword1 <<  9) & 0x00FFFE00;    // high 15 of imm20b
2391         imm25 |= (qword0 >> 55) & 0x000001F0;    // low   5 of imm20b
2392     }
2393     else if (slot == 0)
2394     {
2395         if ((qword0 >> 41) & 1)
2396             imm25 = 0xFF000000;
2397         imm25 |= (qword0 >> 14) & 0x00FFFFF0;    // 20 imm20b
2398     }
2399
2400     return imm25;
2401 }
2402
2403 //*****************************************************************************
2404 //  Deposit the IP-Relative signed 25-bit immediate into an IA64 bundle
2405 //  (Formats B1, B2 or B3)
2406 //  Note that due to branch target alignment requirements 
2407 //       the lowest four bits are required to be zero.
2408 //*****************************************************************************
2409 void PutIA64Rel25(UINT64 * pBundle, UINT32 slot, INT32 imm25)
2410 {
2411     LIMITED_METHOD_CONTRACT;
2412     
2413     _ASSERTE((imm25 & 0xF) == 0);
2414
2415     if (slot == 2)
2416     {
2417         const UINT64 mask1 = UI64(0xF700000FFFFFFFFF);
2418         /* Clear all bits used as part of the imm25 */
2419         pBundle[1] &= mask1;
2420
2421         UINT64 temp1;
2422         
2423         temp1  = (UINT64) (imm25 & 0x1000000) << 35;     //  1 s
2424         temp1 |= (UINT64) (imm25 & 0x0FFFFF0) << 32;     // 20 imm20b
2425         
2426         /* Or in the new bits used in the imm64 */
2427         pBundle[1] |= temp1;
2428     }
2429     else if (slot == 1)
2430     {
2431         const UINT64 mask0 = UI64(0x0EFFFFFFFFFFFFFF);
2432         const UINT64 mask1 = UI64(0xFFFFFFFFFFFB8000);
2433         /* Clear all bits used as part of the imm25 */
2434         pBundle[0] &= mask0;
2435         pBundle[1] &= mask1;
2436         
2437         UINT64 temp0;
2438         UINT64 temp1;
2439         
2440         temp1  = (UINT64) (imm25 & 0x1000000) >>  7;     //  1 s
2441         temp1 |= (UINT64) (imm25 & 0x0FFFE00) >>  9;     // high 15 of imm20b
2442         temp0  = (UINT64) (imm25 & 0x00001F0) << 55;     // low   5 of imm20b
2443         
2444         /* Or in the new bits used in the imm64 */
2445         pBundle[0] |= temp0;
2446         pBundle[1] |= temp1;
2447     }
2448     else if (slot == 0)
2449     {
2450         const UINT64 mask0 = UI64(0xFFFFFDC00003FFFF);
2451         /* Clear all bits used as part of the imm25 */
2452         pBundle[0] &= mask0;
2453
2454         UINT64 temp0;
2455         
2456         temp0  = (UINT64) (imm25 & 0x1000000) << 16;     //  1 s
2457         temp0 |= (UINT64) (imm25 & 0x0FFFFF0) << 14;     // 20 imm20b
2458         
2459         /* Or in the new bits used in the imm64 */
2460         pBundle[0] |= temp0;
2461
2462     }
2463     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2464 }
2465
2466 //*****************************************************************************
2467 //  Extract the IP-Relative signed 64-bit immediate from an IA64 bundle 
2468 //  (Formats X3 or X4)
2469 //*****************************************************************************
2470 INT64 GetIA64Rel64(UINT64 * pBundle)
2471 {
2472     WRAPPER_NO_CONTRACT;
2473     
2474     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2475     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2476
2477     return GetIA64Rel64(temp0, temp1);
2478 }
2479
2480 INT64 GetIA64Rel64(UINT64 qword0, UINT64 qword1)
2481 {
2482     LIMITED_METHOD_CONTRACT;
2483     
2484     INT64 imm64 = 0;
2485     
2486 #ifdef _DEBUG_IMPL
2487     //
2488     // make certain we're decoding a brl opcode, with template 4 or 5
2489     //
2490     UINT64       templa = (qword0 >>  0) & 0x1f;
2491     UINT64       opcode = (qword1 >> 60) & 0xf;
2492     
2493     _ASSERTE(((opcode == 0xC) || (opcode == 0xD)) &&
2494              ((templa == 0x4) || (templa == 0x5)));
2495 #endif        
2496
2497     imm64  = (qword1 >> 59) << 63;         //  1 i
2498     imm64 |= (qword1 << 41) >>  1;         // 23 high bits of imm39 
2499     imm64 |= (qword0 >> 48) << 24;         // 16 low  bits of imm39
2500     imm64 |= (qword1 >> 32) & 0xFFFFF0;    // 20 imm20b
2501                                           //  4 bits of zeros
2502     return imm64;
2503 }
2504
2505 //*****************************************************************************
2506 //  Deposit the IP-Relative signed 64-bit immediate into an IA64 bundle
2507 //  (Formats X3 or X4)
2508 //*****************************************************************************
2509 void PutIA64Rel64(UINT64 * pBundle, INT64 imm64)
2510 {
2511     LIMITED_METHOD_CONTRACT;
2512     
2513 #ifdef _DEBUG_IMPL
2514     //
2515     // make certain we're decoding a brl opcode, with template 4 or 5
2516     //
2517     UINT64    templa = (pBundle[0] >>  0) & 0x1f;
2518     UINT64    opcode = (pBundle[1] >> 60) & 0xf;
2519     
2520     _ASSERTE(((opcode == 0xC) || (opcode == 0xD)) &&
2521              ((templa == 0x4) || (templa == 0x5)));
2522     _ASSERTE((imm64 & 0xF) == 0);
2523 #endif        
2524
2525     const UINT64 mask0 = UI64(0x00003FFFFFFFFFFF);
2526     const UINT64 mask1 = UI64(0xF700000FFF800000);
2527
2528     /* Clear all bits used as part of the imm64 */
2529     pBundle[0] &= mask0;
2530     pBundle[1] &= mask1;
2531
2532     UINT64 temp0  = (imm64 & UI64(0x000000FFFF000000)) << 24;  // 16 low  bits of imm39
2533     UINT64 temp1  = (imm64 & UI64(0x8000000000000000)) >>  4   //  1 i
2534                   | (imm64 & UI64(0x7FFFFF0000000000)) >> 40   // 23 high bits of imm39 
2535                   | (imm64 & UI64(0x0000000000FFFFF0)) << 32;  // 20 imm20b
2536
2537     /* Or in the new bits used in the imm64 */
2538     pBundle[0] |= temp0;
2539     pBundle[1] |= temp1;
2540     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2541 }
2542
2543 //*****************************************************************************
2544 //  Extract the 16-bit immediate from ARM Thumb2 Instruction (format T2_N)
2545 //*****************************************************************************
2546 static FORCEINLINE UINT16 GetThumb2Imm16(UINT16 * p)
2547 {
2548     LIMITED_METHOD_CONTRACT;
2549     
2550     return ((p[0] << 12) & 0xf000) |
2551            ((p[0] <<  1) & 0x0800) |
2552            ((p[1] >>  4) & 0x0700) |
2553            ((p[1] >>  0) & 0x00ff);
2554 }
2555
2556 //*****************************************************************************
2557 //  Extract the 32-bit immediate from movw/movt sequence
2558 //*****************************************************************************
2559 UINT32 GetThumb2Mov32(UINT16 * p)
2560 {
2561     LIMITED_METHOD_CONTRACT;
2562
2563     // Make sure we are decoding movw/movt sequence
2564     _ASSERTE_IMPL((*(p+0) & 0xFBF0) == 0xF240);
2565     _ASSERTE_IMPL((*(p+2) & 0xFBF0) == 0xF2C0);
2566
2567     return (UINT32)GetThumb2Imm16(p) + ((UINT32)GetThumb2Imm16(p + 2) << 16);
2568 }
2569
2570 //*****************************************************************************
2571 //  Deposit the 16-bit immediate into ARM Thumb2 Instruction (format T2_N)
2572 //*****************************************************************************
2573 static FORCEINLINE void PutThumb2Imm16(UINT16 * p, UINT16 imm16)
2574 {
2575     LIMITED_METHOD_CONTRACT;
2576
2577     USHORT Opcode0 = p[0];
2578     USHORT Opcode1 = p[1];
2579     Opcode0 &= ~((0xf000 >> 12) | (0x0800 >> 1));
2580     Opcode1 &= ~((0x0700 <<  4) | (0x00ff << 0));
2581     Opcode0 |= (imm16 & 0xf000) >> 12;
2582     Opcode0 |= (imm16 & 0x0800) >>  1;
2583     Opcode1 |= (imm16 & 0x0700) <<  4;
2584     Opcode1 |= (imm16 & 0x00ff) <<  0;
2585     p[0] = Opcode0;
2586     p[1] = Opcode1;
2587 }
2588
2589 //*****************************************************************************
2590 //  Deposit the 32-bit immediate into movw/movt Thumb2 sequence
2591 //*****************************************************************************
2592 void PutThumb2Mov32(UINT16 * p, UINT32 imm32)
2593 {
2594     LIMITED_METHOD_CONTRACT;
2595
2596     // Make sure we are decoding movw/movt sequence
2597     _ASSERTE_IMPL((*(p+0) & 0xFBF0) == 0xF240);
2598     _ASSERTE_IMPL((*(p+2) & 0xFBF0) == 0xF2C0);
2599
2600     PutThumb2Imm16(p, (UINT16)imm32);
2601     PutThumb2Imm16(p + 2, (UINT16)(imm32 >> 16));
2602 }
2603
2604 //*****************************************************************************
2605 //  Extract the 24-bit rel offset from bl instruction
2606 //*****************************************************************************
2607 INT32 GetThumb2BlRel24(UINT16 * p)
2608 {
2609     LIMITED_METHOD_CONTRACT;
2610
2611     USHORT Opcode0 = p[0];
2612     USHORT Opcode1 = p[1];
2613
2614     UINT32 S  = Opcode0 >> 10;
2615     UINT32 J2 = Opcode1 >> 11;
2616     UINT32 J1 = Opcode1 >> 13;
2617
2618     INT32 ret = 
2619         ((S << 24)              & 0x1000000) |
2620         (((J1 ^ S ^ 1) << 23)   & 0x0800000) |
2621         (((J2 ^ S ^ 1) << 22)   & 0x0400000) |
2622         ((Opcode0 << 12)        & 0x03FF000) |
2623         ((Opcode1 <<  1)        & 0x0000FFE);
2624
2625     // Sign-extend and return
2626     return (ret << 7) >> 7;
2627 }
2628
2629 //*****************************************************************************
2630 //  Extract the 24-bit rel offset from bl instruction
2631 //*****************************************************************************
2632 void PutThumb2BlRel24(UINT16 * p, INT32 imm24)
2633 {
2634     LIMITED_METHOD_CONTRACT;
2635
2636     // Verify that we got a valid offset
2637     _ASSERTE(FitsInThumb2BlRel24(imm24));
2638
2639 #if defined(_TARGET_ARM_)
2640     // Ensure that the ThumbBit is not set on the offset
2641     // as it cannot be encoded.
2642     _ASSERTE(!(imm24 & THUMB_CODE));
2643 #endif // _TARGET_ARM_    
2644
2645     USHORT Opcode0 = p[0];
2646     USHORT Opcode1 = p[1];
2647     Opcode0 &= 0xF800;
2648     Opcode1 &= 0xD000;
2649
2650     UINT32 S  =  (imm24 & 0x1000000) >> 24;
2651     UINT32 J1 = ((imm24 & 0x0800000) >> 23) ^ S ^ 1;
2652     UINT32 J2 = ((imm24 & 0x0400000) >> 22) ^ S ^ 1;
2653
2654     Opcode0 |=  ((imm24 & 0x03FF000) >> 12) | (S << 10);
2655     Opcode1 |=  ((imm24 & 0x0000FFE) >>  1) | (J1 << 13) | (J2 << 11);
2656
2657     p[0] = Opcode0;
2658     p[1] = Opcode1;
2659
2660     _ASSERTE(GetThumb2BlRel24(p) == imm24);
2661 }
2662
2663 //*****************************************************************************
2664 //  Extract the PC-Relative offset from a b or bl instruction 
2665 //*****************************************************************************
2666 INT32 GetArm64Rel28(UINT32 * pCode)
2667 {
2668     LIMITED_METHOD_CONTRACT;
2669
2670     UINT32 branchInstr = *pCode;
2671
2672     // first shift 6 bits left to set the sign bit, 
2673     // then arithmetic shift right by 4 bits 
2674     INT32 imm28 = (((INT32)(branchInstr & 0x03FFFFFF)) << 6) >> 4;
2675
2676     return imm28;
2677 }
2678
2679 //*****************************************************************************
2680 //  Extract the PC-Relative offset from an adrp instruction
2681 //*****************************************************************************
2682 INT32 GetArm64Rel21(UINT32 * pCode)
2683 {
2684     LIMITED_METHOD_CONTRACT;
2685
2686     UINT32 addInstr = *pCode;
2687
2688     // 23-5 bits for the high part. Shift it by 5.
2689     INT32 immhi = (((INT32)(addInstr & 0xFFFFE0))) >> 5;
2690     // 30,29 bits for the lower part. Shift it by 29.
2691     INT32 immlo = ((INT32)(addInstr & 0x60000000)) >> 29;
2692
2693     // Merge them
2694     INT32 imm21 = (immhi << 2) | immlo;
2695
2696     return imm21;
2697 }
2698
2699 //*****************************************************************************
2700 //  Extract the PC-Relative offset from an add instruction
2701 //*****************************************************************************
2702 INT32 GetArm64Rel12(UINT32 * pCode)
2703 {
2704     LIMITED_METHOD_CONTRACT;
2705
2706     UINT32 addInstr = *pCode;
2707
2708     // 21-10 contains value. Mask 12 bits and shift by 10 bits.
2709     INT32 imm12 = (INT32)(addInstr & 0x003FFC00) >> 10;
2710
2711     return imm12;
2712 }
2713
2714 //*****************************************************************************
2715 //  Deposit the PC-Relative offset 'imm28' into a b or bl instruction 
2716 //*****************************************************************************
2717 void PutArm64Rel28(UINT32 * pCode, INT32 imm28)
2718 {
2719     LIMITED_METHOD_CONTRACT;
2720
2721     // Verify that we got a valid offset
2722     _ASSERTE(FitsInRel28(imm28));
2723     _ASSERTE((imm28 & 0x3) == 0);    // the low two bits must be zero
2724
2725     UINT32 branchInstr = *pCode;
2726
2727     branchInstr &= 0xFC000000;       // keep bits 31-26
2728
2729     // Assemble the pc-relative delta 'imm28' into the branch instruction
2730     branchInstr |= ((imm28 >> 2) & 0x03FFFFFF);
2731
2732     *pCode = branchInstr;          // write the assembled instruction
2733
2734     _ASSERTE(GetArm64Rel28(pCode) == imm28);
2735 }
2736
2737 //*****************************************************************************
2738 //  Deposit the PC-Relative offset 'imm21' into an adrp instruction
2739 //*****************************************************************************
2740 void PutArm64Rel21(UINT32 * pCode, INT32 imm21)
2741 {
2742     LIMITED_METHOD_CONTRACT;
2743
2744     // Verify that we got a valid offset
2745     _ASSERTE(FitsInRel21(imm21));
2746
2747     UINT32 adrpInstr = *pCode;
2748     // Check adrp opcode 1ii1 0000 ...
2749     _ASSERTE((adrpInstr & 0x9F000000) == 0x90000000);
2750
2751     adrpInstr &= 0x9F00001F;               // keep bits 31, 28-24, 4-0.
2752     INT32 immlo = imm21 & 0x03;            // Extract low 2 bits which will occupy 30-29 bits.
2753     INT32 immhi = (imm21 & 0x1FFFFC) >> 2; // Extract high 19 bits which will occupy 23-5 bits.
2754     adrpInstr |= ((immlo << 29) | (immhi << 5));
2755
2756     *pCode = adrpInstr;                    // write the assembled instruction
2757
2758     _ASSERTE(GetArm64Rel21(pCode) == imm21);
2759 }
2760
2761 //*****************************************************************************
2762 //  Deposit the PC-Relative offset 'imm12' into an add instruction
2763 //*****************************************************************************
2764 void PutArm64Rel12(UINT32 * pCode, INT32 imm12)
2765 {
2766     LIMITED_METHOD_CONTRACT;
2767
2768     // Verify that we got a valid offset
2769     _ASSERTE(FitsInRel12(imm12));
2770
2771     UINT32 addInstr = *pCode;
2772     // Check add opcode 1001 0001 00...
2773     _ASSERTE((addInstr & 0xFFC00000) == 0x91000000);
2774
2775     addInstr &= 0xFFC003FF;     // keep bits 31-22, 9-0
2776     addInstr |= (imm12 << 10);  // Occupy 21-10.
2777
2778     *pCode = addInstr;          // write the assembled instruction
2779
2780     _ASSERTE(GetArm64Rel12(pCode) == imm12);
2781 }
2782
2783 //---------------------------------------------------------------------
2784 // Splits a command line into argc/argv lists, using the VC7 parsing rules.
2785 //
2786 // This functions interface mimics the CommandLineToArgvW api.
2787 //
2788 // If function fails, returns NULL.
2789 //
2790 // If function suceeds, call delete [] on return pointer when done.
2791 //
2792 //---------------------------------------------------------------------
2793 // NOTE: Implementation-wise, once every few years it would be a good idea to
2794 // compare this code with the C runtime library's parse_cmdline method,
2795 // which is in vctools\crt\crtw32\startup\stdargv.c.  (Note we don't
2796 // support wild cards, and we use Unicode characters exclusively.)
2797 // We are up to date as of ~6/2005.
2798 //---------------------------------------------------------------------
2799 LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs)
2800 {
2801     STATIC_CONTRACT_NOTHROW;
2802     STATIC_CONTRACT_GC_NOTRIGGER;
2803     STATIC_CONTRACT_FAULT;
2804
2805
2806     *pNumArgs = 0;
2807
2808     int nch = (int)wcslen(lpCmdLine);
2809
2810     // Calculate the worstcase storage requirement. (One pointer for
2811     // each argument, plus storage for the arguments themselves.)
2812     int cbAlloc = (nch+1)*sizeof(LPWSTR) + sizeof(WCHAR)*(nch + 1);
2813     LPWSTR pAlloc = new (nothrow) WCHAR[cbAlloc / sizeof(WCHAR)];
2814     if (!pAlloc)
2815         return NULL;
2816
2817     LPWSTR *argv = (LPWSTR*) pAlloc;  // We store the argv pointers in the first halt
2818     LPWSTR  pdst = (LPWSTR)( ((BYTE*)pAlloc) + sizeof(LPWSTR)*(nch+1) ); // A running pointer to second half to store arguments
2819     LPCWSTR psrc = lpCmdLine;
2820     WCHAR   c;
2821     BOOL    inquote;
2822     BOOL    copychar;
2823     int     numslash;
2824
2825     // First, parse the program name (argv[0]). Argv[0] is parsed under
2826     // special rules. Anything up to the first whitespace outside a quoted
2827     // subtring is accepted. Backslashes are treated as normal characters.
2828     argv[ (*pNumArgs)++ ] = pdst;
2829     inquote = FALSE;
2830     do {
2831         if (*psrc == W('"') )
2832         {
2833             inquote = !inquote;
2834             c = *psrc++;
2835             continue;
2836         }
2837         *pdst++ = *psrc;
2838
2839         c = *psrc++;
2840
2841     } while ( (c != W('\0') && (inquote || (c != W(' ') && c != W('\t')))) );
2842
2843     if ( c == W('\0') ) {
2844         psrc--;
2845     } else {
2846         *(pdst-1) = W('\0');
2847     }
2848
2849     inquote = FALSE;
2850
2851
2852
2853     /* loop on each argument */
2854     for(;;)
2855     {
2856         if ( *psrc )
2857         {
2858             while (*psrc == W(' ') || *psrc == W('\t'))
2859             {
2860                 ++psrc;
2861             }
2862         }
2863
2864         if (*psrc == W('\0'))
2865             break;              /* end of args */
2866
2867         /* scan an argument */
2868         argv[ (*pNumArgs)++ ] = pdst;
2869
2870         /* loop through scanning one argument */
2871         for (;;)
2872         {
2873             copychar = 1;
2874             /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
2875                2N+1 backslashes + " ==> N backslashes + literal "
2876                N backslashes ==> N backslashes */
2877             numslash = 0;
2878             while (*psrc == W('\\'))
2879             {
2880                 /* count number of backslashes for use below */
2881                 ++psrc;
2882                 ++numslash;
2883             }
2884             if (*psrc == W('"'))
2885             {
2886                 /* if 2N backslashes before, start/end quote, otherwise
2887                    copy literally */
2888                 if (numslash % 2 == 0)
2889                 {
2890                     if (inquote && psrc[1] == W('"'))
2891                     {
2892                         psrc++;    /* Double quote inside quoted string */
2893                     }
2894                     else
2895                     {
2896                         /* skip first quote char and copy second */
2897                         copychar = 0;       /* don't copy quote */
2898                         inquote = !inquote;
2899                     }
2900                 }
2901                 numslash /= 2;          /* divide numslash by two */
2902             }
2903     
2904             /* copy slashes */
2905             while (numslash--)
2906             {
2907                 *pdst++ = W('\\');
2908             }
2909     
2910             /* if at end of arg, break loop */
2911             if (*psrc == W('\0') || (!inquote && (*psrc == W(' ') || *psrc == W('\t'))))
2912                 break;
2913     
2914             /* copy character into argument */
2915             if (copychar)
2916             {
2917                 *pdst++ = *psrc;
2918             }
2919             ++psrc;
2920         }
2921
2922         /* null-terminate the argument */
2923
2924         *pdst++ = W('\0');          /* terminate string */
2925     }
2926
2927     /* We put one last argument in -- a null ptr */
2928     argv[ (*pNumArgs) ] = NULL;
2929
2930     // If we hit this assert, we overwrote our destination buffer.
2931     // Since we're supposed to allocate for the worst
2932     // case, either the parsing rules have changed or our worse case
2933     // formula is wrong.
2934     _ASSERTE((BYTE*)pdst <= (BYTE*)pAlloc + cbAlloc);
2935     return argv;
2936 }
2937
2938 Volatile<PVOID> ForbidCallsIntoHostOnThisThread::s_pvOwningFiber = NULL;
2939
2940 //======================================================================
2941 // This function returns true, if it can determine that the instruction pointer
2942 // refers to a code address that belongs in the range of the given image.
2943 // <TODO>@TODO: Merge with IsIPInModule from vm\util.hpp</TODO>
2944
2945 BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip)
2946 {
2947     STATIC_CONTRACT_LEAF;
2948     SUPPORTS_DAC;
2949
2950     struct Param
2951     {
2952         HMODULE_TGT hModule;
2953         PCODE ip;
2954         BOOL fRet;
2955     } param;
2956     param.hModule = hModule;
2957     param.ip = ip;
2958     param.fRet = FALSE;
2959
2960 // UNIXTODO: implement a proper version for PAL
2961 #ifndef FEATURE_PAL   
2962     PAL_TRY(Param *, pParam, &param)
2963     {
2964         PTR_BYTE pBase = dac_cast<PTR_BYTE>(pParam->hModule);
2965
2966         PTR_IMAGE_DOS_HEADER pDOS = NULL;
2967         PTR_IMAGE_NT_HEADERS pNT  = NULL;
2968         USHORT cbOptHdr;
2969         PCODE baseAddr;
2970         
2971         //
2972         // First, must validate the format of the PE headers to make sure that
2973         // the fields we're interested in using exist in the image.
2974         //
2975
2976         // Validate the DOS header.
2977         pDOS = PTR_IMAGE_DOS_HEADER(pBase);
2978         if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE) ||
2979             pDOS->e_lfanew == 0)
2980         {
2981             goto lDone;
2982         }
2983
2984         // Validate the NT header
2985         pNT = PTR_IMAGE_NT_HEADERS(pBase + VAL32(pDOS->e_lfanew));
2986
2987         if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
2988         {
2989             goto lDone;
2990         }
2991
2992         // Validate that the optional header is large enough to contain the fields
2993         // we're interested, namely IMAGE_OPTIONAL_HEADER::SizeOfImage. The reason
2994         // we don't just check that SizeOfOptionalHeader == IMAGE_SIZEOF_NT_OPTIONAL_HEADER
2995         // is due to VSW443590, which states that the extensibility of this structure
2996         // is such that it is possible to include only a portion of the optional header.
2997         cbOptHdr = pNT->FileHeader.SizeOfOptionalHeader;
2998
2999         // Check that the magic field is contained by the optional header and set to the correct value.
3000         if (cbOptHdr < (offsetof(IMAGE_OPTIONAL_HEADER, Magic) + sizeofmember(IMAGE_OPTIONAL_HEADER, Magic)) ||
3001             pNT->OptionalHeader.Magic != VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
3002         {
3003             goto lDone;
3004         }
3005
3006         // Check that the SizeOfImage is contained by the optional header.
3007         if (cbOptHdr < (offsetof(IMAGE_OPTIONAL_HEADER, SizeOfImage) + sizeofmember(IMAGE_OPTIONAL_HEADER, SizeOfImage)))
3008         {
3009             goto lDone;
3010         }
3011
3012         //
3013         // The real check
3014         //
3015
3016         baseAddr = dac_cast<PCODE>(pBase);
3017         if ((pParam->ip < baseAddr) || (pParam->ip >= (baseAddr + VAL32(pNT->OptionalHeader.SizeOfImage))))
3018         {
3019             goto lDone;
3020         }
3021
3022         pParam->fRet = TRUE;
3023
3024 lDone: ;
3025     }
3026     PAL_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
3027     {
3028     }
3029     PAL_ENDTRY
3030 #endif // !FEATURE_PAL    
3031
3032     return param.fRet;
3033 }
3034
3035 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
3036
3037 // To include definition of EXCEPTION_SOFTSO
3038 #include "corexcep.h"
3039
3040 // These functions provide limited support for corrupting exceptions
3041 // outside the VM folder. Its limited since we don't have access to the
3042 // throwable.
3043 //
3044 // These functions are also wrapped by the corresponding CEHelper 
3045 // methods in excep.cpp.
3046
3047 // Given an exception code, this method returns a BOOL to indicate if the
3048 // code belongs to a corrupting exception or not.
3049 BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*=TRUE*/)
3050 {
3051     LIMITED_METHOD_CONTRACT;
3052
3053     // By default, assume its not corrupting
3054     BOOL fIsCorruptedStateException = FALSE;
3055
3056     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 1)
3057     {
3058         return fIsCorruptedStateException;
3059     }
3060
3061     // If we have been asked not to include SO in the CSE check
3062     // and the code represent SO, then exit now.
3063     if ((fCheckForSO == FALSE) && (dwExceptionCode == STATUS_STACK_OVERFLOW))
3064     {
3065         return fIsCorruptedStateException;
3066     }
3067
3068     switch(dwExceptionCode)
3069     {
3070         case STATUS_ACCESS_VIOLATION:
3071         case STATUS_STACK_OVERFLOW:
3072         case EXCEPTION_ILLEGAL_INSTRUCTION:
3073         case EXCEPTION_IN_PAGE_ERROR:
3074         case EXCEPTION_INVALID_DISPOSITION:
3075         case EXCEPTION_NONCONTINUABLE_EXCEPTION:
3076         case EXCEPTION_PRIV_INSTRUCTION:
3077         case STATUS_UNWIND_CONSOLIDATE:
3078             fIsCorruptedStateException = TRUE;
3079             break;
3080     }
3081
3082     return fIsCorruptedStateException;
3083 }
3084
3085 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3086
3087 void EnableTerminationOnHeapCorruption()
3088 {
3089     HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
3090 }
3091
3092 namespace Clr
3093 {
3094 namespace Util
3095 {
3096     static BOOL g_fLocalAppDataDirectoryInitted = FALSE;
3097     static WCHAR *g_wszLocalAppDataDirectory = NULL;
3098
3099 // This api returns a pointer to a null-terminated string that contains the local appdata directory
3100 // or it returns NULL in the case that the directory could not be found. The return value from this function
3101 // is not actually checked for existence. 
3102     HRESULT GetLocalAppDataDirectory(LPCWSTR *ppwzLocalAppDataDirectory)
3103     {
3104         CONTRACTL {
3105             NOTHROW;
3106             GC_NOTRIGGER;
3107         } CONTRACTL_END;
3108
3109         HRESULT hr = S_OK;
3110         *ppwzLocalAppDataDirectory = NULL;
3111
3112         EX_TRY
3113         {
3114             if (!g_fLocalAppDataDirectoryInitted)
3115             {
3116                 WCHAR *wszLocalAppData = NULL;
3117
3118                 DWORD cCharsNeeded;
3119                 cCharsNeeded = GetEnvironmentVariableW(W("LOCALAPPDATA"), NULL, 0);
3120
3121                 if ((cCharsNeeded != 0) && (cCharsNeeded < MAX_LONGPATH))
3122                 {
3123                     wszLocalAppData = new WCHAR[cCharsNeeded];
3124                     cCharsNeeded = GetEnvironmentVariableW(W("LOCALAPPDATA"), wszLocalAppData, cCharsNeeded);
3125                     if (cCharsNeeded != 0)
3126                     {
3127                         // We've collected the appropriate app data directory into a local. Now publish it.
3128                         if (InterlockedCompareExchangeT(&g_wszLocalAppDataDirectory, wszLocalAppData, NULL) == NULL)
3129                         {
3130                             // This variable doesn't need to be freed, as it has been stored in the global
3131                             wszLocalAppData = NULL;
3132                         }
3133                     }
3134                 }
3135
3136                 g_fLocalAppDataDirectoryInitted = TRUE;
3137                 delete[] wszLocalAppData;
3138             }
3139         }
3140         EX_CATCH_HRESULT(hr);
3141
3142         if (SUCCEEDED(hr))
3143             *ppwzLocalAppDataDirectory = g_wszLocalAppDataDirectory;
3144
3145         return hr;
3146     }
3147
3148     HRESULT SetLocalAppDataDirectory(LPCWSTR pwzLocalAppDataDirectory)
3149     {
3150         CONTRACTL {
3151             NOTHROW;
3152             GC_NOTRIGGER;
3153         } CONTRACTL_END;
3154
3155         if (pwzLocalAppDataDirectory == NULL || *pwzLocalAppDataDirectory == W('\0'))
3156             return E_INVALIDARG;
3157
3158         if (g_fLocalAppDataDirectoryInitted)
3159             return E_UNEXPECTED;
3160
3161         HRESULT hr = S_OK;
3162
3163         EX_TRY
3164         {
3165             size_t size = wcslen(pwzLocalAppDataDirectory) + 1;
3166             WCHAR *wszLocalAppData = new WCHAR[size];
3167             wcscpy_s(wszLocalAppData, size, pwzLocalAppDataDirectory);
3168
3169             // We've collected the appropriate app data directory into a local. Now publish it.
3170             if (InterlockedCompareExchangeT(&g_wszLocalAppDataDirectory, wszLocalAppData, NULL) != NULL)
3171             {
3172                 // Someone else already set LocalAppData. Free our copy and return an error.
3173                 delete[] wszLocalAppData;
3174                 hr = E_UNEXPECTED;
3175             }
3176
3177             g_fLocalAppDataDirectoryInitted = TRUE;
3178         }
3179         EX_CATCH_HRESULT(hr);
3180
3181         return hr;
3182     }
3183
3184 #ifndef FEATURE_PAL
3185     // Struct used to scope suspension of client impersonation for the current thread.
3186     // https://docs.microsoft.com/en-us/windows/desktop/secauthz/client-impersonation
3187     class SuspendImpersonation
3188     {
3189     public:
3190         SuspendImpersonation()
3191             : _token(nullptr)
3192         {
3193             // The approach used here matches what is used elsewhere in CLR (RevertIfImpersonated).
3194             // In general, OpenThreadToken fails with ERROR_NO_TOKEN if impersonation is not active,
3195             // fails with ERROR_CANT_OPEN_ANONYMOUS if anonymous impersonation is active, and otherwise
3196             // succeeds and returns the active impersonation token.
3197             BOOL res = ::OpenThreadToken(::GetCurrentThread(), TOKEN_IMPERSONATE, /* OpenAsSelf */ TRUE, &_token);
3198             if (res != FALSE)
3199             {
3200                 ::RevertToSelf();
3201             }
3202             else
3203             {
3204                 _token = nullptr;
3205             }
3206         }
3207
3208         ~SuspendImpersonation()
3209         {
3210             if (_token != nullptr)
3211                 ::SetThreadToken(nullptr, _token);
3212         }
3213
3214     private:
3215         HandleHolder _token;
3216     };
3217
3218     struct ProcessIntegrityResult
3219     {
3220         BOOL Success;
3221         DWORD Integrity;
3222         HRESULT LastError;
3223
3224         HRESULT RecordAndReturnError(HRESULT hr)
3225         {
3226             LastError = hr;
3227             return hr;
3228         }
3229     };
3230
3231     // The system calls in this code can fail if run with reduced privileges.
3232     // It is the caller's responsibility to choose an appropriate default in the event
3233     // that this function fails to retrieve the current process integrity.
3234     HRESULT GetCurrentProcessIntegrity(DWORD *integrity)
3235     {
3236         static ProcessIntegrityResult s_Result = { FALSE, 0, S_FALSE };
3237
3238         if (FALSE != InterlockedCompareExchangeT(&s_Result.Success, FALSE, FALSE))
3239         {
3240             *integrity = s_Result.Integrity;
3241             return S_OK;
3242         }
3243
3244         // Temporarily suspend impersonation (if possible) while computing the integrity level.
3245         // If impersonation is active, the OpenProcessToken call below will check the impersonation
3246         // token against the process token ACL, and will generally fail with ERROR_ACCESS_DENIED if
3247         // the impersonation token is less privileged than this process's primary token.
3248         Clr::Util::SuspendImpersonation si;
3249
3250         HandleHolder hToken;
3251         if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
3252             return s_Result.RecordAndReturnError(HRESULT_FROM_GetLastError());
3253
3254         DWORD dwSize = 0;
3255         DWORD err = ERROR_SUCCESS;
3256         if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, nullptr, 0, &dwSize))
3257             err = GetLastError();
3258
3259         // We need to make sure that GetTokenInformation failed in a predictable manner so we know that
3260         // dwSize has the correct buffer size in it.
3261         if (err != ERROR_INSUFFICIENT_BUFFER || dwSize == 0)
3262             return s_Result.RecordAndReturnError((err == ERROR_SUCCESS) ? E_FAIL : HRESULT_FROM_WIN32(err));
3263
3264         NewArrayHolder<BYTE> pLabel = new (nothrow) BYTE[dwSize];
3265         if (pLabel == NULL)
3266             return s_Result.RecordAndReturnError(E_OUTOFMEMORY);
3267
3268         if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, pLabel, dwSize, &dwSize))
3269             return s_Result.RecordAndReturnError(HRESULT_FROM_GetLastError());
3270
3271         TOKEN_MANDATORY_LABEL *ptml = (TOKEN_MANDATORY_LABEL *)(void*)pLabel;
3272         PSID psidIntegrityLevelLabel = ptml->Label.Sid;
3273
3274         s_Result.Integrity = *GetSidSubAuthority(psidIntegrityLevelLabel, (*GetSidSubAuthorityCount(psidIntegrityLevelLabel) - 1));
3275         *integrity = s_Result.Integrity;
3276         InterlockedExchangeT(&s_Result.Success, TRUE);
3277         return S_OK;
3278     }
3279
3280 namespace Reg
3281 {
3282     HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKeyName, LPCWSTR wszValueName, SString & ssValue)
3283     {
3284         STANDARD_VM_CONTRACT;
3285
3286         if (hKey == NULL)
3287         {
3288             return E_INVALIDARG;
3289         }
3290
3291         RegKeyHolder hTargetKey;
3292         if (wszSubKeyName == NULL || *wszSubKeyName == W('\0'))
3293         {   // No subkey was requested, use hKey as the resolved key.
3294             hTargetKey = hKey;
3295             hTargetKey.SuppressRelease();
3296         }
3297         else
3298         {   // Try to open the specified subkey.
3299             if (WszRegOpenKeyEx(hKey, wszSubKeyName, 0, KEY_READ, &hTargetKey) != ERROR_SUCCESS)
3300                 return REGDB_E_CLASSNOTREG;
3301         }
3302
3303         DWORD type;
3304         DWORD size;
3305         if ((WszRegQueryValueEx(hTargetKey, wszValueName, 0, &type, 0, &size) == ERROR_SUCCESS) &&
3306             type == REG_SZ && size > 0)
3307         {
3308             LPWSTR wszValueBuf = ssValue.OpenUnicodeBuffer(static_cast<COUNT_T>((size / sizeof(WCHAR)) - 1));
3309             LONG lResult = WszRegQueryValueEx(
3310                 hTargetKey,
3311                 wszValueName,
3312                 0,
3313                 0,
3314                 reinterpret_cast<LPBYTE>(wszValueBuf),
3315                 &size);
3316
3317             _ASSERTE(lResult == ERROR_SUCCESS);
3318             if (lResult == ERROR_SUCCESS)
3319             {
3320                 // Can't count on the returned size being accurate - I've seen at least
3321                 // one string with an extra NULL at the end that will cause the resulting
3322                 // SString to count the extra NULL as part of the string. An extra
3323                 // terminating NULL is not a legitimate scenario for REG_SZ - this must
3324                 // be done using REG_MULTI_SZ - however this was tolerated in the
3325                 // past and so it would be a breaking change to stop doing so.
3326                 _ASSERTE(wcslen(wszValueBuf) <= (size / sizeof(WCHAR)) - 1);
3327                 ssValue.CloseBuffer((COUNT_T)wcsnlen(wszValueBuf, (size_t)size));
3328             }
3329             else
3330             {
3331                 ssValue.CloseBuffer(0);
3332                 return HRESULT_FROM_WIN32(lResult);
3333             }
3334
3335             return S_OK;
3336         }
3337         else
3338         {
3339             return REGDB_E_KEYMISSING;
3340         }
3341     }
3342
3343     HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, __deref_out __deref_out_z LPWSTR* pwszValue)
3344     {
3345         CONTRACTL {
3346             NOTHROW;
3347             GC_NOTRIGGER;
3348         } CONTRACTL_END;
3349
3350         HRESULT hr = S_OK;
3351         EX_TRY
3352         {
3353             StackSString ssValue;
3354             if (SUCCEEDED(hr = ReadStringValue(hKey, wszSubKey, wszName, ssValue)))
3355             {
3356                 *pwszValue = new WCHAR[ssValue.GetCount() + 1];
3357                 wcscpy_s(*pwszValue, ssValue.GetCount() + 1, ssValue.GetUnicode());
3358             }
3359         }
3360         EX_CATCH_HRESULT(hr);
3361         return hr;
3362     }
3363 } // namespace Reg
3364
3365 namespace Com
3366 {
3367     namespace __imp
3368     {
3369         __success(return == S_OK)
3370         static
3371         HRESULT FindSubKeyDefaultValueForCLSID(REFCLSID rclsid, LPCWSTR wszSubKeyName, SString & ssValue)
3372         {
3373             STANDARD_VM_CONTRACT;
3374
3375             WCHAR wszClsid[39];
3376             if (GuidToLPWSTR(rclsid, wszClsid, NumItems(wszClsid)) == 0)
3377                 return E_UNEXPECTED;
3378
3379             StackSString ssKeyName;
3380             ssKeyName.Append(SL(W("CLSID\\")));
3381             ssKeyName.Append(wszClsid);
3382             ssKeyName.Append(SL(W("\\")));
3383             ssKeyName.Append(wszSubKeyName);
3384
3385             // Query HKCR first to retain backwards compat with previous implementation where HKCR was only queried.
3386             // This is being done due to registry caching. This value will be used if the process integrity is medium or less.
3387             HRESULT hkcrResult = Clr::Util::Reg::ReadStringValue(HKEY_CLASSES_ROOT, ssKeyName.GetUnicode(), nullptr, ssValue);
3388
3389             // HKCR is a virtualized registry hive that weaves together HKCU\Software\Classes and HKLM\Software\Classes
3390             // Processes with high integrity or greater should only read from HKLM to avoid being hijacked by medium
3391             // integrity processes writing to HKCU.
3392             DWORD integrity = SECURITY_MANDATORY_PROTECTED_PROCESS_RID;
3393             HRESULT hr = Clr::Util::GetCurrentProcessIntegrity(&integrity);
3394             if (hr != S_OK)
3395             {
3396                 // In the event that we are unable to get the current process integrity,
3397                 // we assume that this process is running in an elevated state.
3398                 // GetCurrentProcessIntegrity may fail if the process has insufficient rights to get the integrity level
3399                 integrity = SECURITY_MANDATORY_PROTECTED_PROCESS_RID;
3400             }
3401
3402             if (integrity > SECURITY_MANDATORY_MEDIUM_RID)
3403             {
3404                 Clr::Util::SuspendImpersonation si;
3405
3406                 // Clear the previous HKCR queried value
3407                 ssValue.Clear();
3408
3409                 // Force to use HKLM
3410                 StackSString ssHklmKeyName(SL(W("SOFTWARE\\Classes\\")));
3411                 ssHklmKeyName.Append(ssKeyName);
3412                 return Clr::Util::Reg::ReadStringValue(HKEY_LOCAL_MACHINE, ssHklmKeyName.GetUnicode(), nullptr, ssValue);
3413             }
3414
3415             return hkcrResult;
3416         }
3417     }
3418
3419     HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, SString & ssInprocServer32Name)
3420     {
3421         WRAPPER_NO_CONTRACT;
3422         return __imp::FindSubKeyDefaultValueForCLSID(rclsid, W("InprocServer32"), ssInprocServer32Name);
3423     }
3424 } // namespace Com
3425 #endif //  FEATURE_PAL
3426
3427 namespace Win32
3428 {
3429     void GetModuleFileName(
3430         HMODULE hModule,
3431         SString & ssFileName,
3432         bool fAllowLongFileNames)
3433     {
3434         STANDARD_VM_CONTRACT;
3435
3436         // Try to use what the SString already has allocated. If it does not have anything allocated
3437         // or it has < 20 characters allocated, then bump the size requested to _MAX_PATH.
3438         
3439         DWORD dwResult = WszGetModuleFileName(hModule, ssFileName);
3440
3441
3442         if (dwResult == 0)
3443             ThrowHR(HRESULT_FROM_GetLastError());
3444
3445         _ASSERTE(dwResult != 0 );
3446     }
3447
3448     // Returns heap-allocated string in *pwszFileName
3449     HRESULT GetModuleFileName(
3450         HMODULE hModule,
3451         __deref_out_z LPWSTR * pwszFileName,
3452         bool fAllowLongFileNames)
3453     {
3454         CONTRACTL {
3455             NOTHROW;
3456             GC_NOTRIGGER;
3457             PRECONDITION(CheckPointer(pwszFileName));
3458         } CONTRACTL_END;
3459
3460         HRESULT hr = S_OK;
3461         EX_TRY
3462         {
3463             InlineSString<_MAX_PATH> ssFileName;
3464             GetModuleFileName(hModule, ssFileName);
3465             *pwszFileName = DuplicateStringThrowing(ssFileName.GetUnicode());
3466         }
3467         EX_CATCH_HRESULT(hr);
3468
3469         return hr;
3470     }
3471
3472     void GetFullPathName(
3473         SString const & ssFileName,
3474         SString & ssPathName,
3475         DWORD * pdwFilePartIdx,
3476         bool fAllowLongFileNames)
3477     {
3478         STANDARD_VM_CONTRACT;
3479
3480         // Get the required buffer length (including terminating NULL).
3481         DWORD dwLengthRequired = WszGetFullPathName(ssFileName.GetUnicode(), 0, NULL, NULL);
3482
3483         if (dwLengthRequired == 0)
3484             ThrowHR(HRESULT_FROM_GetLastError());
3485
3486         LPWSTR wszPathName = ssPathName.OpenUnicodeBuffer(dwLengthRequired - 1);
3487         LPWSTR wszFileName = NULL;
3488         DWORD dwLengthWritten = WszGetFullPathName(
3489             ssFileName.GetUnicode(),
3490             dwLengthRequired,
3491             wszPathName,
3492             &wszFileName);
3493
3494         // Calculate the index while the buffer is open and the string pointer is stable.
3495         if (dwLengthWritten != 0 && dwLengthWritten < dwLengthRequired && pdwFilePartIdx != NULL)
3496             *pdwFilePartIdx = static_cast<DWORD>(wszFileName - wszPathName);
3497
3498         ssPathName.CloseBuffer(dwLengthWritten < dwLengthRequired ? dwLengthWritten : 0);
3499
3500         if (dwLengthRequired == 0)
3501             ThrowHR(HRESULT_FROM_GetLastError());
3502
3503         // Overly defensive? Perhaps.
3504         if (!(dwLengthWritten < dwLengthRequired))
3505             ThrowHR(E_UNEXPECTED);
3506     }
3507 } // namespace Win32
3508
3509 } // namespace Util
3510 } // namespace Clr