Modify affinity range config format for Windows
[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 /*static*/ BOOL NumaNodeInfo::GetNumaProcessorNodeEx(PPROCESSOR_NUMBER proc_no, PUSHORT node_no)
737 {
738     return ::GetNumaProcessorNodeEx(proc_no, node_no);
739 }
740 #endif
741
742 /*static*/ BOOL NumaNodeInfo::m_enableGCNumaAware = FALSE;
743 /*static*/ BOOL NumaNodeInfo::InitNumaNodeInfoAPI()
744 {
745 #if !defined(FEATURE_REDHAWK)
746     //check for numa support if multiple heaps are used
747     ULONG highest = 0;
748     
749     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCNumaAware) == 0)
750         return FALSE;
751
752 #ifndef FEATURE_PAL
753     // check if required APIs are supported
754     HMODULE hMod = GetModuleHandleW(WINDOWS_KERNEL32_DLLNAME_W);
755 #else
756     HMODULE hMod = GetCLRModule();
757 #endif    
758     if (hMod == NULL)
759         return FALSE;
760
761     // fail to get the highest numa node number
762     if (!::GetNumaHighestNodeNumber(&highest) || (highest == 0))
763         return FALSE;
764
765     return TRUE;
766 #else
767     return FALSE;
768 #endif
769 }
770
771 /*static*/ BOOL NumaNodeInfo::CanEnableGCNumaAware()
772 {
773     return m_enableGCNumaAware;
774 }
775
776 /*static*/ void NumaNodeInfo::InitNumaNodeInfo()
777 {
778     m_enableGCNumaAware = InitNumaNodeInfoAPI();
779 }
780
781 //******************************************************************************
782 // NumaNodeInfo 
783 //******************************************************************************
784 #if !defined(FEATURE_REDHAWK)
785 /*static*/ //CPUGroupInfo::PNTQSIEx CPUGroupInfo::m_pNtQuerySystemInformationEx = NULL;
786
787 /*static*/ BOOL CPUGroupInfo::GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP relationship,
788                          SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *slpiex, PDWORD count)
789 {
790     LIMITED_METHOD_CONTRACT;
791     return ::GetLogicalProcessorInformationEx(relationship, slpiex, count);
792 }
793
794 /*static*/ BOOL CPUGroupInfo::SetThreadGroupAffinity(HANDLE h, 
795                         GROUP_AFFINITY *groupAffinity, GROUP_AFFINITY *previousGroupAffinity)
796 {
797     LIMITED_METHOD_CONTRACT;
798     return ::SetThreadGroupAffinity(h, groupAffinity, previousGroupAffinity);
799 }
800
801 /*static*/ BOOL CPUGroupInfo::GetThreadGroupAffinity(HANDLE h, GROUP_AFFINITY *groupAffinity)
802 {
803     LIMITED_METHOD_CONTRACT;
804     return ::GetThreadGroupAffinity(h, groupAffinity);
805 }
806
807 /*static*/ BOOL CPUGroupInfo::GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime)
808 {
809     LIMITED_METHOD_CONTRACT;
810
811 #ifndef FEATURE_PAL    
812     return ::GetSystemTimes(idleTime, kernelTime, userTime);
813 #else
814     return FALSE;
815 #endif
816 }
817 #endif
818
819 /*static*/ BOOL CPUGroupInfo::m_enableGCCPUGroups = FALSE;
820 /*static*/ BOOL CPUGroupInfo::m_threadUseAllCpuGroups = FALSE;
821 /*static*/ WORD CPUGroupInfo::m_nGroups = 0;
822 /*static*/ WORD CPUGroupInfo::m_nProcessors = 0;
823 /*static*/ WORD CPUGroupInfo::m_initialGroup = 0;
824 /*static*/ CPU_Group_Info *CPUGroupInfo::m_CPUGroupInfoArray = NULL;
825 /*static*/ LONG CPUGroupInfo::m_initialization = 0;
826 /*static*/ bool CPUGroupInfo::s_hadSingleProcessorAtStartup = false;
827
828 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
829 // Calculate greatest common divisor
830 DWORD GCD(DWORD u, DWORD v)
831 {
832     while (v != 0)
833     {
834         DWORD dwTemp = v;
835         v = u % v;
836         u = dwTemp;
837     }
838
839     return u;
840 }
841
842 // Calculate least common multiple
843 DWORD LCM(DWORD u, DWORD v)
844 {
845     return u / GCD(u, v) * v;
846 }
847 #endif
848
849 /*static*/ BOOL CPUGroupInfo::InitCPUGroupInfoArray()
850 {
851     CONTRACTL
852     {
853         NOTHROW;
854         GC_NOTRIGGER;
855     }
856     CONTRACTL_END;
857
858 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
859     BYTE *bBuffer = NULL;
860     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pSLPIEx = NULL;
861     SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *pRecord = NULL;
862     DWORD cbSLPIEx = 0;
863     DWORD byteOffset = 0;
864     DWORD dwNumElements = 0;
865     DWORD dwWeight = 1;
866
867     if (CPUGroupInfo::GetLogicalProcessorInformationEx(RelationGroup, pSLPIEx, &cbSLPIEx) &&
868                       GetLastError() != ERROR_INSUFFICIENT_BUFFER)
869         return FALSE;
870
871     _ASSERTE(cbSLPIEx);
872
873     // Fail to allocate buffer
874     bBuffer = new (nothrow) BYTE[ cbSLPIEx ];
875     if (bBuffer == NULL)
876         return FALSE;
877
878     pSLPIEx = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)bBuffer;
879     if (!::GetLogicalProcessorInformationEx(RelationGroup, pSLPIEx, &cbSLPIEx))
880     {
881         delete[] bBuffer;
882         return FALSE;
883     }
884
885     pRecord = pSLPIEx;
886     while (byteOffset < cbSLPIEx)
887     {
888         if (pRecord->Relationship == RelationGroup)
889         {
890             m_nGroups = pRecord->Group.ActiveGroupCount;
891             break;
892         }
893         byteOffset += pRecord->Size;
894         pRecord = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *)(bBuffer + byteOffset);
895     }
896
897     m_CPUGroupInfoArray = new (nothrow) CPU_Group_Info[m_nGroups];
898     if (m_CPUGroupInfoArray == NULL) 
899     {
900         delete[] bBuffer;
901         return FALSE;
902     }
903
904     for (DWORD i = 0; i < m_nGroups; i++)
905     {
906         m_CPUGroupInfoArray[i].nr_active   = (WORD)pRecord->Group.GroupInfo[i].ActiveProcessorCount;
907         m_CPUGroupInfoArray[i].active_mask = pRecord->Group.GroupInfo[i].ActiveProcessorMask;
908         m_nProcessors += m_CPUGroupInfoArray[i].nr_active;
909         dwWeight = LCM(dwWeight, (DWORD)m_CPUGroupInfoArray[i].nr_active);
910     }
911
912     // The number of threads per group that can be supported will depend on the number of CPU groups
913     // and the number of LPs within each processor group. For example, when the number of LPs in
914     // CPU groups is the same and is 64, the number of threads per group before weight overflow
915     // would be 2^32/2^6 = 2^26 (64M threads)
916     for (DWORD i = 0; i < m_nGroups; i++)
917     {
918         m_CPUGroupInfoArray[i].groupWeight = dwWeight / (DWORD)m_CPUGroupInfoArray[i].nr_active;
919         m_CPUGroupInfoArray[i].activeThreadWeight = 0;
920     }
921
922     delete[] bBuffer;  // done with it; free it
923     return TRUE;
924 #else
925     return FALSE;
926 #endif
927 }
928
929 /*static*/ BOOL CPUGroupInfo::InitCPUGroupInfoRange()
930 {
931     LIMITED_METHOD_CONTRACT;
932
933 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
934     WORD begin   = 0;
935     WORD nr_proc = 0;
936
937     for (WORD i = 0; i < m_nGroups; i++) 
938     {
939         nr_proc += m_CPUGroupInfoArray[i].nr_active;
940         m_CPUGroupInfoArray[i].begin = begin;
941         m_CPUGroupInfoArray[i].end   = nr_proc - 1;
942         begin = nr_proc;
943     }
944     return TRUE;
945 #else
946     return FALSE;
947 #endif
948 }
949
950 /*static*/ void CPUGroupInfo::InitCPUGroupInfo()
951 {
952     CONTRACTL
953     {
954         NOTHROW;
955         GC_NOTRIGGER;
956     }
957     CONTRACTL_END;
958
959 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
960     BOOL enableGCCPUGroups     = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_GCCpuGroup) != 0;
961     BOOL threadUseAllCpuGroups = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_Thread_UseAllCpuGroups) != 0;
962
963     if (!enableGCCPUGroups)
964         return;
965
966     if (!InitCPUGroupInfoArray())
967         return;
968
969     if (!InitCPUGroupInfoRange())
970         return;
971
972     // initalGroup is whatever the CPU group that the main thread is running on
973     GROUP_AFFINITY groupAffinity;
974     CPUGroupInfo::GetThreadGroupAffinity(GetCurrentThread(), &groupAffinity);
975     m_initialGroup = groupAffinity.Group;  
976
977         // only enable CPU groups if more than one group exists
978         BOOL hasMultipleGroups = m_nGroups > 1;
979         m_enableGCCPUGroups = enableGCCPUGroups && hasMultipleGroups;
980         m_threadUseAllCpuGroups = threadUseAllCpuGroups && hasMultipleGroups;
981 #endif // _TARGET_AMD64_ || _TARGET_ARM64_
982
983     // Determine if the process is affinitized to a single processor (or if the system has a single processor)
984     DWORD_PTR processAffinityMask, systemAffinityMask;
985     if (GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask))
986     {
987         processAffinityMask &= systemAffinityMask;
988         if (processAffinityMask != 0 && // only one CPU group is involved
989             (processAffinityMask & (processAffinityMask - 1)) == 0) // only one bit is set
990         {
991             s_hadSingleProcessorAtStartup = true;
992         }
993     }
994 }
995
996 /*static*/ BOOL CPUGroupInfo::IsInitialized()
997 {
998     LIMITED_METHOD_CONTRACT;
999     return (m_initialization == -1);
1000 }
1001
1002 /*static*/ void CPUGroupInfo::EnsureInitialized()
1003 {
1004     CONTRACTL
1005     {
1006         NOTHROW;
1007         GC_NOTRIGGER;
1008     }
1009     CONTRACTL_END;
1010
1011     // CPUGroupInfo needs to be initialized only once. This could happen in three cases 
1012     // 1. CLR initialization at begining of EEStartup, or
1013     // 2. Sometimes, when hosted by ASP.NET, the hosting process may initialize ThreadPool
1014     //    before initializing CLR, thus require CPUGroupInfo to be initialized to determine
1015     //    if CPU group support should/could be enabled.
1016     // 3. Call into Threadpool functions before Threadpool _and_ CLR is initialized.
1017     // Vast majority of time, CPUGroupInfo is initialized in case 1. or 2. 
1018     // The chance of contention will be extremely small, so the following code should be fine
1019     //
1020 retry:
1021     if (IsInitialized())
1022         return;
1023
1024     if (InterlockedCompareExchange(&m_initialization, 1, 0) == 0)
1025     {
1026         InitCPUGroupInfo();
1027         m_initialization = -1;
1028     }
1029     else //some other thread started initialization, just wait until complete;
1030     {
1031         while (m_initialization != -1)
1032         {
1033             SwitchToThread();
1034         }
1035         goto retry;
1036     }
1037 }
1038
1039 /*static*/ WORD CPUGroupInfo::GetNumActiveProcessors()
1040 {
1041     LIMITED_METHOD_CONTRACT;
1042     return (WORD)m_nProcessors;
1043 }
1044
1045 /*static*/ void CPUGroupInfo::GetGroupForProcessor(WORD processor_number,
1046                                          WORD* group_number, WORD* group_processor_number)
1047 {
1048     LIMITED_METHOD_CONTRACT;
1049
1050 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1051     WORD bTemp = 0;
1052     WORD bDiff = processor_number - bTemp;
1053
1054     for (WORD i=0; i < m_nGroups; i++)
1055     {
1056         bTemp += m_CPUGroupInfoArray[i].nr_active;
1057         if (bTemp > processor_number)
1058         {
1059             *group_number = i;
1060             *group_processor_number = bDiff;
1061             break;
1062         }
1063         bDiff = processor_number - bTemp;
1064     }
1065 #else
1066     *group_number = 0;
1067     *group_processor_number = 0;
1068 #endif
1069 }
1070
1071 /*static*/ DWORD CPUGroupInfo::CalculateCurrentProcessorNumber()
1072 {
1073     CONTRACTL
1074     {
1075         NOTHROW;
1076         GC_NOTRIGGER;
1077     }
1078     CONTRACTL_END;
1079
1080 #if !defined(FEATURE_REDHAWK) && (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1081     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1082     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1083
1084     PROCESSOR_NUMBER proc_no;
1085     proc_no.Group=0;
1086     proc_no.Number=0;
1087     proc_no.Reserved=0;
1088     ::GetCurrentProcessorNumberEx(&proc_no);
1089
1090     DWORD fullNumber = 0;
1091     for (WORD i = 0; i < proc_no.Group; i++)
1092         fullNumber += (DWORD)m_CPUGroupInfoArray[i].nr_active;
1093     fullNumber += (DWORD)(proc_no.Number);
1094
1095     return fullNumber;
1096 #else
1097     return 0;
1098 #endif
1099 }
1100
1101 #if !defined(FEATURE_REDHAWK)
1102 //Lock ThreadStore before calling this function, so that updates of weights/counts are consistent
1103 /*static*/ void CPUGroupInfo::ChooseCPUGroupAffinity(GROUP_AFFINITY *gf)
1104 {
1105     CONTRACTL
1106     {
1107         NOTHROW;
1108         GC_NOTRIGGER;
1109     }
1110     CONTRACTL_END;
1111
1112 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1113     WORD i, minGroup = 0;
1114     DWORD minWeight = 0;
1115
1116     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1117     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1118
1119     for (i = 0; i < m_nGroups; i++) 
1120     {
1121         minGroup = (m_initialGroup + i) % m_nGroups;    
1122
1123         // the group is not filled up, use it
1124         if (m_CPUGroupInfoArray[minGroup].activeThreadWeight / m_CPUGroupInfoArray[minGroup].groupWeight
1125                           < (DWORD)m_CPUGroupInfoArray[minGroup].nr_active)
1126             goto found;
1127     }
1128
1129     // all groups filled up, distribute proportionally
1130     minGroup = m_initialGroup;
1131     minWeight = m_CPUGroupInfoArray[m_initialGroup].activeThreadWeight; 
1132     for (i = 0; i < m_nGroups; i++) 
1133     {
1134         if (m_CPUGroupInfoArray[i].activeThreadWeight < minWeight)
1135         {
1136             minGroup = i;
1137             minWeight = m_CPUGroupInfoArray[i].activeThreadWeight;
1138         }
1139     }
1140
1141 found:
1142     gf->Group = minGroup;
1143     gf->Mask = m_CPUGroupInfoArray[minGroup].active_mask;
1144     gf->Reserved[0] = 0;
1145     gf->Reserved[1] = 0;
1146     gf->Reserved[2] = 0;
1147     m_CPUGroupInfoArray[minGroup].activeThreadWeight += m_CPUGroupInfoArray[minGroup].groupWeight;
1148 #endif
1149 }
1150
1151 //Lock ThreadStore before calling this function, so that updates of weights/counts are consistent
1152 /*static*/ void CPUGroupInfo::ClearCPUGroupAffinity(GROUP_AFFINITY *gf)
1153 {
1154     LIMITED_METHOD_CONTRACT;
1155 #if (defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_))
1156     // m_enableGCCPUGroups and m_threadUseAllCpuGroups must be TRUE
1157     _ASSERTE(m_enableGCCPUGroups && m_threadUseAllCpuGroups);
1158
1159     WORD group = gf->Group;
1160     m_CPUGroupInfoArray[group].activeThreadWeight -= m_CPUGroupInfoArray[group].groupWeight;
1161 #endif
1162 }
1163
1164 BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* group_size)
1165 {
1166     if (group_number >= m_nGroups)
1167     {
1168         return FALSE;
1169     }
1170
1171     *group_begin = m_CPUGroupInfoArray[group_number].begin;
1172     *group_size = m_CPUGroupInfoArray[group_number].nr_active;
1173
1174     return TRUE;
1175 }
1176
1177 #endif
1178
1179 /*static*/ BOOL CPUGroupInfo::CanEnableGCCPUGroups()
1180 {
1181     LIMITED_METHOD_CONTRACT;
1182     return m_enableGCCPUGroups;
1183 }
1184
1185 /*static*/ BOOL CPUGroupInfo::CanEnableThreadUseAllCpuGroups()
1186 {
1187     LIMITED_METHOD_CONTRACT;
1188     return m_threadUseAllCpuGroups;
1189 }
1190
1191 //******************************************************************************
1192 // Returns the number of processors that a process has been configured to run on
1193 //******************************************************************************
1194 int GetCurrentProcessCpuCount()
1195 {
1196     CONTRACTL
1197     {
1198         NOTHROW;
1199         CANNOT_TAKE_LOCK;
1200     }
1201     CONTRACTL_END;
1202     
1203     static int cCPUs = 0;
1204
1205     if (cCPUs != 0)
1206         return cCPUs;
1207
1208     unsigned int count = 0;
1209     DWORD_PTR pmask, smask;
1210
1211     if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
1212     {
1213         count = 1;
1214     }
1215     else
1216     {
1217         pmask &= smask;
1218
1219         while (pmask)
1220         {
1221             pmask &= (pmask - 1);
1222             count++;
1223         }
1224
1225         // GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
1226         // than 64 processors, which would leave us with a count of 0.  Since the GC
1227         // expects there to be at least one processor to run on (and thus at least one
1228         // heap), we'll return 64 here if count is 0, since there are likely a ton of
1229         // processors available in that case.  The GC also cannot (currently) handle
1230         // the case where there are more than 64 processors, so we will return a
1231         // maximum of 64 here.
1232         if (count == 0 || count > 64)
1233             count = 64;
1234     }
1235
1236 #ifdef FEATURE_PAL
1237     uint32_t cpuLimit;
1238
1239     if (PAL_GetCpuLimit(&cpuLimit) && cpuLimit < count)
1240         count = cpuLimit;
1241 #endif
1242
1243     cCPUs = count;
1244
1245     return count;
1246 }
1247
1248 DWORD_PTR GetCurrentProcessCpuMask()
1249 {
1250     CONTRACTL
1251     {
1252         NOTHROW;
1253         CANNOT_TAKE_LOCK;
1254     }
1255     CONTRACTL_END;
1256
1257 #ifndef FEATURE_PAL
1258     DWORD_PTR pmask, smask;
1259
1260     if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
1261         return 1;
1262
1263     pmask &= smask;
1264     return pmask;
1265 #else
1266     return 0;
1267 #endif
1268 }
1269
1270 uint32_t GetOsPageSizeUncached()
1271 {
1272     SYSTEM_INFO sysInfo;
1273     ::GetSystemInfo(&sysInfo);
1274     return sysInfo.dwAllocationGranularity ? sysInfo.dwAllocationGranularity : 0x1000;
1275 }
1276
1277 namespace
1278 {
1279     Volatile<uint32_t> g_pageSize = 0;
1280 }
1281
1282 uint32_t GetOsPageSize()
1283 {
1284 #ifdef FEATURE_PAL
1285     size_t result = g_pageSize.LoadWithoutBarrier();
1286
1287     if(!result)
1288     {
1289         result = GetOsPageSizeUncached();
1290
1291         g_pageSize.StoreWithoutBarrier(result);
1292     }
1293
1294     return result;
1295 #else
1296     return 0x1000;
1297 #endif
1298 }
1299
1300 /**************************************************************************/
1301
1302 /**************************************************************************/
1303 void ConfigMethodSet::init(const CLRConfig::ConfigStringInfo & info)
1304 {
1305     CONTRACTL
1306     {
1307         THROWS;
1308     }
1309     CONTRACTL_END;
1310     
1311     // make sure that the memory was zero initialized
1312     _ASSERTE(m_inited == 0 || m_inited == 1);
1313
1314     LPWSTR str = CLRConfig::GetConfigValue(info);
1315     if (str) 
1316     {
1317         m_list.Insert(str);
1318         delete[] str;
1319     }
1320     m_inited = 1;
1321 }
1322
1323 /**************************************************************************/
1324 bool ConfigMethodSet::contains(LPCUTF8 methodName, LPCUTF8 className, PCCOR_SIGNATURE sig)
1325 {
1326     CONTRACTL
1327     {
1328         NOTHROW;
1329     }
1330     CONTRACTL_END;
1331
1332     _ASSERTE(m_inited == 1);
1333
1334     if (m_list.IsEmpty())
1335         return false;
1336     return(m_list.IsInList(methodName, className, sig));
1337 }
1338
1339 /**************************************************************************/
1340 bool ConfigMethodSet::contains(LPCUTF8 methodName, LPCUTF8 className, CORINFO_SIG_INFO* pSigInfo)
1341 {
1342     CONTRACTL
1343     {
1344         NOTHROW;
1345     }
1346     CONTRACTL_END;
1347
1348     _ASSERTE(m_inited == 1);
1349
1350     if (m_list.IsEmpty())
1351         return false;
1352     return(m_list.IsInList(methodName, className, pSigInfo));
1353 }
1354
1355 /**************************************************************************/
1356 void ConfigDWORD::init_DontUse_(__in_z LPCWSTR keyName, DWORD defaultVal)
1357 {
1358     CONTRACTL
1359     {
1360         NOTHROW;
1361     }
1362     CONTRACTL_END;
1363     
1364     // make sure that the memory was zero initialized
1365     _ASSERTE(m_inited == 0 || m_inited == 1);
1366
1367     m_value = REGUTIL::GetConfigDWORD_DontUse_(keyName, defaultVal);
1368     m_inited = 1;
1369 }
1370
1371 /**************************************************************************/
1372 void ConfigString::init(const CLRConfig::ConfigStringInfo & info)
1373 {
1374     CONTRACTL
1375     {
1376         NOTHROW;
1377     }
1378     CONTRACTL_END;
1379     
1380     // make sure that the memory was zero initialized
1381     _ASSERTE(m_inited == 0 || m_inited == 1);
1382
1383     // Note: m_value will be leaking
1384     m_value = CLRConfig::GetConfigValue(info);
1385     m_inited = 1;
1386 }
1387
1388 //=============================================================================
1389 // AssemblyNamesList
1390 //=============================================================================
1391 // The string should be of the form
1392 // MyAssembly
1393 // MyAssembly;mscorlib;System
1394 // MyAssembly;mscorlib System
1395
1396 AssemblyNamesList::AssemblyNamesList(__in LPWSTR list)
1397 {
1398     CONTRACTL {
1399         THROWS;
1400     } CONTRACTL_END;
1401
1402     WCHAR prevChar = '?'; // dummy
1403     LPWSTR nameStart = NULL; // start of the name currently being processed. NULL if no current name
1404     AssemblyName ** ppPrevLink = &m_pNames;
1405     
1406     for (LPWSTR listWalk = list; prevChar != '\0'; prevChar = *listWalk, listWalk++)
1407     {
1408         WCHAR curChar = *listWalk;
1409         
1410         if (iswspace(curChar) || curChar == ';' || curChar == '\0' )
1411         {
1412             //
1413             // Found white-space
1414             //
1415             
1416             if (nameStart)
1417             {
1418                 // Found the end of the current name
1419                 
1420                 AssemblyName * newName = new AssemblyName();
1421                 size_t nameLen = listWalk - nameStart;
1422                 
1423                 MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1424                 newName->m_assemblyName = new char[nameLen + 1];
1425                 memcpy(newName->m_assemblyName, temp, nameLen * sizeof(newName->m_assemblyName[0]));
1426                 newName->m_assemblyName[nameLen] = '\0';
1427
1428                 *ppPrevLink = newName;
1429                 ppPrevLink = &newName->m_next;
1430
1431                 nameStart = NULL;
1432             }
1433         }
1434         else if (!nameStart)
1435         {
1436             //
1437             // Found the start of a new name
1438             //
1439             
1440             nameStart = listWalk;
1441         }
1442     }
1443
1444     _ASSERTE(!nameStart); // cannot be in the middle of a name
1445     *ppPrevLink = NULL;
1446 }
1447
1448 AssemblyNamesList::~AssemblyNamesList()
1449 {
1450     CONTRACTL
1451     {
1452         NOTHROW;
1453     }
1454     CONTRACTL_END;
1455
1456     for (AssemblyName * pName = m_pNames; pName; /**/)
1457     {
1458         AssemblyName * cur = pName;
1459         pName = pName->m_next;
1460
1461         delete [] cur->m_assemblyName;
1462         delete cur;
1463     }
1464 }
1465
1466 bool AssemblyNamesList::IsInList(LPCUTF8 assemblyName)
1467 {
1468     if (IsEmpty())
1469         return false;
1470     
1471     for (AssemblyName * pName = m_pNames; pName; pName = pName->m_next)
1472     {
1473         if (_stricmp(pName->m_assemblyName, assemblyName) == 0)
1474             return true;
1475     }
1476
1477     return false;
1478 }
1479
1480 //=============================================================================
1481 // MethodNamesList
1482 //=============================================================================
1483 //  str should be of the form :
1484 // "foo1 MyNamespace.MyClass:foo3 *:foo4 foo5(x,y,z)"
1485 // "MyClass:foo2 MyClass:*" will match under _DEBUG
1486 //
1487
1488 void MethodNamesListBase::Insert(__in_z LPWSTR str)
1489 {
1490     CONTRACTL {
1491         THROWS;
1492     } CONTRACTL_END;
1493
1494     enum State { NO_NAME, CLS_NAME, FUNC_NAME, ARG_LIST }; // parsing state machine
1495
1496     const char   SEP_CHAR = ' ';     // current character use to separate each entry
1497 //  const char   SEP_CHAR = ';';     // better  character use to separate each entry
1498
1499     WCHAR lastChar = '?'; // dummy
1500     LPWSTR nameStart = NULL; // while walking over the classname or methodname, this points to start
1501     MethodName nameBuf; // Buffer used while parsing the current entry
1502     MethodName** lastName = &pNames; // last entry inserted into the list
1503     bool         bQuote   = false;
1504
1505     nameBuf.methodName = NULL;
1506     nameBuf.className = NULL;
1507     nameBuf.numArgs = -1;
1508     nameBuf.next = NULL;
1509
1510     for(State state = NO_NAME; lastChar != '\0'; str++)
1511     {
1512         lastChar = *str;
1513
1514         switch(state)
1515         {
1516         case NO_NAME:
1517             if (*str != SEP_CHAR)
1518             {
1519                 nameStart = str;
1520                 state = CLS_NAME; // we have found the start of the next entry
1521             }
1522             break;
1523
1524         case CLS_NAME:
1525             if (*nameStart == '"')
1526             {
1527                 while (*str && *str!='"')
1528                 {
1529                     str++;
1530                 }
1531                 nameStart++;
1532                 bQuote=true;
1533             }
1534
1535             if (*str == ':')
1536             {
1537                 if (*nameStart == '*' && !bQuote)
1538                 {
1539                     // Is the classname string a wildcard. Then set it to NULL
1540                     nameBuf.className = NULL;
1541                 }
1542                 else
1543                 {
1544                     int len = (int)(str - nameStart);
1545
1546                     // Take off the quote
1547                     if (bQuote) { len--; bQuote=false; }
1548                     
1549                     nameBuf.className = new char[len + 1];
1550                     MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1551                     memcpy(nameBuf.className, temp, len*sizeof(nameBuf.className[0]));
1552                     nameBuf.className[len] = '\0';
1553                 }
1554                 if (str[1] == ':')      // Accept class::name syntax too
1555                     str++;
1556                 nameStart = str + 1;
1557                 state = FUNC_NAME;
1558             }
1559             else if (*str == '\0' || *str == SEP_CHAR || *str == '(')
1560             {
1561                 /* This was actually a method name without any class */
1562                 nameBuf.className = NULL;
1563                 goto DONE_FUNC_NAME;
1564             }
1565             break;
1566
1567         case FUNC_NAME:
1568             if (*nameStart == '"')
1569             {
1570                 while ( (nameStart==str)    || // workaround to handle when className!=NULL
1571                         (*str && *str!='"'))
1572                 {
1573                     str++;
1574                 }
1575                        
1576                 nameStart++;
1577                 bQuote=true;
1578             }
1579
1580             if (*str == '\0' || *str == SEP_CHAR || *str == '(')
1581             {
1582             DONE_FUNC_NAME:
1583                 _ASSERTE(*str == '\0' || *str == SEP_CHAR || *str == '(');
1584
1585                 if (*nameStart == '*' && !bQuote)
1586                 {
1587                     // Is the name string a wildcard. Then set it to NULL
1588                     nameBuf.methodName = NULL;
1589                 }
1590                 else
1591                 {
1592                     int len = (int)(str - nameStart);
1593
1594                     // Take off the quote
1595                     if (bQuote) { len--; bQuote=false; }
1596
1597                     nameBuf.methodName = new char[len + 1];
1598                     MAKE_UTF8PTR_FROMWIDE(temp, nameStart);
1599                     memcpy(nameBuf.methodName, temp, len*sizeof(nameBuf.methodName[0]));
1600                     nameBuf.methodName[len] = '\0';
1601                 }
1602
1603                 if (*str == '\0' || *str == SEP_CHAR)
1604                 {
1605                     nameBuf.numArgs = -1;
1606                     goto DONE_ARG_LIST;
1607                 }
1608                 else
1609                 {
1610                     _ASSERTE(*str == '(');
1611                     nameBuf.numArgs = -1;
1612                     state = ARG_LIST;
1613                 }
1614             }
1615             break;
1616
1617         case ARG_LIST:
1618             if (*str == '\0' || *str == ')')
1619             {
1620                 if (nameBuf.numArgs == -1)
1621                     nameBuf.numArgs = 0;
1622
1623             DONE_ARG_LIST:
1624                 _ASSERTE(*str == '\0' || *str == SEP_CHAR || *str == ')');
1625
1626                 // We have parsed an entire method name.
1627                 // Create a new entry in the list for it
1628
1629                 MethodName * newName = new MethodName();
1630                 *newName = nameBuf;
1631                 newName->next = NULL;
1632                 *lastName = newName;
1633                 lastName = &newName->next;
1634                 state = NO_NAME;
1635
1636                 // Skip anything after the argument list until we find the next
1637                 // separator character, otherwise if we see "func(a,b):foo" we
1638                 // create entries for "func(a,b)" as well as ":foo".
1639                 if (*str == ')')
1640                 {
1641                     while (*str && *str != SEP_CHAR)
1642                     {
1643                         str++;
1644                     }
1645                     lastChar = *str;
1646                 }
1647             }
1648             else
1649             {
1650                 if (*str != SEP_CHAR && nameBuf.numArgs == -1)
1651                     nameBuf.numArgs = 1;
1652                 if (*str == ',')
1653                     nameBuf.numArgs++;
1654             }
1655             break;
1656
1657         default: _ASSERTE(!"Bad state"); break;
1658         }
1659     }
1660 }
1661
1662 /**************************************************************/
1663
1664 void MethodNamesListBase::Destroy() 
1665 {
1666     CONTRACTL
1667     {
1668         NOTHROW;
1669     }
1670     CONTRACTL_END;
1671     
1672     for(MethodName * pName = pNames; pName; /**/)
1673     {
1674         if (pName->className)
1675             delete [] pName->className;
1676         if (pName->methodName)
1677             delete [] pName->methodName;
1678
1679         MethodName * curName = pName;
1680         pName = pName->next;
1681         delete curName;
1682     }
1683 }
1684
1685 /**************************************************************/
1686 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, PCCOR_SIGNATURE sig) 
1687 {
1688     CONTRACTL
1689     {
1690         NOTHROW;
1691     }
1692     CONTRACTL_END;
1693
1694     int numArgs = -1;
1695     if (sig != NULL)
1696     {
1697         sig++;      // Skip calling convention
1698         numArgs = CorSigUncompressData(sig);  
1699     }
1700
1701     return IsInList(methName, clsName, numArgs);
1702 }
1703
1704 /**************************************************************/
1705 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, CORINFO_SIG_INFO* pSigInfo)
1706 {
1707     CONTRACTL
1708     {
1709         NOTHROW;
1710     }
1711     CONTRACTL_END;
1712
1713     int numArgs = -1;
1714     if (pSigInfo != NULL)
1715     {
1716         numArgs = pSigInfo->numArgs;
1717     }
1718
1719     return IsInList(methName, clsName, numArgs);
1720 }
1721
1722 /**************************************************************/
1723 bool MethodNamesListBase::IsInList(LPCUTF8 methName, LPCUTF8 clsName, int numArgs) 
1724 {
1725     CONTRACTL
1726     {
1727         NOTHROW;
1728     }
1729     CONTRACTL_END;
1730
1731     // Try to match all the entries in the list
1732
1733     for(MethodName * pName = pNames; pName; pName = pName->next)
1734     {
1735         // If numArgs is valid, check for mismatch
1736         if (pName->numArgs != -1 && pName->numArgs != numArgs)
1737             continue;
1738
1739         // If methodName is valid, check for mismatch
1740         if (pName->methodName) {
1741             if (strcmp(pName->methodName, methName) != 0) {
1742
1743                 // C++ embeds the class name into the method name,
1744                 // deal with that here (workaround)
1745                 const char* ptr = strchr(methName, ':');
1746                 if (ptr != 0 && ptr[1] == ':' && strcmp(&ptr[2], pName->methodName) == 0) {
1747                     unsigned clsLen = (unsigned)(ptr - methName);
1748                     if (pName->className == 0 || strncmp(pName->className, methName, clsLen) == 0)
1749                         return true;
1750                 }
1751                 continue;
1752             }
1753         }
1754
1755         // check for class Name exact match
1756         if (clsName == 0 || pName->className == 0 || strcmp(pName->className, clsName) == 0)
1757             return true;
1758
1759         // check for suffix wildcard like System.*
1760         unsigned len = (unsigned)strlen(pName->className);
1761         if (len > 0 && pName->className[len-1] == '*' && strncmp(pName->className, clsName, len-1) == 0)
1762             return true;
1763
1764 #ifdef _DEBUG
1765             // Maybe className doesnt include namespace. Try to match that
1766         LPCUTF8 onlyClass = ns::FindSep(clsName);
1767         if (onlyClass && strcmp(pName->className, onlyClass+1) == 0)
1768             return true;
1769 #endif
1770     }
1771     return(false);
1772 }
1773
1774 //=============================================================================
1775 // Signature Validation Functions (scaled down version from MDValidator
1776 //=============================================================================
1777
1778 //*****************************************************************************
1779 // This function validates one argument given an offset into the signature
1780 // where the argument begins.  This function assumes that the signature is well
1781 // formed as far as the compression scheme is concerned.
1782 // <TODO>@todo: Validate tokens embedded.</TODO>
1783 //*****************************************************************************
1784 HRESULT validateOneArg(
1785     mdToken     tk,                     // [IN] Token whose signature needs to be validated.
1786     SigParser  *pSig, 
1787     ULONG       *pulNSentinels,         // [IN/OUT] Number of sentinels
1788     IMDInternalImport*  pImport,        // [IN] Internal MD Import interface ptr
1789     BOOL        bNoVoidAllowed)         // [IN] Flag indicating whether "void" is disallowed for this arg
1790
1791 {
1792     CONTRACTL
1793     {
1794         NOTHROW;
1795     }
1796     CONTRACTL_END;
1797     
1798     BYTE        elementType;          // Current element type being processed.
1799     mdToken     token;                  // Embedded token.
1800     ULONG       ulArgCnt;               // Argument count for function pointer.
1801     ULONG       ulIndex;                // Index for type parameters
1802     ULONG       ulRank;                 // Rank of the array.
1803     ULONG       ulSizes;                // Count of sized dimensions of the array.
1804     ULONG       ulLbnds;                // Count of lower bounds of the array.
1805     ULONG       ulCallConv;
1806     
1807     HRESULT     hr = S_OK;              // Value returned.
1808     BOOL        bRepeat = TRUE;         // MODOPT and MODREQ belong to the arg after them
1809     
1810     while(bRepeat)
1811     {
1812         bRepeat = FALSE;
1813         // Validate that the argument is not missing.
1814         
1815         // Get the element type.
1816         if (FAILED(pSig->GetByte(&elementType)))
1817         {
1818             IfFailGo(VLDTR_E_SIG_MISSARG);
1819         }
1820         
1821         // Walk past all the modifier types.
1822         while (elementType & ELEMENT_TYPE_MODIFIER)
1823         {
1824             if (elementType == ELEMENT_TYPE_SENTINEL)
1825             {
1826                 if(pulNSentinels) *pulNSentinels+=1;
1827                 if(TypeFromToken(tk) != mdtMemberRef) IfFailGo(VLDTR_E_SIG_SENTINMETHODDEF);
1828             }
1829             if (FAILED(pSig->GetByte(&elementType)))
1830             {
1831                 IfFailGo(VLDTR_E_SIG_MISSELTYPE);
1832             }
1833         }
1834         
1835         switch (elementType)
1836         {
1837             case ELEMENT_TYPE_VOID:
1838                 if(bNoVoidAllowed) IfFailGo(VLDTR_E_SIG_BADVOID);
1839                 
1840             case ELEMENT_TYPE_BOOLEAN:
1841             case ELEMENT_TYPE_CHAR:
1842             case ELEMENT_TYPE_I1:
1843             case ELEMENT_TYPE_U1:
1844             case ELEMENT_TYPE_I2:
1845             case ELEMENT_TYPE_U2:
1846             case ELEMENT_TYPE_I4:
1847             case ELEMENT_TYPE_U4:
1848             case ELEMENT_TYPE_I8:
1849             case ELEMENT_TYPE_U8:
1850             case ELEMENT_TYPE_R4:
1851             case ELEMENT_TYPE_R8:
1852             case ELEMENT_TYPE_STRING:
1853             case ELEMENT_TYPE_OBJECT:
1854             case ELEMENT_TYPE_TYPEDBYREF:
1855             case ELEMENT_TYPE_U:
1856             case ELEMENT_TYPE_I:
1857                 break;
1858             case ELEMENT_TYPE_PTR:
1859                 // Validate the referenced type.
1860                 if(FAILED(hr = validateOneArg(tk, pSig, pulNSentinels, pImport, FALSE))) IfFailGo(hr);
1861                 break;
1862             case ELEMENT_TYPE_BYREF:  //fallthru
1863                 if(TypeFromToken(tk)==mdtFieldDef) IfFailGo(VLDTR_E_SIG_BYREFINFIELD);
1864             case ELEMENT_TYPE_PINNED:
1865             case ELEMENT_TYPE_SZARRAY:
1866                 // Validate the referenced type.
1867                 if(FAILED(hr = validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE))) IfFailGo(hr);
1868                 break;
1869             case ELEMENT_TYPE_CMOD_OPT:
1870             case ELEMENT_TYPE_CMOD_REQD:
1871                 bRepeat = TRUE; // go on validating, we're not done with this arg
1872             case ELEMENT_TYPE_VALUETYPE: //fallthru
1873             case ELEMENT_TYPE_CLASS:
1874                 // See if the token is missing.
1875                 if (FAILED(pSig->GetToken(&token)))
1876                 {
1877                     IfFailGo(VLDTR_E_SIG_MISSTKN);
1878                 }
1879                 // Token validation .
1880                 if(pImport)
1881                 {
1882                     ULONG   rid = RidFromToken(token);
1883                     ULONG   typ = TypeFromToken(token);
1884                     ULONG   maxrid = pImport->GetCountWithTokenKind(typ);
1885                     if(typ == mdtTypeDef) maxrid++;
1886                     if((rid==0)||(rid > maxrid)) IfFailGo(VLDTR_E_SIG_TKNBAD);
1887                 }
1888                 break;
1889                 
1890             case ELEMENT_TYPE_FNPTR: 
1891                 // <TODO>@todo: More function pointer validation?</TODO>
1892                 // Validate that calling convention is present.
1893                 if (FAILED(pSig->GetCallingConvInfo(&ulCallConv)))
1894                 {
1895                     IfFailGo(VLDTR_E_SIG_MISSFPTR);
1896                 }
1897                 if(((ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK) >= IMAGE_CEE_CS_CALLCONV_MAX) 
1898                     ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
1899                     &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS)))) IfFailGo(VLDTR_E_MD_BADCALLINGCONV);
1900                 
1901                 // Validate that argument count is present.
1902                 if (FAILED(pSig->GetData(&ulArgCnt)))
1903                 {
1904                     IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
1905                 }
1906                 
1907                 // FNPTR signature must follow the rules of MethodDef
1908                 // Validate and consume return type.
1909                 IfFailGo(validateOneArg(mdtMethodDef, pSig, NULL, pImport, FALSE));
1910                 
1911                 // Validate and consume the arguments.
1912                 while(ulArgCnt--)
1913                 {
1914                     IfFailGo(validateOneArg(mdtMethodDef, pSig, NULL, pImport, TRUE));
1915                 }
1916                 break;
1917                 
1918             case ELEMENT_TYPE_ARRAY:
1919                 // Validate and consume the base type.
1920                 IfFailGo(validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE));
1921                 
1922                 // Validate that the rank is present.
1923                 if (FAILED(pSig->GetData(&ulRank)))
1924                 {
1925                     IfFailGo(VLDTR_E_SIG_MISSRANK);
1926                 }
1927                 
1928                 // Process the sizes.
1929                 if (ulRank)
1930                 {
1931                     // Validate that the count of sized-dimensions is specified.
1932                     if (FAILED(pSig->GetData(&ulSizes)))
1933                     {
1934                         IfFailGo(VLDTR_E_SIG_MISSNSIZE);
1935                     }
1936                     
1937                     // Loop over the sizes.
1938                     while(ulSizes--)
1939                     {
1940                         // Validate the current size.
1941                         if (FAILED(pSig->GetData(NULL)))
1942                         {
1943                             IfFailGo(VLDTR_E_SIG_MISSSIZE);
1944                         }
1945                     }
1946                     
1947                     // Validate that the count of lower bounds is specified.
1948                     if (FAILED(pSig->GetData(&ulLbnds)))
1949                     {
1950                         IfFailGo(VLDTR_E_SIG_MISSNLBND);
1951                     }
1952                     
1953                     // Loop over the lower bounds.
1954                     while(ulLbnds--)
1955                     {
1956                         // Validate the current lower bound.
1957                         if (FAILED(pSig->GetData(NULL)))
1958                         {
1959                             IfFailGo(VLDTR_E_SIG_MISSLBND);
1960                         }
1961                     }
1962                 }
1963                 break;
1964                 case ELEMENT_TYPE_VAR:
1965                 case ELEMENT_TYPE_MVAR:
1966                     // Validate that index is present.
1967                     if (FAILED(pSig->GetData(&ulIndex)))
1968                     {
1969                         IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
1970                     }
1971                     
1972                     //@todo GENERICS: check that index is in range
1973                     break;
1974                     
1975                 case ELEMENT_TYPE_GENERICINST:
1976                     // Validate the generic type.
1977                     IfFailGo(validateOneArg(tk, pSig, pulNSentinels, pImport, TRUE));
1978                     
1979                     // Validate that parameter count is present.
1980                     if (FAILED(pSig->GetData(&ulArgCnt)))
1981                     {
1982                         IfFailGo(VLDTR_E_SIG_MISSFPTRARGCNT);
1983                     }
1984                     
1985                 //@todo GENERICS: check that number of parameters matches definition?
1986                     
1987                     // Validate and consume the parameters.
1988                     while(ulArgCnt--)
1989                     {
1990                         IfFailGo(validateOneArg(tk, pSig, NULL, pImport, TRUE));
1991                     }
1992                     break;
1993                     
1994             case ELEMENT_TYPE_SENTINEL: // this case never works because all modifiers are skipped before switch
1995                 if(TypeFromToken(tk) == mdtMethodDef) IfFailGo(VLDTR_E_SIG_SENTINMETHODDEF);
1996                 break;
1997                 
1998             default:
1999                 IfFailGo(VLDTR_E_SIG_BADELTYPE);
2000                 break;
2001         }   // switch (ulElementType)
2002     } // end while(bRepeat)
2003 ErrExit:
2004     return hr;
2005 }   // validateOneArg()
2006
2007 //*****************************************************************************
2008 // This function validates the given Method/Field/Standalone signature.  
2009 //@todo GENERICS: MethodInstantiation?
2010 //*****************************************************************************
2011 HRESULT validateTokenSig(
2012     mdToken             tk,                     // [IN] Token whose signature needs to be validated.
2013     PCCOR_SIGNATURE     pbSig,                  // [IN] Signature.
2014     ULONG               cbSig,                  // [IN] Size in bytes of the signature.
2015     DWORD               dwFlags,                // [IN] Method flags.
2016     IMDInternalImport*  pImport)               // [IN] Internal MD Import interface ptr
2017 {
2018     CONTRACTL
2019     {
2020         NOTHROW;
2021     }
2022     CONTRACTL_END;
2023     
2024     ULONG       ulCallConv;             // Calling convention.
2025     ULONG       ulArgCount = 1;         // Count of arguments (1 because of the return type)
2026     ULONG       ulTyArgCount = 0;         // Count of type arguments
2027     ULONG       ulArgIx = 0;            // Starting index of argument (standalone sig: 1)
2028     ULONG       i;                      // Looping index.
2029     HRESULT     hr = S_OK;              // Value returned.
2030     ULONG       ulNSentinels = 0;
2031     SigParser   sig(pbSig, cbSig);
2032     
2033     _ASSERTE(TypeFromToken(tk) == mdtMethodDef ||
2034              TypeFromToken(tk) == mdtMemberRef ||
2035              TypeFromToken(tk) == mdtSignature ||
2036              TypeFromToken(tk) == mdtFieldDef);
2037
2038     // Check for NULL signature.
2039     if (!pbSig || !cbSig) return VLDTR_E_SIGNULL;
2040
2041     // Validate the calling convention.
2042     
2043     // Moves behind calling convention
2044     IfFailRet(sig.GetCallingConvInfo(&ulCallConv));
2045     i = ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK;
2046     switch(TypeFromToken(tk))
2047     {
2048         case mdtMethodDef: // MemberRefs have no flags available
2049             // If HASTHIS is set on the calling convention, the method should not be static.
2050             if ((ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
2051                 IsMdStatic(dwFlags)) return VLDTR_E_MD_THISSTATIC;
2052             
2053             // If HASTHIS is not set on the calling convention, the method should be static.
2054             if (!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS) &&
2055                 !IsMdStatic(dwFlags)) return VLDTR_E_MD_NOTTHISNOTSTATIC;
2056             // fall thru to callconv check;
2057             
2058         case mdtMemberRef:
2059             if(i == IMAGE_CEE_CS_CALLCONV_FIELD) return validateOneArg(tk, &sig, NULL, pImport, TRUE);
2060             
2061             // EXPLICITTHIS and native call convs are for stand-alone sigs only (for calli)
2062             if(((i != IMAGE_CEE_CS_CALLCONV_DEFAULT)&&( i != IMAGE_CEE_CS_CALLCONV_VARARG))
2063                 || (ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)) return VLDTR_E_MD_BADCALLINGCONV;
2064             break;
2065             
2066         case mdtSignature:
2067             if(i != IMAGE_CEE_CS_CALLCONV_LOCAL_SIG) // then it is function sig for calli
2068             {
2069                 if((i >= IMAGE_CEE_CS_CALLCONV_MAX) 
2070                     ||((ulCallConv & IMAGE_CEE_CS_CALLCONV_EXPLICITTHIS)
2071                     &&(!(ulCallConv & IMAGE_CEE_CS_CALLCONV_HASTHIS)))) return VLDTR_E_MD_BADCALLINGCONV;
2072             }
2073             else
2074                 ulArgIx = 1;        // Local variable signatures don't have a return type 
2075             break;
2076             
2077         case mdtFieldDef:
2078             if(i != IMAGE_CEE_CS_CALLCONV_FIELD) return VLDTR_E_MD_BADCALLINGCONV;
2079             return validateOneArg(tk, &sig, NULL, pImport, TRUE);
2080     }
2081     // Is there any sig left for arguments?
2082     
2083     // Get the type argument count
2084     if (ulCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC)
2085     {
2086         if (FAILED(sig.GetData(&ulTyArgCount)))
2087         {
2088             return VLDTR_E_MD_NOARGCNT;
2089         }
2090     }
2091     
2092     // Get the argument count.
2093     if (FAILED(sig.GetData(&ulArgCount)))
2094     {
2095         return VLDTR_E_MD_NOARGCNT;
2096     }
2097     
2098     // Validate the return type and the arguments.
2099     // (at this moment ulArgCount = num.args+1, ulArgIx = (standalone sig. ? 1 :0); )
2100     for(; ulArgIx < ulArgCount; ulArgIx++)
2101     {
2102         if(FAILED(hr = validateOneArg(tk, &sig, &ulNSentinels, pImport, (ulArgIx!=0)))) return hr;
2103     }
2104     
2105     // <TODO>@todo: we allow junk to be at the end of the signature (we may not consume it all)
2106     // do we care?</TODO>
2107     
2108     if((ulNSentinels != 0) && ((ulCallConv & IMAGE_CEE_CS_CALLCONV_MASK) != IMAGE_CEE_CS_CALLCONV_VARARG ))
2109         return VLDTR_E_SIG_SENTMUSTVARARG;
2110     if(ulNSentinels > 1) return VLDTR_E_SIG_MULTSENTINELS;
2111     return S_OK;
2112 }   // validateTokenSig()
2113
2114 HRESULT GetImageRuntimeVersionString(PVOID pMetaData, LPCSTR* pString)
2115 {
2116     CONTRACTL
2117     {
2118         NOTHROW;
2119     }
2120     CONTRACTL_END;
2121     
2122     _ASSERTE(pString);
2123     STORAGESIGNATURE* pSig = (STORAGESIGNATURE*) pMetaData;
2124
2125     // Verify the signature.
2126
2127     // If signature didn't match, you shouldn't be here.
2128     if (pSig->GetSignature() != STORAGE_MAGIC_SIG)
2129         return CLDB_E_FILE_CORRUPT;
2130
2131     // The version started in version 1.1
2132     if (pSig->GetMajorVer() < 1)
2133         return CLDB_E_FILE_OLDVER;
2134
2135     if (pSig->GetMajorVer() == 1 && pSig->GetMinorVer() < 1)
2136         return CLDB_E_FILE_OLDVER;
2137     
2138     // Header data starts after signature.
2139     *pString = (LPCSTR) pSig->pVersion;
2140     return S_OK;
2141 }
2142
2143 //*****************************************************************************
2144 // Convert a UTF8 string to Unicode, into a CQuickArray<WCHAR>.
2145 //*****************************************************************************
2146 HRESULT Utf2Quick(
2147     LPCUTF8     pStr,                   // The string to convert.
2148     CQuickArray<WCHAR> &rStr,           // The QuickArray<WCHAR> to convert it into.
2149     int         iCurLen)                // Inital characters in the array to leave (default 0).
2150 {
2151     CONTRACTL
2152     {
2153         NOTHROW;
2154     }
2155     CONTRACTL_END;
2156     
2157     HRESULT     hr = S_OK;              // A result.
2158     int         iReqLen;                // Required additional length.
2159     int         iActLen;
2160     int         bAlloc = 0;             // If non-zero, allocation was required.
2161
2162     if (iCurLen < 0 )
2163     {
2164         _ASSERTE_MSG(false, "Invalid current length");
2165         return E_INVALIDARG;
2166     }
2167
2168     // Calculate the space available
2169     S_SIZE_T cchAvail = S_SIZE_T(rStr.MaxSize()) - S_SIZE_T(iCurLen);
2170     if (cchAvail.IsOverflow() || cchAvail.Value() > INT_MAX)
2171     {
2172         _ASSERTE_MSG(false, "Integer overflow/underflow");
2173         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2174     }
2175
2176     // Attempt the conversion.
2177     LPWSTR rNewStr = rStr.Ptr()+iCurLen;
2178     if(rNewStr < rStr.Ptr())
2179     {
2180         _ASSERTE_MSG(false, "Integer overflow/underflow");
2181         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2182     }
2183     iReqLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, rNewStr, (int)(cchAvail.Value()));
2184
2185     // If the buffer was too small, determine what is required.
2186     if (iReqLen == 0) 
2187         bAlloc = iReqLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, 0, 0);
2188     // Resize the buffer.  If the buffer was large enough, this just sets the internal
2189     //  counter, but if it was too small, this will attempt a reallocation.  Note that 
2190     //  the length includes the terminating W('/0').
2191     IfFailGo(rStr.ReSizeNoThrow(iCurLen+iReqLen));
2192     // If we had to realloc, then do the conversion again, now that the buffer is 
2193     //  large enough.
2194     if (bAlloc) {
2195         //recalculating cchAvail since MaxSize could have been changed.
2196         cchAvail = S_SIZE_T(rStr.MaxSize()) - S_SIZE_T(iCurLen);
2197         if (cchAvail.IsOverflow() || cchAvail.Value() > INT_MAX)
2198         {
2199             _ASSERTE_MSG(false, "Integer overflow/underflow");
2200             return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2201         }
2202         //reculculating rNewStr
2203         rNewStr = rStr.Ptr()+iCurLen;
2204         
2205         if(rNewStr < rStr.Ptr())
2206         {
2207         _ASSERTE_MSG(false, "Integer overflow/underflow");
2208         return HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW);
2209         }
2210         iActLen = WszMultiByteToWideChar(CP_UTF8, 0, pStr, -1, rNewStr, (int)(cchAvail.Value()));
2211         _ASSERTE(iReqLen == iActLen);
2212     }
2213 ErrExit:
2214     return hr;
2215 } // HRESULT Utf2Quick()
2216
2217
2218 //*****************************************************************************
2219 //  Extract the movl 64-bit unsigned immediate from an IA64 bundle
2220 //  (Format X2)
2221 //*****************************************************************************
2222 UINT64 GetIA64Imm64(UINT64 * pBundle)
2223 {
2224     WRAPPER_NO_CONTRACT;
2225     
2226     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2227     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2228
2229     return GetIA64Imm64(temp0, temp1);
2230 }
2231
2232 UINT64 GetIA64Imm64(UINT64 qword0, UINT64 qword1)
2233 {
2234     LIMITED_METHOD_CONTRACT;
2235     
2236     UINT64 imm64 = 0;
2237     
2238 #ifdef _DEBUG_IMPL
2239     //
2240     // make certain we're decoding a movl opcode, with template 4 or 5
2241     //
2242     UINT64    templa = (qword0 >>  0) & 0x1f;
2243     UINT64    opcode = (qword1 >> 60) & 0xf;
2244     
2245     _ASSERTE((opcode == 0x6) && ((templa == 0x4) || (templa == 0x5)));
2246 #endif        
2247
2248     imm64  = (qword1 >> 59) << 63;       //  1 i
2249     imm64 |= (qword1 << 41) >>  1;       // 23 high bits of imm41 
2250     imm64 |= (qword0 >> 46) << 22;       // 18 low  bits of imm41
2251     imm64 |= (qword1 >> 23) & 0x200000;  //  1 ic
2252     imm64 |= (qword1 >> 29) & 0x1F0000;  //  5 imm5c
2253     imm64 |= (qword1 >> 43) & 0xFF80;    //  9 imm9d
2254     imm64 |= (qword1 >> 36) & 0x7F;      //  7 imm7b
2255
2256     return imm64;
2257 }
2258
2259 //*****************************************************************************
2260 //  Deposit the movl 64-bit unsigned immediate into an IA64 bundle
2261 //  (Format X2)
2262 //*****************************************************************************
2263 void PutIA64Imm64(UINT64 * pBundle, UINT64 imm64)
2264 {
2265     LIMITED_METHOD_CONTRACT;
2266     
2267 #ifdef _DEBUG_IMPL
2268     //
2269     // make certain we're decoding a movl opcode, with template 4 or 5
2270     //
2271     UINT64    templa = (pBundle[0] >>  0) & 0x1f;
2272     UINT64    opcode = (pBundle[1] >> 60) & 0xf ;
2273     
2274     _ASSERTE((opcode == 0x6) && ((templa == 0x4) || (templa == 0x5)));
2275 #endif        
2276
2277     const UINT64 mask0 = UI64(0x00003FFFFFFFFFFF);
2278     const UINT64 mask1 = UI64(0xF000080FFF800000);
2279
2280     /* Clear all bits used as part of the imm64 */
2281     pBundle[0] &= mask0;
2282     pBundle[1] &= mask1;
2283
2284     UINT64 temp0;
2285     UINT64 temp1;
2286
2287     temp1  = (imm64 >> 63)      << 59;  //  1 i
2288     temp1 |= (imm64 & 0xFF80)   << 43;  //  9 imm9d
2289     temp1 |= (imm64 & 0x1F0000) << 29;  //  5 imm5c
2290     temp1 |= (imm64 & 0x200000) << 23;  //  1 ic
2291     temp1 |= (imm64 & 0x7F)     << 36;  //  7 imm7b
2292     temp1 |= (imm64 <<  1)      >> 41;  // 23 high bits of imm41
2293     temp0  = (imm64 >> 22)      << 46;  // 18 low bits of imm41
2294
2295     /* Or in the new bits used in the imm64 */
2296     pBundle[0] |= temp0;
2297     pBundle[1] |= temp1;
2298     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2299 }
2300
2301 //*****************************************************************************
2302 //  Extract the IP-Relative signed 25-bit immediate from an IA64 bundle 
2303 //  (Formats B1, B2 or B3)
2304 //  Note that due to branch target alignment requirements 
2305 //       the lowest four bits in the result will always be zero.
2306 //*****************************************************************************
2307 INT32 GetIA64Rel25(UINT64 * pBundle, UINT32 slot)
2308 {
2309     WRAPPER_NO_CONTRACT;
2310     
2311     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2312     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2313
2314     return GetIA64Rel25(temp0, temp1, slot);
2315 }
2316
2317 INT32 GetIA64Rel25(UINT64 qword0, UINT64 qword1, UINT32 slot)
2318 {
2319     LIMITED_METHOD_CONTRACT;
2320     
2321     INT32 imm25 = 0;
2322     
2323     if (slot == 2)
2324     {
2325         if ((qword1 >> 59) & 1)
2326             imm25 = 0xFF000000;
2327         imm25 |= (qword1 >> 32) & 0x00FFFFF0;    // 20 imm20b
2328     }
2329     else if (slot == 1)
2330     {
2331         if ((qword1 >> 18) & 1)
2332             imm25 = 0xFF000000;
2333         imm25 |= (qword1 <<  9) & 0x00FFFE00;    // high 15 of imm20b
2334         imm25 |= (qword0 >> 55) & 0x000001F0;    // low   5 of imm20b
2335     }
2336     else if (slot == 0)
2337     {
2338         if ((qword0 >> 41) & 1)
2339             imm25 = 0xFF000000;
2340         imm25 |= (qword0 >> 14) & 0x00FFFFF0;    // 20 imm20b
2341     }
2342
2343     return imm25;
2344 }
2345
2346 //*****************************************************************************
2347 //  Deposit the IP-Relative signed 25-bit immediate into an IA64 bundle
2348 //  (Formats B1, B2 or B3)
2349 //  Note that due to branch target alignment requirements 
2350 //       the lowest four bits are required to be zero.
2351 //*****************************************************************************
2352 void PutIA64Rel25(UINT64 * pBundle, UINT32 slot, INT32 imm25)
2353 {
2354     LIMITED_METHOD_CONTRACT;
2355     
2356     _ASSERTE((imm25 & 0xF) == 0);
2357
2358     if (slot == 2)
2359     {
2360         const UINT64 mask1 = UI64(0xF700000FFFFFFFFF);
2361         /* Clear all bits used as part of the imm25 */
2362         pBundle[1] &= mask1;
2363
2364         UINT64 temp1;
2365         
2366         temp1  = (UINT64) (imm25 & 0x1000000) << 35;     //  1 s
2367         temp1 |= (UINT64) (imm25 & 0x0FFFFF0) << 32;     // 20 imm20b
2368         
2369         /* Or in the new bits used in the imm64 */
2370         pBundle[1] |= temp1;
2371     }
2372     else if (slot == 1)
2373     {
2374         const UINT64 mask0 = UI64(0x0EFFFFFFFFFFFFFF);
2375         const UINT64 mask1 = UI64(0xFFFFFFFFFFFB8000);
2376         /* Clear all bits used as part of the imm25 */
2377         pBundle[0] &= mask0;
2378         pBundle[1] &= mask1;
2379         
2380         UINT64 temp0;
2381         UINT64 temp1;
2382         
2383         temp1  = (UINT64) (imm25 & 0x1000000) >>  7;     //  1 s
2384         temp1 |= (UINT64) (imm25 & 0x0FFFE00) >>  9;     // high 15 of imm20b
2385         temp0  = (UINT64) (imm25 & 0x00001F0) << 55;     // low   5 of imm20b
2386         
2387         /* Or in the new bits used in the imm64 */
2388         pBundle[0] |= temp0;
2389         pBundle[1] |= temp1;
2390     }
2391     else if (slot == 0)
2392     {
2393         const UINT64 mask0 = UI64(0xFFFFFDC00003FFFF);
2394         /* Clear all bits used as part of the imm25 */
2395         pBundle[0] &= mask0;
2396
2397         UINT64 temp0;
2398         
2399         temp0  = (UINT64) (imm25 & 0x1000000) << 16;     //  1 s
2400         temp0 |= (UINT64) (imm25 & 0x0FFFFF0) << 14;     // 20 imm20b
2401         
2402         /* Or in the new bits used in the imm64 */
2403         pBundle[0] |= temp0;
2404
2405     }
2406     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2407 }
2408
2409 //*****************************************************************************
2410 //  Extract the IP-Relative signed 64-bit immediate from an IA64 bundle 
2411 //  (Formats X3 or X4)
2412 //*****************************************************************************
2413 INT64 GetIA64Rel64(UINT64 * pBundle)
2414 {
2415     WRAPPER_NO_CONTRACT;
2416     
2417     UINT64 temp0 = PTR_UINT64(pBundle)[0];
2418     UINT64 temp1 = PTR_UINT64(pBundle)[1];
2419
2420     return GetIA64Rel64(temp0, temp1);
2421 }
2422
2423 INT64 GetIA64Rel64(UINT64 qword0, UINT64 qword1)
2424 {
2425     LIMITED_METHOD_CONTRACT;
2426     
2427     INT64 imm64 = 0;
2428     
2429 #ifdef _DEBUG_IMPL
2430     //
2431     // make certain we're decoding a brl opcode, with template 4 or 5
2432     //
2433     UINT64       templa = (qword0 >>  0) & 0x1f;
2434     UINT64       opcode = (qword1 >> 60) & 0xf;
2435     
2436     _ASSERTE(((opcode == 0xC) || (opcode == 0xD)) &&
2437              ((templa == 0x4) || (templa == 0x5)));
2438 #endif        
2439
2440     imm64  = (qword1 >> 59) << 63;         //  1 i
2441     imm64 |= (qword1 << 41) >>  1;         // 23 high bits of imm39 
2442     imm64 |= (qword0 >> 48) << 24;         // 16 low  bits of imm39
2443     imm64 |= (qword1 >> 32) & 0xFFFFF0;    // 20 imm20b
2444                                           //  4 bits of zeros
2445     return imm64;
2446 }
2447
2448 //*****************************************************************************
2449 //  Deposit the IP-Relative signed 64-bit immediate into an IA64 bundle
2450 //  (Formats X3 or X4)
2451 //*****************************************************************************
2452 void PutIA64Rel64(UINT64 * pBundle, INT64 imm64)
2453 {
2454     LIMITED_METHOD_CONTRACT;
2455     
2456 #ifdef _DEBUG_IMPL
2457     //
2458     // make certain we're decoding a brl opcode, with template 4 or 5
2459     //
2460     UINT64    templa = (pBundle[0] >>  0) & 0x1f;
2461     UINT64    opcode = (pBundle[1] >> 60) & 0xf;
2462     
2463     _ASSERTE(((opcode == 0xC) || (opcode == 0xD)) &&
2464              ((templa == 0x4) || (templa == 0x5)));
2465     _ASSERTE((imm64 & 0xF) == 0);
2466 #endif        
2467
2468     const UINT64 mask0 = UI64(0x00003FFFFFFFFFFF);
2469     const UINT64 mask1 = UI64(0xF700000FFF800000);
2470
2471     /* Clear all bits used as part of the imm64 */
2472     pBundle[0] &= mask0;
2473     pBundle[1] &= mask1;
2474
2475     UINT64 temp0  = (imm64 & UI64(0x000000FFFF000000)) << 24;  // 16 low  bits of imm39
2476     UINT64 temp1  = (imm64 & UI64(0x8000000000000000)) >>  4   //  1 i
2477                   | (imm64 & UI64(0x7FFFFF0000000000)) >> 40   // 23 high bits of imm39 
2478                   | (imm64 & UI64(0x0000000000FFFFF0)) << 32;  // 20 imm20b
2479
2480     /* Or in the new bits used in the imm64 */
2481     pBundle[0] |= temp0;
2482     pBundle[1] |= temp1;
2483     FlushInstructionCache(GetCurrentProcess(),pBundle,16);
2484 }
2485
2486 //*****************************************************************************
2487 //  Extract the 16-bit immediate from ARM Thumb2 Instruction (format T2_N)
2488 //*****************************************************************************
2489 static FORCEINLINE UINT16 GetThumb2Imm16(UINT16 * p)
2490 {
2491     LIMITED_METHOD_CONTRACT;
2492     
2493     return ((p[0] << 12) & 0xf000) |
2494            ((p[0] <<  1) & 0x0800) |
2495            ((p[1] >>  4) & 0x0700) |
2496            ((p[1] >>  0) & 0x00ff);
2497 }
2498
2499 //*****************************************************************************
2500 //  Extract the 32-bit immediate from movw/movt sequence
2501 //*****************************************************************************
2502 UINT32 GetThumb2Mov32(UINT16 * p)
2503 {
2504     LIMITED_METHOD_CONTRACT;
2505
2506     // Make sure we are decoding movw/movt sequence
2507     _ASSERTE_IMPL((*(p+0) & 0xFBF0) == 0xF240);
2508     _ASSERTE_IMPL((*(p+2) & 0xFBF0) == 0xF2C0);
2509
2510     return (UINT32)GetThumb2Imm16(p) + ((UINT32)GetThumb2Imm16(p + 2) << 16);
2511 }
2512
2513 //*****************************************************************************
2514 //  Deposit the 16-bit immediate into ARM Thumb2 Instruction (format T2_N)
2515 //*****************************************************************************
2516 static FORCEINLINE void PutThumb2Imm16(UINT16 * p, UINT16 imm16)
2517 {
2518     LIMITED_METHOD_CONTRACT;
2519
2520     USHORT Opcode0 = p[0];
2521     USHORT Opcode1 = p[1];
2522     Opcode0 &= ~((0xf000 >> 12) | (0x0800 >> 1));
2523     Opcode1 &= ~((0x0700 <<  4) | (0x00ff << 0));
2524     Opcode0 |= (imm16 & 0xf000) >> 12;
2525     Opcode0 |= (imm16 & 0x0800) >>  1;
2526     Opcode1 |= (imm16 & 0x0700) <<  4;
2527     Opcode1 |= (imm16 & 0x00ff) <<  0;
2528     p[0] = Opcode0;
2529     p[1] = Opcode1;
2530 }
2531
2532 //*****************************************************************************
2533 //  Deposit the 32-bit immediate into movw/movt Thumb2 sequence
2534 //*****************************************************************************
2535 void PutThumb2Mov32(UINT16 * p, UINT32 imm32)
2536 {
2537     LIMITED_METHOD_CONTRACT;
2538
2539     // Make sure we are decoding movw/movt sequence
2540     _ASSERTE_IMPL((*(p+0) & 0xFBF0) == 0xF240);
2541     _ASSERTE_IMPL((*(p+2) & 0xFBF0) == 0xF2C0);
2542
2543     PutThumb2Imm16(p, (UINT16)imm32);
2544     PutThumb2Imm16(p + 2, (UINT16)(imm32 >> 16));
2545 }
2546
2547 //*****************************************************************************
2548 //  Extract the 24-bit rel offset from bl instruction
2549 //*****************************************************************************
2550 INT32 GetThumb2BlRel24(UINT16 * p)
2551 {
2552     LIMITED_METHOD_CONTRACT;
2553
2554     USHORT Opcode0 = p[0];
2555     USHORT Opcode1 = p[1];
2556
2557     UINT32 S  = Opcode0 >> 10;
2558     UINT32 J2 = Opcode1 >> 11;
2559     UINT32 J1 = Opcode1 >> 13;
2560
2561     INT32 ret = 
2562         ((S << 24)              & 0x1000000) |
2563         (((J1 ^ S ^ 1) << 23)   & 0x0800000) |
2564         (((J2 ^ S ^ 1) << 22)   & 0x0400000) |
2565         ((Opcode0 << 12)        & 0x03FF000) |
2566         ((Opcode1 <<  1)        & 0x0000FFE);
2567
2568     // Sign-extend and return
2569     return (ret << 7) >> 7;
2570 }
2571
2572 //*****************************************************************************
2573 //  Extract the 24-bit rel offset from bl instruction
2574 //*****************************************************************************
2575 void PutThumb2BlRel24(UINT16 * p, INT32 imm24)
2576 {
2577     LIMITED_METHOD_CONTRACT;
2578
2579     // Verify that we got a valid offset
2580     _ASSERTE(FitsInThumb2BlRel24(imm24));
2581
2582 #if defined(_TARGET_ARM_)
2583     // Ensure that the ThumbBit is not set on the offset
2584     // as it cannot be encoded.
2585     _ASSERTE(!(imm24 & THUMB_CODE));
2586 #endif // _TARGET_ARM_    
2587
2588     USHORT Opcode0 = p[0];
2589     USHORT Opcode1 = p[1];
2590     Opcode0 &= 0xF800;
2591     Opcode1 &= 0xD000;
2592
2593     UINT32 S  =  (imm24 & 0x1000000) >> 24;
2594     UINT32 J1 = ((imm24 & 0x0800000) >> 23) ^ S ^ 1;
2595     UINT32 J2 = ((imm24 & 0x0400000) >> 22) ^ S ^ 1;
2596
2597     Opcode0 |=  ((imm24 & 0x03FF000) >> 12) | (S << 10);
2598     Opcode1 |=  ((imm24 & 0x0000FFE) >>  1) | (J1 << 13) | (J2 << 11);
2599
2600     p[0] = Opcode0;
2601     p[1] = Opcode1;
2602
2603     _ASSERTE(GetThumb2BlRel24(p) == imm24);
2604 }
2605
2606 //*****************************************************************************
2607 //  Extract the PC-Relative offset from a b or bl instruction 
2608 //*****************************************************************************
2609 INT32 GetArm64Rel28(UINT32 * pCode)
2610 {
2611     LIMITED_METHOD_CONTRACT;
2612
2613     UINT32 branchInstr = *pCode;
2614
2615     // first shift 6 bits left to set the sign bit, 
2616     // then arithmetic shift right by 4 bits 
2617     INT32 imm28 = (((INT32)(branchInstr & 0x03FFFFFF)) << 6) >> 4;
2618
2619     return imm28;
2620 }
2621
2622 //*****************************************************************************
2623 //  Extract the PC-Relative offset from an adrp instruction
2624 //*****************************************************************************
2625 INT32 GetArm64Rel21(UINT32 * pCode)
2626 {
2627     LIMITED_METHOD_CONTRACT;
2628
2629     UINT32 addInstr = *pCode;
2630
2631     // 23-5 bits for the high part. Shift it by 5.
2632     INT32 immhi = (((INT32)(addInstr & 0xFFFFE0))) >> 5;
2633     // 30,29 bits for the lower part. Shift it by 29.
2634     INT32 immlo = ((INT32)(addInstr & 0x60000000)) >> 29;
2635
2636     // Merge them
2637     INT32 imm21 = (immhi << 2) | immlo;
2638
2639     return imm21;
2640 }
2641
2642 //*****************************************************************************
2643 //  Extract the PC-Relative offset from an add instruction
2644 //*****************************************************************************
2645 INT32 GetArm64Rel12(UINT32 * pCode)
2646 {
2647     LIMITED_METHOD_CONTRACT;
2648
2649     UINT32 addInstr = *pCode;
2650
2651     // 21-10 contains value. Mask 12 bits and shift by 10 bits.
2652     INT32 imm12 = (INT32)(addInstr & 0x003FFC00) >> 10;
2653
2654     return imm12;
2655 }
2656
2657 //*****************************************************************************
2658 //  Deposit the PC-Relative offset 'imm28' into a b or bl instruction 
2659 //*****************************************************************************
2660 void PutArm64Rel28(UINT32 * pCode, INT32 imm28)
2661 {
2662     LIMITED_METHOD_CONTRACT;
2663
2664     // Verify that we got a valid offset
2665     _ASSERTE(FitsInRel28(imm28));
2666     _ASSERTE((imm28 & 0x3) == 0);    // the low two bits must be zero
2667
2668     UINT32 branchInstr = *pCode;
2669
2670     branchInstr &= 0xFC000000;       // keep bits 31-26
2671
2672     // Assemble the pc-relative delta 'imm28' into the branch instruction
2673     branchInstr |= ((imm28 >> 2) & 0x03FFFFFF);
2674
2675     *pCode = branchInstr;          // write the assembled instruction
2676
2677     _ASSERTE(GetArm64Rel28(pCode) == imm28);
2678 }
2679
2680 //*****************************************************************************
2681 //  Deposit the PC-Relative offset 'imm21' into an adrp instruction
2682 //*****************************************************************************
2683 void PutArm64Rel21(UINT32 * pCode, INT32 imm21)
2684 {
2685     LIMITED_METHOD_CONTRACT;
2686
2687     // Verify that we got a valid offset
2688     _ASSERTE(FitsInRel21(imm21));
2689
2690     UINT32 adrpInstr = *pCode;
2691     // Check adrp opcode 1ii1 0000 ...
2692     _ASSERTE((adrpInstr & 0x9F000000) == 0x90000000);
2693
2694     adrpInstr &= 0x9F00001F;               // keep bits 31, 28-24, 4-0.
2695     INT32 immlo = imm21 & 0x03;            // Extract low 2 bits which will occupy 30-29 bits.
2696     INT32 immhi = (imm21 & 0x1FFFFC) >> 2; // Extract high 19 bits which will occupy 23-5 bits.
2697     adrpInstr |= ((immlo << 29) | (immhi << 5));
2698
2699     *pCode = adrpInstr;                    // write the assembled instruction
2700
2701     _ASSERTE(GetArm64Rel21(pCode) == imm21);
2702 }
2703
2704 //*****************************************************************************
2705 //  Deposit the PC-Relative offset 'imm12' into an add instruction
2706 //*****************************************************************************
2707 void PutArm64Rel12(UINT32 * pCode, INT32 imm12)
2708 {
2709     LIMITED_METHOD_CONTRACT;
2710
2711     // Verify that we got a valid offset
2712     _ASSERTE(FitsInRel12(imm12));
2713
2714     UINT32 addInstr = *pCode;
2715     // Check add opcode 1001 0001 00...
2716     _ASSERTE((addInstr & 0xFFC00000) == 0x91000000);
2717
2718     addInstr &= 0xFFC003FF;     // keep bits 31-22, 9-0
2719     addInstr |= (imm12 << 10);  // Occupy 21-10.
2720
2721     *pCode = addInstr;          // write the assembled instruction
2722
2723     _ASSERTE(GetArm64Rel12(pCode) == imm12);
2724 }
2725
2726 //---------------------------------------------------------------------
2727 // Splits a command line into argc/argv lists, using the VC7 parsing rules.
2728 //
2729 // This functions interface mimics the CommandLineToArgvW api.
2730 //
2731 // If function fails, returns NULL.
2732 //
2733 // If function suceeds, call delete [] on return pointer when done.
2734 //
2735 //---------------------------------------------------------------------
2736 // NOTE: Implementation-wise, once every few years it would be a good idea to
2737 // compare this code with the C runtime library's parse_cmdline method,
2738 // which is in vctools\crt\crtw32\startup\stdargv.c.  (Note we don't
2739 // support wild cards, and we use Unicode characters exclusively.)
2740 // We are up to date as of ~6/2005.
2741 //---------------------------------------------------------------------
2742 LPWSTR *SegmentCommandLine(LPCWSTR lpCmdLine, DWORD *pNumArgs)
2743 {
2744     STATIC_CONTRACT_NOTHROW;
2745     STATIC_CONTRACT_GC_NOTRIGGER;
2746     STATIC_CONTRACT_FAULT;
2747
2748
2749     *pNumArgs = 0;
2750
2751     int nch = (int)wcslen(lpCmdLine);
2752
2753     // Calculate the worstcase storage requirement. (One pointer for
2754     // each argument, plus storage for the arguments themselves.)
2755     int cbAlloc = (nch+1)*sizeof(LPWSTR) + sizeof(WCHAR)*(nch + 1);
2756     LPWSTR pAlloc = new (nothrow) WCHAR[cbAlloc / sizeof(WCHAR)];
2757     if (!pAlloc)
2758         return NULL;
2759
2760     LPWSTR *argv = (LPWSTR*) pAlloc;  // We store the argv pointers in the first halt
2761     LPWSTR  pdst = (LPWSTR)( ((BYTE*)pAlloc) + sizeof(LPWSTR)*(nch+1) ); // A running pointer to second half to store arguments
2762     LPCWSTR psrc = lpCmdLine;
2763     WCHAR   c;
2764     BOOL    inquote;
2765     BOOL    copychar;
2766     int     numslash;
2767
2768     // First, parse the program name (argv[0]). Argv[0] is parsed under
2769     // special rules. Anything up to the first whitespace outside a quoted
2770     // subtring is accepted. Backslashes are treated as normal characters.
2771     argv[ (*pNumArgs)++ ] = pdst;
2772     inquote = FALSE;
2773     do {
2774         if (*psrc == W('"') )
2775         {
2776             inquote = !inquote;
2777             c = *psrc++;
2778             continue;
2779         }
2780         *pdst++ = *psrc;
2781
2782         c = *psrc++;
2783
2784     } while ( (c != W('\0') && (inquote || (c != W(' ') && c != W('\t')))) );
2785
2786     if ( c == W('\0') ) {
2787         psrc--;
2788     } else {
2789         *(pdst-1) = W('\0');
2790     }
2791
2792     inquote = FALSE;
2793
2794
2795
2796     /* loop on each argument */
2797     for(;;)
2798     {
2799         if ( *psrc )
2800         {
2801             while (*psrc == W(' ') || *psrc == W('\t'))
2802             {
2803                 ++psrc;
2804             }
2805         }
2806
2807         if (*psrc == W('\0'))
2808             break;              /* end of args */
2809
2810         /* scan an argument */
2811         argv[ (*pNumArgs)++ ] = pdst;
2812
2813         /* loop through scanning one argument */
2814         for (;;)
2815         {
2816             copychar = 1;
2817             /* Rules: 2N backslashes + " ==> N backslashes and begin/end quote
2818                2N+1 backslashes + " ==> N backslashes + literal "
2819                N backslashes ==> N backslashes */
2820             numslash = 0;
2821             while (*psrc == W('\\'))
2822             {
2823                 /* count number of backslashes for use below */
2824                 ++psrc;
2825                 ++numslash;
2826             }
2827             if (*psrc == W('"'))
2828             {
2829                 /* if 2N backslashes before, start/end quote, otherwise
2830                    copy literally */
2831                 if (numslash % 2 == 0)
2832                 {
2833                     if (inquote && psrc[1] == W('"'))
2834                     {
2835                         psrc++;    /* Double quote inside quoted string */
2836                     }
2837                     else
2838                     {
2839                         /* skip first quote char and copy second */
2840                         copychar = 0;       /* don't copy quote */
2841                         inquote = !inquote;
2842                     }
2843                 }
2844                 numslash /= 2;          /* divide numslash by two */
2845             }
2846     
2847             /* copy slashes */
2848             while (numslash--)
2849             {
2850                 *pdst++ = W('\\');
2851             }
2852     
2853             /* if at end of arg, break loop */
2854             if (*psrc == W('\0') || (!inquote && (*psrc == W(' ') || *psrc == W('\t'))))
2855                 break;
2856     
2857             /* copy character into argument */
2858             if (copychar)
2859             {
2860                 *pdst++ = *psrc;
2861             }
2862             ++psrc;
2863         }
2864
2865         /* null-terminate the argument */
2866
2867         *pdst++ = W('\0');          /* terminate string */
2868     }
2869
2870     /* We put one last argument in -- a null ptr */
2871     argv[ (*pNumArgs) ] = NULL;
2872
2873     // If we hit this assert, we overwrote our destination buffer.
2874     // Since we're supposed to allocate for the worst
2875     // case, either the parsing rules have changed or our worse case
2876     // formula is wrong.
2877     _ASSERTE((BYTE*)pdst <= (BYTE*)pAlloc + cbAlloc);
2878     return argv;
2879 }
2880
2881 Volatile<PVOID> ForbidCallsIntoHostOnThisThread::s_pvOwningFiber = NULL;
2882
2883 //======================================================================
2884 // This function returns true, if it can determine that the instruction pointer
2885 // refers to a code address that belongs in the range of the given image.
2886 // <TODO>@TODO: Merge with IsIPInModule from vm\util.hpp</TODO>
2887
2888 BOOL IsIPInModule(HMODULE_TGT hModule, PCODE ip)
2889 {
2890     STATIC_CONTRACT_LEAF;
2891     SUPPORTS_DAC;
2892
2893     struct Param
2894     {
2895         HMODULE_TGT hModule;
2896         PCODE ip;
2897         BOOL fRet;
2898     } param;
2899     param.hModule = hModule;
2900     param.ip = ip;
2901     param.fRet = FALSE;
2902
2903 // UNIXTODO: implement a proper version for PAL
2904 #ifndef FEATURE_PAL   
2905     PAL_TRY(Param *, pParam, &param)
2906     {
2907         PTR_BYTE pBase = dac_cast<PTR_BYTE>(pParam->hModule);
2908
2909         PTR_IMAGE_DOS_HEADER pDOS = NULL;
2910         PTR_IMAGE_NT_HEADERS pNT  = NULL;
2911         USHORT cbOptHdr;
2912         PCODE baseAddr;
2913         
2914         //
2915         // First, must validate the format of the PE headers to make sure that
2916         // the fields we're interested in using exist in the image.
2917         //
2918
2919         // Validate the DOS header.
2920         pDOS = PTR_IMAGE_DOS_HEADER(pBase);
2921         if (pDOS->e_magic != VAL16(IMAGE_DOS_SIGNATURE) ||
2922             pDOS->e_lfanew == 0)
2923         {
2924             goto lDone;
2925         }
2926
2927         // Validate the NT header
2928         pNT = PTR_IMAGE_NT_HEADERS(pBase + VAL32(pDOS->e_lfanew));
2929
2930         if (pNT->Signature != VAL32(IMAGE_NT_SIGNATURE))
2931         {
2932             goto lDone;
2933         }
2934
2935         // Validate that the optional header is large enough to contain the fields
2936         // we're interested, namely IMAGE_OPTIONAL_HEADER::SizeOfImage. The reason
2937         // we don't just check that SizeOfOptionalHeader == IMAGE_SIZEOF_NT_OPTIONAL_HEADER
2938         // is due to VSW443590, which states that the extensibility of this structure
2939         // is such that it is possible to include only a portion of the optional header.
2940         cbOptHdr = pNT->FileHeader.SizeOfOptionalHeader;
2941
2942         // Check that the magic field is contained by the optional header and set to the correct value.
2943         if (cbOptHdr < (offsetof(IMAGE_OPTIONAL_HEADER, Magic) + sizeofmember(IMAGE_OPTIONAL_HEADER, Magic)) ||
2944             pNT->OptionalHeader.Magic != VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC))
2945         {
2946             goto lDone;
2947         }
2948
2949         // Check that the SizeOfImage is contained by the optional header.
2950         if (cbOptHdr < (offsetof(IMAGE_OPTIONAL_HEADER, SizeOfImage) + sizeofmember(IMAGE_OPTIONAL_HEADER, SizeOfImage)))
2951         {
2952             goto lDone;
2953         }
2954
2955         //
2956         // The real check
2957         //
2958
2959         baseAddr = dac_cast<PCODE>(pBase);
2960         if ((pParam->ip < baseAddr) || (pParam->ip >= (baseAddr + VAL32(pNT->OptionalHeader.SizeOfImage))))
2961         {
2962             goto lDone;
2963         }
2964
2965         pParam->fRet = TRUE;
2966
2967 lDone: ;
2968     }
2969     PAL_EXCEPT (EXCEPTION_EXECUTE_HANDLER)
2970     {
2971     }
2972     PAL_ENDTRY
2973 #endif // !FEATURE_PAL    
2974
2975     return param.fRet;
2976 }
2977
2978 #ifdef FEATURE_CORRUPTING_EXCEPTIONS
2979
2980 // To include definition of EXCEPTION_SOFTSO
2981 #include "corexcep.h"
2982
2983 // These functions provide limited support for corrupting exceptions
2984 // outside the VM folder. Its limited since we don't have access to the
2985 // throwable.
2986 //
2987 // These functions are also wrapped by the corresponding CEHelper 
2988 // methods in excep.cpp.
2989
2990 // Given an exception code, this method returns a BOOL to indicate if the
2991 // code belongs to a corrupting exception or not.
2992 BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*=TRUE*/)
2993 {
2994     LIMITED_METHOD_CONTRACT;
2995
2996     // By default, assume its not corrupting
2997     BOOL fIsCorruptedStateException = FALSE;
2998
2999     if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 1)
3000     {
3001         return fIsCorruptedStateException;
3002     }
3003
3004     // If we have been asked not to include SO in the CSE check
3005     // and the code represent SO, then exit now.
3006     if ((fCheckForSO == FALSE) && (dwExceptionCode == STATUS_STACK_OVERFLOW))
3007     {
3008         return fIsCorruptedStateException;
3009     }
3010
3011     switch(dwExceptionCode)
3012     {
3013         case STATUS_ACCESS_VIOLATION:
3014         case STATUS_STACK_OVERFLOW:
3015         case EXCEPTION_ILLEGAL_INSTRUCTION:
3016         case EXCEPTION_IN_PAGE_ERROR:
3017         case EXCEPTION_INVALID_DISPOSITION:
3018         case EXCEPTION_NONCONTINUABLE_EXCEPTION:
3019         case EXCEPTION_PRIV_INSTRUCTION:
3020         case STATUS_UNWIND_CONSOLIDATE:
3021             fIsCorruptedStateException = TRUE;
3022             break;
3023     }
3024
3025     return fIsCorruptedStateException;
3026 }
3027
3028 #endif // FEATURE_CORRUPTING_EXCEPTIONS
3029
3030 void EnableTerminationOnHeapCorruption()
3031 {
3032     HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
3033 }
3034
3035 namespace Clr
3036 {
3037 namespace Util
3038 {
3039     static BOOL g_fLocalAppDataDirectoryInitted = FALSE;
3040     static WCHAR *g_wszLocalAppDataDirectory = NULL;
3041
3042 // This api returns a pointer to a null-terminated string that contains the local appdata directory
3043 // or it returns NULL in the case that the directory could not be found. The return value from this function
3044 // is not actually checked for existence. 
3045     HRESULT GetLocalAppDataDirectory(LPCWSTR *ppwzLocalAppDataDirectory)
3046     {
3047         CONTRACTL {
3048             NOTHROW;
3049             GC_NOTRIGGER;
3050         } CONTRACTL_END;
3051
3052         HRESULT hr = S_OK;
3053         *ppwzLocalAppDataDirectory = NULL;
3054
3055         EX_TRY
3056         {
3057             if (!g_fLocalAppDataDirectoryInitted)
3058             {
3059                 WCHAR *wszLocalAppData = NULL;
3060
3061                 DWORD cCharsNeeded;
3062                 cCharsNeeded = GetEnvironmentVariableW(W("LOCALAPPDATA"), NULL, 0);
3063
3064                 if ((cCharsNeeded != 0) && (cCharsNeeded < MAX_LONGPATH))
3065                 {
3066                     wszLocalAppData = new WCHAR[cCharsNeeded];
3067                     cCharsNeeded = GetEnvironmentVariableW(W("LOCALAPPDATA"), wszLocalAppData, cCharsNeeded);
3068                     if (cCharsNeeded != 0)
3069                     {
3070                         // We've collected the appropriate app data directory into a local. Now publish it.
3071                         if (InterlockedCompareExchangeT(&g_wszLocalAppDataDirectory, wszLocalAppData, NULL) == NULL)
3072                         {
3073                             // This variable doesn't need to be freed, as it has been stored in the global
3074                             wszLocalAppData = NULL;
3075                         }
3076                     }
3077                 }
3078
3079                 g_fLocalAppDataDirectoryInitted = TRUE;
3080                 delete[] wszLocalAppData;
3081             }
3082         }
3083         EX_CATCH_HRESULT(hr);
3084
3085         if (SUCCEEDED(hr))
3086             *ppwzLocalAppDataDirectory = g_wszLocalAppDataDirectory;
3087
3088         return hr;
3089     }
3090
3091     HRESULT SetLocalAppDataDirectory(LPCWSTR pwzLocalAppDataDirectory)
3092     {
3093         CONTRACTL {
3094             NOTHROW;
3095             GC_NOTRIGGER;
3096         } CONTRACTL_END;
3097
3098         if (pwzLocalAppDataDirectory == NULL || *pwzLocalAppDataDirectory == W('\0'))
3099             return E_INVALIDARG;
3100
3101         if (g_fLocalAppDataDirectoryInitted)
3102             return E_UNEXPECTED;
3103
3104         HRESULT hr = S_OK;
3105
3106         EX_TRY
3107         {
3108             size_t size = wcslen(pwzLocalAppDataDirectory) + 1;
3109             WCHAR *wszLocalAppData = new WCHAR[size];
3110             wcscpy_s(wszLocalAppData, size, pwzLocalAppDataDirectory);
3111
3112             // We've collected the appropriate app data directory into a local. Now publish it.
3113             if (InterlockedCompareExchangeT(&g_wszLocalAppDataDirectory, wszLocalAppData, NULL) != NULL)
3114             {
3115                 // Someone else already set LocalAppData. Free our copy and return an error.
3116                 delete[] wszLocalAppData;
3117                 hr = E_UNEXPECTED;
3118             }
3119
3120             g_fLocalAppDataDirectoryInitted = TRUE;
3121         }
3122         EX_CATCH_HRESULT(hr);
3123
3124         return hr;
3125     }
3126
3127 #ifndef FEATURE_PAL
3128     // Struct used to scope suspension of client impersonation for the current thread.
3129     // https://docs.microsoft.com/en-us/windows/desktop/secauthz/client-impersonation
3130     class SuspendImpersonation
3131     {
3132     public:
3133         SuspendImpersonation()
3134             : _token(nullptr)
3135         {
3136             // The approach used here matches what is used elsewhere in CLR (RevertIfImpersonated).
3137             // In general, OpenThreadToken fails with ERROR_NO_TOKEN if impersonation is not active,
3138             // fails with ERROR_CANT_OPEN_ANONYMOUS if anonymous impersonation is active, and otherwise
3139             // succeeds and returns the active impersonation token.
3140             BOOL res = ::OpenThreadToken(::GetCurrentThread(), TOKEN_IMPERSONATE, /* OpenAsSelf */ TRUE, &_token);
3141             if (res != FALSE)
3142             {
3143                 ::RevertToSelf();
3144             }
3145             else
3146             {
3147                 _token = nullptr;
3148             }
3149         }
3150
3151         ~SuspendImpersonation()
3152         {
3153             if (_token != nullptr)
3154                 ::SetThreadToken(nullptr, _token);
3155         }
3156
3157     private:
3158         HandleHolder _token;
3159     };
3160
3161     struct ProcessIntegrityResult
3162     {
3163         BOOL Success;
3164         DWORD Integrity;
3165         HRESULT LastError;
3166
3167         HRESULT RecordAndReturnError(HRESULT hr)
3168         {
3169             LastError = hr;
3170             return hr;
3171         }
3172     };
3173
3174     // The system calls in this code can fail if run with reduced privileges.
3175     // It is the caller's responsibility to choose an appropriate default in the event
3176     // that this function fails to retrieve the current process integrity.
3177     HRESULT GetCurrentProcessIntegrity(DWORD *integrity)
3178     {
3179         static ProcessIntegrityResult s_Result = { FALSE, 0, S_FALSE };
3180
3181         if (FALSE != InterlockedCompareExchangeT(&s_Result.Success, FALSE, FALSE))
3182         {
3183             *integrity = s_Result.Integrity;
3184             return S_OK;
3185         }
3186
3187         // Temporarily suspend impersonation (if possible) while computing the integrity level.
3188         // If impersonation is active, the OpenProcessToken call below will check the impersonation
3189         // token against the process token ACL, and will generally fail with ERROR_ACCESS_DENIED if
3190         // the impersonation token is less privileged than this process's primary token.
3191         Clr::Util::SuspendImpersonation si;
3192
3193         HandleHolder hToken;
3194         if(!OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &hToken))
3195             return s_Result.RecordAndReturnError(HRESULT_FROM_GetLastError());
3196
3197         DWORD dwSize = 0;
3198         DWORD err = ERROR_SUCCESS;
3199         if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, nullptr, 0, &dwSize))
3200             err = GetLastError();
3201
3202         // We need to make sure that GetTokenInformation failed in a predictable manner so we know that
3203         // dwSize has the correct buffer size in it.
3204         if (err != ERROR_INSUFFICIENT_BUFFER || dwSize == 0)
3205             return s_Result.RecordAndReturnError((err == ERROR_SUCCESS) ? E_FAIL : HRESULT_FROM_WIN32(err));
3206
3207         NewArrayHolder<BYTE> pLabel = new (nothrow) BYTE[dwSize];
3208         if (pLabel == NULL)
3209             return s_Result.RecordAndReturnError(E_OUTOFMEMORY);
3210
3211         if(!GetTokenInformation(hToken, (TOKEN_INFORMATION_CLASS)TokenIntegrityLevel, pLabel, dwSize, &dwSize))
3212             return s_Result.RecordAndReturnError(HRESULT_FROM_GetLastError());
3213
3214         TOKEN_MANDATORY_LABEL *ptml = (TOKEN_MANDATORY_LABEL *)(void*)pLabel;
3215         PSID psidIntegrityLevelLabel = ptml->Label.Sid;
3216
3217         s_Result.Integrity = *GetSidSubAuthority(psidIntegrityLevelLabel, (*GetSidSubAuthorityCount(psidIntegrityLevelLabel) - 1));
3218         *integrity = s_Result.Integrity;
3219         InterlockedExchangeT(&s_Result.Success, TRUE);
3220         return S_OK;
3221     }
3222
3223 namespace Reg
3224 {
3225     HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKeyName, LPCWSTR wszValueName, SString & ssValue)
3226     {
3227         STANDARD_VM_CONTRACT;
3228
3229         if (hKey == NULL)
3230         {
3231             return E_INVALIDARG;
3232         }
3233
3234         RegKeyHolder hTargetKey;
3235         if (wszSubKeyName == NULL || *wszSubKeyName == W('\0'))
3236         {   // No subkey was requested, use hKey as the resolved key.
3237             hTargetKey = hKey;
3238             hTargetKey.SuppressRelease();
3239         }
3240         else
3241         {   // Try to open the specified subkey.
3242             if (WszRegOpenKeyEx(hKey, wszSubKeyName, 0, KEY_READ, &hTargetKey) != ERROR_SUCCESS)
3243                 return REGDB_E_CLASSNOTREG;
3244         }
3245
3246         DWORD type;
3247         DWORD size;
3248         if ((WszRegQueryValueEx(hTargetKey, wszValueName, 0, &type, 0, &size) == ERROR_SUCCESS) &&
3249             type == REG_SZ && size > 0)
3250         {
3251             LPWSTR wszValueBuf = ssValue.OpenUnicodeBuffer(static_cast<COUNT_T>((size / sizeof(WCHAR)) - 1));
3252             LONG lResult = WszRegQueryValueEx(
3253                 hTargetKey,
3254                 wszValueName,
3255                 0,
3256                 0,
3257                 reinterpret_cast<LPBYTE>(wszValueBuf),
3258                 &size);
3259
3260             _ASSERTE(lResult == ERROR_SUCCESS);
3261             if (lResult == ERROR_SUCCESS)
3262             {
3263                 // Can't count on the returned size being accurate - I've seen at least
3264                 // one string with an extra NULL at the end that will cause the resulting
3265                 // SString to count the extra NULL as part of the string. An extra
3266                 // terminating NULL is not a legitimate scenario for REG_SZ - this must
3267                 // be done using REG_MULTI_SZ - however this was tolerated in the
3268                 // past and so it would be a breaking change to stop doing so.
3269                 _ASSERTE(wcslen(wszValueBuf) <= (size / sizeof(WCHAR)) - 1);
3270                 ssValue.CloseBuffer((COUNT_T)wcsnlen(wszValueBuf, (size_t)size));
3271             }
3272             else
3273             {
3274                 ssValue.CloseBuffer(0);
3275                 return HRESULT_FROM_WIN32(lResult);
3276             }
3277
3278             return S_OK;
3279         }
3280         else
3281         {
3282             return REGDB_E_KEYMISSING;
3283         }
3284     }
3285
3286     HRESULT ReadStringValue(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, __deref_out __deref_out_z LPWSTR* pwszValue)
3287     {
3288         CONTRACTL {
3289             NOTHROW;
3290             GC_NOTRIGGER;
3291         } CONTRACTL_END;
3292
3293         HRESULT hr = S_OK;
3294         EX_TRY
3295         {
3296             StackSString ssValue;
3297             if (SUCCEEDED(hr = ReadStringValue(hKey, wszSubKey, wszName, ssValue)))
3298             {
3299                 *pwszValue = new WCHAR[ssValue.GetCount() + 1];
3300                 wcscpy_s(*pwszValue, ssValue.GetCount() + 1, ssValue.GetUnicode());
3301             }
3302         }
3303         EX_CATCH_HRESULT(hr);
3304         return hr;
3305     }
3306 } // namespace Reg
3307
3308 namespace Com
3309 {
3310     namespace __imp
3311     {
3312         __success(return == S_OK)
3313         static
3314         HRESULT FindSubKeyDefaultValueForCLSID(REFCLSID rclsid, LPCWSTR wszSubKeyName, SString & ssValue)
3315         {
3316             STANDARD_VM_CONTRACT;
3317
3318             WCHAR wszClsid[39];
3319             if (GuidToLPWSTR(rclsid, wszClsid, NumItems(wszClsid)) == 0)
3320                 return E_UNEXPECTED;
3321
3322             StackSString ssKeyName;
3323             ssKeyName.Append(SL(W("CLSID\\")));
3324             ssKeyName.Append(wszClsid);
3325             ssKeyName.Append(SL(W("\\")));
3326             ssKeyName.Append(wszSubKeyName);
3327
3328             // Query HKCR first to retain backwards compat with previous implementation where HKCR was only queried.
3329             // This is being done due to registry caching. This value will be used if the process integrity is medium or less.
3330             HRESULT hkcrResult = Clr::Util::Reg::ReadStringValue(HKEY_CLASSES_ROOT, ssKeyName.GetUnicode(), nullptr, ssValue);
3331
3332             // HKCR is a virtualized registry hive that weaves together HKCU\Software\Classes and HKLM\Software\Classes
3333             // Processes with high integrity or greater should only read from HKLM to avoid being hijacked by medium
3334             // integrity processes writing to HKCU.
3335             DWORD integrity = SECURITY_MANDATORY_PROTECTED_PROCESS_RID;
3336             HRESULT hr = Clr::Util::GetCurrentProcessIntegrity(&integrity);
3337             if (hr != S_OK)
3338             {
3339                 // In the event that we are unable to get the current process integrity,
3340                 // we assume that this process is running in an elevated state.
3341                 // GetCurrentProcessIntegrity may fail if the process has insufficient rights to get the integrity level
3342                 integrity = SECURITY_MANDATORY_PROTECTED_PROCESS_RID;
3343             }
3344
3345             if (integrity > SECURITY_MANDATORY_MEDIUM_RID)
3346             {
3347                 Clr::Util::SuspendImpersonation si;
3348
3349                 // Clear the previous HKCR queried value
3350                 ssValue.Clear();
3351
3352                 // Force to use HKLM
3353                 StackSString ssHklmKeyName(SL(W("SOFTWARE\\Classes\\")));
3354                 ssHklmKeyName.Append(ssKeyName);
3355                 return Clr::Util::Reg::ReadStringValue(HKEY_LOCAL_MACHINE, ssHklmKeyName.GetUnicode(), nullptr, ssValue);
3356             }
3357
3358             return hkcrResult;
3359         }
3360     }
3361
3362     HRESULT FindInprocServer32UsingCLSID(REFCLSID rclsid, SString & ssInprocServer32Name)
3363     {
3364         WRAPPER_NO_CONTRACT;
3365         return __imp::FindSubKeyDefaultValueForCLSID(rclsid, W("InprocServer32"), ssInprocServer32Name);
3366     }
3367 } // namespace Com
3368 #endif //  FEATURE_PAL
3369
3370 namespace Win32
3371 {
3372     void GetModuleFileName(
3373         HMODULE hModule,
3374         SString & ssFileName,
3375         bool fAllowLongFileNames)
3376     {
3377         STANDARD_VM_CONTRACT;
3378
3379         // Try to use what the SString already has allocated. If it does not have anything allocated
3380         // or it has < 20 characters allocated, then bump the size requested to _MAX_PATH.
3381         
3382         DWORD dwResult = WszGetModuleFileName(hModule, ssFileName);
3383
3384
3385         if (dwResult == 0)
3386             ThrowHR(HRESULT_FROM_GetLastError());
3387
3388         _ASSERTE(dwResult != 0 );
3389     }
3390
3391     // Returns heap-allocated string in *pwszFileName
3392     HRESULT GetModuleFileName(
3393         HMODULE hModule,
3394         __deref_out_z LPWSTR * pwszFileName,
3395         bool fAllowLongFileNames)
3396     {
3397         CONTRACTL {
3398             NOTHROW;
3399             GC_NOTRIGGER;
3400             PRECONDITION(CheckPointer(pwszFileName));
3401         } CONTRACTL_END;
3402
3403         HRESULT hr = S_OK;
3404         EX_TRY
3405         {
3406             InlineSString<_MAX_PATH> ssFileName;
3407             GetModuleFileName(hModule, ssFileName);
3408             *pwszFileName = DuplicateStringThrowing(ssFileName.GetUnicode());
3409         }
3410         EX_CATCH_HRESULT(hr);
3411
3412         return hr;
3413     }
3414
3415     void GetFullPathName(
3416         SString const & ssFileName,
3417         SString & ssPathName,
3418         DWORD * pdwFilePartIdx,
3419         bool fAllowLongFileNames)
3420     {
3421         STANDARD_VM_CONTRACT;
3422
3423         // Get the required buffer length (including terminating NULL).
3424         DWORD dwLengthRequired = WszGetFullPathName(ssFileName.GetUnicode(), 0, NULL, NULL);
3425
3426         if (dwLengthRequired == 0)
3427             ThrowHR(HRESULT_FROM_GetLastError());
3428
3429         LPWSTR wszPathName = ssPathName.OpenUnicodeBuffer(dwLengthRequired - 1);
3430         LPWSTR wszFileName = NULL;
3431         DWORD dwLengthWritten = WszGetFullPathName(
3432             ssFileName.GetUnicode(),
3433             dwLengthRequired,
3434             wszPathName,
3435             &wszFileName);
3436
3437         // Calculate the index while the buffer is open and the string pointer is stable.
3438         if (dwLengthWritten != 0 && dwLengthWritten < dwLengthRequired && pdwFilePartIdx != NULL)
3439             *pdwFilePartIdx = static_cast<DWORD>(wszFileName - wszPathName);
3440
3441         ssPathName.CloseBuffer(dwLengthWritten < dwLengthRequired ? dwLengthWritten : 0);
3442
3443         if (dwLengthRequired == 0)
3444             ThrowHR(HRESULT_FROM_GetLastError());
3445
3446         // Overly defensive? Perhaps.
3447         if (!(dwLengthWritten < dwLengthRequired))
3448             ThrowHR(E_UNEXPECTED);
3449     }
3450 } // namespace Win32
3451
3452 } // namespace Util
3453 } // namespace Clr