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
6//
7
8#include "stdafx.h"
9
10#include "unsafe.h"
11#include "clrhost.h"
12#include "utilcode.h"
13#include "ex.h"
14#include "hostimpl.h"
15#include "clrnt.h"
16#include "contract.h"
17
18#if defined __llvm__
19# if defined(__has_feature) && __has_feature(address_sanitizer)
20# define HAS_ADDRESS_SANITIZER
21# endif
22#endif
23
24#ifdef _DEBUG_IMPL
25
26//
27// I'd very much like for this to go away. Its used to disable all THROWS contracts within whatever DLL this
28// function is called from. That's obviously very, very bad, since there's no validation of those macros. But it
29// can be difficult to remove this without actually fixing every violation at the same time.
30//
31// When this flag is finally removed, remove RealCLRThrowsExceptionWorker() too and put CONTRACT_THROWS() in place
32// of it.
33//
34//
35static BOOL dbg_fDisableThrowCheck = FALSE;
36
37void DisableThrowCheck()
38{
39 LIMITED_METHOD_CONTRACT;
40
41 dbg_fDisableThrowCheck = TRUE;
42}
43
44#ifdef HAS_ADDRESS_SANITIZER
45// use the functionality from address santizier (which does not throw exceptions)
46#else
47
48#define CLRThrowsExceptionWorker() RealCLRThrowsExceptionWorker(__FUNCTION__, __FILE__, __LINE__)
49
50static void RealCLRThrowsExceptionWorker(__in_z const char *szFunction,
51 __in_z const char *szFile,
52 int lineNum)
53{
54 WRAPPER_NO_CONTRACT;
55
56 if (dbg_fDisableThrowCheck)
57 {
58 return;
59 }
60
61 CONTRACT_THROWSEX(szFunction, szFile, lineNum);
62}
63
64#endif // HAS_ADDRESS_SANITIZER
65#endif //_DEBUG_IMPL
66
67#if defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
68
69// Fls callback to deallocate ClrDebugState when our FLS block goes away.
70void FreeClrDebugState(LPVOID pTlsData)
71{
72#ifdef _DEBUG
73 ClrDebugState *pClrDebugState = (ClrDebugState*)pTlsData;
74
75 // Make sure the ClrDebugState was initialized by a compatible version of
76 // utilcode.lib. If it was initialized by an older version, we just let it leak.
77 if (pClrDebugState && (pClrDebugState->ViolationMask() & CanFreeMe) && !(pClrDebugState->ViolationMask() & BadDebugState))
78 {
79#undef HeapFree
80#undef GetProcessHeap
81
82 // Since "!(pClrDebugState->m_violationmask & BadDebugState)", we know we have
83 // a valid m_pLockData
84 _ASSERTE(pClrDebugState->GetDbgStateLockData() != NULL);
85 ::HeapFree (GetProcessHeap(), 0, pClrDebugState->GetDbgStateLockData());
86
87 ::HeapFree (GetProcessHeap(), 0, pClrDebugState);
88#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
89#define GetProcessHeap() Dont_Use_GetProcessHeap()
90 }
91#endif //_DEBUG
92}
93
94// This is a drastic shutoff toggle that forces all new threads to fail their CLRInitDebugState calls.
95// We only invoke this if FLS can't allocate its master block, preventing us from tracking the shutoff
96// on a per-thread basis.
97BYTE* GetGlobalContractShutoffFlag()
98{
99#ifdef SELF_NO_HOST
100
101 static BYTE gGlobalContractShutoffFlag = 0;
102 return &gGlobalContractShutoffFlag;
103#else //!SELF_NO_HOST
104 HINSTANCE hmod = GetCLRModule();
105 if (!hmod)
106 {
107 return NULL;
108 }
109 typedef BYTE*(__stdcall * PGETSHUTOFFADDRFUNC)();
110 PGETSHUTOFFADDRFUNC pGetContractShutoffFlagFunc = (PGETSHUTOFFADDRFUNC)GetProcAddress(hmod, "GetAddrOfContractShutoffFlag");
111 if (!pGetContractShutoffFlagFunc)
112 {
113 return NULL;
114 }
115 return pGetContractShutoffFlagFunc();
116#endif //!SELF_NO_HOST
117}
118
119static BOOL AreContractsShutoff()
120{
121 BYTE *pShutoff = GetGlobalContractShutoffFlag();
122 if (!pShutoff)
123 {
124 return FALSE;
125 }
126 else
127 {
128 return 0 != *pShutoff;
129 }
130}
131
132static VOID ShutoffContracts()
133{
134 BYTE *pShutoff = GetGlobalContractShutoffFlag();
135 if (pShutoff)
136 {
137 *pShutoff = 1;
138 }
139}
140
141//=============================================================================================
142// Used to initialize the per-thread ClrDebugState. This is called once per thread (with
143// possible exceptions for OOM scenarios.)
144//
145// No matter what, this function will not return NULL. If it can't do its job because of OOM reasons,
146// it will return a pointer to &gBadClrDebugState which effectively disables contracts for
147// this thread.
148//=============================================================================================
149ClrDebugState *CLRInitDebugState()
150{
151 // workaround!
152 //
153 // The existing Fls apis didn't provide the support we need and adding support cleanly is
154 // messy because of the brittleness of IExecutionEngine.
155 //
156 // To understand this function, you need to know that the Fls routines have special semantics
157 // for the TlsIdx_ClrDebugState slot:
158 //
159 // - FlsSetValue will never throw. If it fails due to OOM on creation of the slot storage,
160 // it will silently bail. Thus, we must do a confirming FlsGetValue before we can conclude
161 // that the SetValue succeeded.
162 //
163 // - FlsAssociateCallback will not complain about multiple sets of the callback.
164 //
165 // - The mscorwks implemention of FlsAssociateCallback will ignore the passed in value
166 // and use the version of FreeClrDebugState compiled into mscorwks. This is needed to
167 // avoid dangling pointer races on shutdown.
168
169
170 // This is our global "bad" debug state that thread use when they OOM on CLRInitDebugState.
171 // We really only need to initialize it once but initializing each time is convenient
172 // and has low perf impact.
173 static ClrDebugState gBadClrDebugState;
174 gBadClrDebugState.ViolationMaskSet( AllViolation );
175 // SO_INFRASTRUCTURE_CODE() Macro to remove SO infrastructure code during build
176 SO_INFRASTRUCTURE_CODE(gBadClrDebugState.BeginSOTolerant();)
177 gBadClrDebugState.SetOkToThrow();
178
179 ClrDebugState *pNewClrDebugState = NULL;
180 ClrDebugState *pClrDebugState = NULL;
181 DbgStateLockData *pNewLockData = NULL;
182
183 // We call this first partly to force a CheckThreadState. We've hopefully chased out all the
184 // recursive contract calls inside here but if we haven't, it's best to get them out of the way
185 // early.
186 ClrFlsAssociateCallback(TlsIdx_ClrDebugState, FreeClrDebugState);
187
188
189 if (AreContractsShutoff())
190 {
191 pNewClrDebugState = NULL;
192 }
193 else
194 {
195 // Yuck. We cannot call the hosted allocator for ClrDebugState (it is impossible to maintain a guarantee
196 // that none of code paths, many of them called conditionally, don't themselves trigger a ClrDebugState creation.)
197 // We have to call the OS directly for this.
198#undef HeapAlloc
199#undef GetProcessHeap
200 pNewClrDebugState = (ClrDebugState*)::HeapAlloc(GetProcessHeap(), 0, sizeof(ClrDebugState));
201 if (pNewClrDebugState != NULL)
202 {
203 // Only allocate a DbgStateLockData if its owning ClrDebugState was successfully allocated
204 pNewLockData = (DbgStateLockData *)::HeapAlloc(GetProcessHeap(), 0, sizeof(DbgStateLockData));
205 }
206#define GetProcessHeap() Dont_Use_GetProcessHeap()
207#define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
208
209 if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
210 {
211 // Both allocations succeeded, so initialize the structures, and have
212 // pNewClrDebugState point to pNewLockData. If either of the allocations
213 // failed, we'll use gBadClrDebugState for this thread, and free whichever of
214 // pNewClrDebugState or pNewLockData actually did get allocated (if either did).
215 // (See code in this function below, outside this block.)
216
217 pNewClrDebugState->SetStartingValues();
218 pNewClrDebugState->ViolationMaskSet( CanFreeMe );
219 _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
220
221 pNewLockData->SetStartingValues();
222 pNewClrDebugState->SetDbgStateLockData(pNewLockData);
223 }
224 }
225
226
227 // This is getting really diseased. All the one-time host init stuff inside the ClrFlsStuff could actually
228 // have caused mscorwks contracts to be executed since the last time we actually checked to see if the ClrDebugState
229 // needed creating.
230 //
231 // So we must make one last check to see if the ClrDebugState still needs creating.
232 //
233 ClrDebugState *pTmp = (ClrDebugState*)(ClrFlsGetValue(TlsIdx_ClrDebugState));
234 if (pTmp != NULL)
235 {
236 // Recursive call set up ClrDebugState for us
237 pClrDebugState = pTmp;
238 }
239 else if ((pNewClrDebugState != NULL) && (pNewLockData != NULL))
240 {
241 // Normal case: our new ClrDebugState will be the one we just allocated.
242 // Note that we require BOTH the ClrDebugState and the DbgStateLockData
243 // structures to have been successfully allocated for contracts to be
244 // enabled for this thread.
245 _ASSERTE(!(pNewClrDebugState->ViolationMask() & BadDebugState));
246 _ASSERTE(pNewClrDebugState->GetDbgStateLockData() == pNewLockData);
247 pClrDebugState = pNewClrDebugState;
248 }
249 else
250 {
251 // OOM case: HeapAlloc of newClrDebugState failed.
252 pClrDebugState = &gBadClrDebugState;
253 }
254
255 _ASSERTE(pClrDebugState != NULL);
256
257
258 ClrFlsSetValue(TlsIdx_ClrDebugState, (LPVOID)pClrDebugState);
259
260 // For the ClrDebugState index, ClrFlsSetValue does *not* throw on OOM.
261 // Instead, it silently throws away the value. So we must now do a confirming
262 // FlsGet to learn if our Set succeeded.
263 if (ClrFlsGetValue(TlsIdx_ClrDebugState) == NULL)
264 {
265 // Our FlsSet didn't work. That means it couldn't allocate the master FLS block for our thread.
266 // Now we're a bad state because not only can't we succeed, we can't record that we didn't succeed.
267 // And it's invalid to return a BadClrDebugState here only to return a good debug state later.
268 //
269 // So we now take the drastic step of forcing all future ClrInitDebugState calls to return the OOM state.
270 ShutoffContracts();
271 pClrDebugState = &gBadClrDebugState;
272
273 // Try once more time to set the FLS (if it doesn't work, the next call will keep cycling through here
274 // until it does succeed.)
275 ClrFlsSetValue(TlsIdx_ClrDebugState, &gBadClrDebugState);
276 }
277
278
279#if defined(_DEBUG)
280 // The ClrDebugState we allocated above made it into FLS iff
281 // the DbgStateLockData we allocated above made it into
282 // the FLS's ClrDebugState::m_pLockData
283 // These debug-only checks enforce this invariant
284
285 if (pClrDebugState != NULL)
286 {
287 // If we're here, then typically pClrDebugState is what's in FLS. However,
288 // it's possible that pClrDebugState is gBadClrDebugState, and FLS is NULL
289 // (if the last ClrFlsSetValue() failed). Either way, our checks below
290 // are valid ones to make.
291
292 if (pClrDebugState == pNewClrDebugState)
293 {
294 // ClrDebugState we allocated above made it into FLS, so DbgStateLockData
295 // must be there, too
296 _ASSERTE(pNewLockData != NULL);
297 _ASSERTE(pClrDebugState->GetDbgStateLockData() == pNewLockData);
298 }
299 else
300 {
301 // ClrDebugState we allocated above did NOT make it into FLS,
302 // so the DbgStateLockData we allocated must not be there, either
303 _ASSERTE(pClrDebugState->GetDbgStateLockData() == NULL || pClrDebugState->GetDbgStateLockData() != pNewLockData);
304 }
305 }
306
307 // One more invariant: Because of ordering & conditions around the HeapAllocs above,
308 // we'll never have a DbgStateLockData without a ClrDebugState
309 _ASSERTE((pNewLockData == NULL) || (pNewClrDebugState != NULL));
310
311#endif //_DEBUG
312
313#undef HeapFree
314#undef GetProcessHeap
315 if (pNewClrDebugState != NULL && pClrDebugState != pNewClrDebugState)
316 {
317 // We allocated a ClrDebugState which didn't make it into FLS, so free it.
318 ::HeapFree (GetProcessHeap(), 0, pNewClrDebugState);
319 if (pNewLockData != NULL)
320 {
321 // We also allocated a DbgStateLockData that didn't make it into FLS, so
322 // free it, too. (Remember, we asserted above that we can only have
323 // this unused DbgStateLockData if we had an unused ClrDebugState
324 // as well (which we just freed).)
325 ::HeapFree (GetProcessHeap(), 0, pNewLockData);
326 }
327 }
328#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
329#define GetProcessHeap() Dont_Use_GetProcessHeap()
330
331 // Not necessary as TLS slots are born NULL and potentially problematic for OOM cases as we can't
332 // take an exception here.
333 //ClrFlsSetValue(TlsIdx_OwnedCrstsChain, NULL);
334
335 return pClrDebugState;
336} // CLRInitDebugState
337
338#endif //defined(_DEBUG_IMPL) && defined(ENABLE_CONTRACTS_IMPL)
339
340
341LPVOID ClrAllocInProcessHeapBootstrap (DWORD dwFlags, SIZE_T dwBytes)
342{
343 STATIC_CONTRACT_SO_INTOLERANT;
344
345#if defined(SELF_NO_HOST)
346 static HANDLE hHeap = NULL;
347
348 // This could race, but the result would be that this
349 // variable gets double initialized.
350 if (hHeap == NULL)
351 hHeap = ClrGetProcessHeap();
352
353 return ClrHeapAlloc(hHeap, dwFlags, S_SIZE_T(dwBytes));
354#else //!defined(SELF_NO_HOST)
355 FastAllocInProcessHeapFunc pfnHeapAlloc = (FastAllocInProcessHeapFunc)
356 GetClrCallbacks().m_pfnGetCLRFunction("EEHeapAllocInProcessHeap");
357 if (pfnHeapAlloc != NULL)
358 {
359 __ClrAllocInProcessHeap = pfnHeapAlloc;
360 return pfnHeapAlloc(dwFlags, dwBytes);
361 }
362 return ClrHeapAlloc(ClrGetProcessHeap(), dwFlags, S_SIZE_T(dwBytes));
363#endif // !defined(SELF_NO_HOST)
364}
365FastAllocInProcessHeapFunc __ClrAllocInProcessHeap = (FastAllocInProcessHeapFunc) ClrAllocInProcessHeapBootstrap;
366
367BOOL ClrFreeInProcessHeapBootstrap (DWORD dwFlags, LPVOID lpMem)
368{
369 STATIC_CONTRACT_SO_INTOLERANT;
370
371#if defined(SELF_NO_HOST)
372 static HANDLE hHeap = NULL;
373
374 // This could race, but the result would be that this
375 // variable gets double initialized.
376 if (hHeap == NULL)
377 hHeap = ClrGetProcessHeap();
378
379 return ClrHeapFree(hHeap, dwFlags,lpMem);
380#else //!defined(SELF_NO_HOST)
381 FastFreeInProcessHeapFunc pfnHeapFree = (FastFreeInProcessHeapFunc)
382 GetClrCallbacks().m_pfnGetCLRFunction("EEHeapFreeInProcessHeap");
383 if (pfnHeapFree)
384 {
385 __ClrFreeInProcessHeap = pfnHeapFree;
386 return (*pfnHeapFree)(dwFlags,lpMem);
387 }
388 return ClrHeapFree(ClrGetProcessHeap(),dwFlags,lpMem);
389#endif //!defined(SELF_NO_HOST)
390}
391FastFreeInProcessHeapFunc __ClrFreeInProcessHeap = (FastFreeInProcessHeapFunc) ClrFreeInProcessHeapBootstrap;
392
393const NoThrow nothrow = { 0 };
394
395#ifdef HAS_ADDRESS_SANITIZER
396// use standard heap functions for address santizier
397#else
398
399void * __cdecl
400operator new(size_t n)
401{
402#ifdef _DEBUG_IMPL
403 CLRThrowsExceptionWorker();
404#endif
405
406 STATIC_CONTRACT_THROWS;
407 STATIC_CONTRACT_GC_NOTRIGGER;
408 STATIC_CONTRACT_FAULT;
409 STATIC_CONTRACT_SO_TOLERANT; // The memory allocation itself should be SO-tolerant. But we must protect the use of it.
410 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
411
412 void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
413 if (result == NULL) {
414 ThrowOutOfMemory();
415 }
416 TRASH_LASTERROR;
417 return result;
418}
419
420void * __cdecl
421operator new[](size_t n)
422{
423#ifdef _DEBUG_IMPL
424 CLRThrowsExceptionWorker();
425#endif
426
427 STATIC_CONTRACT_THROWS;
428 STATIC_CONTRACT_GC_NOTRIGGER;
429 STATIC_CONTRACT_FAULT;
430 STATIC_CONTRACT_SO_TOLERANT; // The memory allocation itself should be SO-tolerant. But we must protect the use of it.
431 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
432
433 void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
434 if (result == NULL) {
435 ThrowOutOfMemory();
436 }
437 TRASH_LASTERROR;
438 return result;
439};
440
441#endif // HAS_ADDRESS_SANITIZER
442
443void * __cdecl operator new(size_t n, const NoThrow&) NOEXCEPT
444{
445#ifdef HAS_ADDRESS_SANITIZER
446 // use standard heap functions for address santizier (which doesn't provide for NoThrow)
447 void * result = operator new(n);
448#else
449 STATIC_CONTRACT_NOTHROW;
450 STATIC_CONTRACT_GC_NOTRIGGER;
451 STATIC_CONTRACT_FAULT;
452 STATIC_CONTRACT_SO_TOLERANT; // The memory allocation itself should be SO-tolerant. But we must protect the use of it.
453 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
454
455 INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
456
457 void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
458#endif // HAS_ADDRESS_SANITIZER
459 TRASH_LASTERROR;
460 return result;
461}
462
463void * __cdecl operator new[](size_t n, const NoThrow&) NOEXCEPT
464{
465#ifdef HAS_ADDRESS_SANITIZER
466 // use standard heap functions for address santizier (which doesn't provide for NoThrow)
467 void * result = operator new[](n);
468#else
469 STATIC_CONTRACT_NOTHROW;
470 STATIC_CONTRACT_GC_NOTRIGGER;
471 STATIC_CONTRACT_FAULT;
472 STATIC_CONTRACT_SO_TOLERANT; // The memory allocation itself should be SO-tolerant. But we must protect the use of it.
473 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
474
475 INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
476
477 void * result = ClrAllocInProcessHeap(0, S_SIZE_T(n));
478#endif // HAS_ADDRESS_SANITIZER
479 TRASH_LASTERROR;
480 return result;
481}
482
483#ifdef HAS_ADDRESS_SANITIZER
484// use standard heap functions for address santizier
485#else
486void __cdecl
487operator delete(void *p) NOEXCEPT
488{
489 STATIC_CONTRACT_NOTHROW;
490 STATIC_CONTRACT_GC_NOTRIGGER;
491 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
492 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
493
494 if (p != NULL)
495 ClrFreeInProcessHeap(0, p);
496 TRASH_LASTERROR;
497}
498
499void __cdecl
500operator delete[](void *p) NOEXCEPT
501{
502 STATIC_CONTRACT_NOTHROW;
503 STATIC_CONTRACT_GC_NOTRIGGER;
504 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
505 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
506
507 if (p != NULL)
508 ClrFreeInProcessHeap(0, p);
509 TRASH_LASTERROR;
510}
511
512#endif // HAS_ADDRESS_SANITIZER
513
514
515/* ------------------------------------------------------------------------ *
516 * New operator overloading for the executable heap
517 * ------------------------------------------------------------------------ */
518
519#ifndef FEATURE_PAL
520
521const CExecutable executable = { 0 };
522
523void * __cdecl operator new(size_t n, const CExecutable&)
524{
525#if defined(_DEBUG_IMPL)
526 CLRThrowsExceptionWorker();
527#endif
528
529 STATIC_CONTRACT_THROWS;
530 STATIC_CONTRACT_GC_NOTRIGGER;
531 STATIC_CONTRACT_FAULT;
532 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
533
534 HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
535 if (hExecutableHeap == NULL) {
536 ThrowOutOfMemory();
537 }
538
539 void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
540 if (result == NULL) {
541 ThrowOutOfMemory();
542 }
543 TRASH_LASTERROR;
544 return result;
545}
546
547void * __cdecl operator new[](size_t n, const CExecutable&)
548{
549#if defined(_DEBUG_IMPL)
550 CLRThrowsExceptionWorker();
551#endif
552
553 STATIC_CONTRACT_THROWS;
554 STATIC_CONTRACT_GC_NOTRIGGER;
555 STATIC_CONTRACT_FAULT;
556 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
557
558 HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
559 if (hExecutableHeap == NULL) {
560 ThrowOutOfMemory();
561 }
562
563 void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
564 if (result == NULL) {
565 ThrowOutOfMemory();
566 }
567 TRASH_LASTERROR;
568 return result;
569}
570
571void * __cdecl operator new(size_t n, const CExecutable&, const NoThrow&)
572{
573 STATIC_CONTRACT_NOTHROW;
574 STATIC_CONTRACT_GC_NOTRIGGER;
575 STATIC_CONTRACT_FAULT;
576 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
577
578 INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
579
580 HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
581 if (hExecutableHeap == NULL)
582 return NULL;
583
584 void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
585 TRASH_LASTERROR;
586 return result;
587}
588
589void * __cdecl operator new[](size_t n, const CExecutable&, const NoThrow&)
590{
591 STATIC_CONTRACT_NOTHROW;
592 STATIC_CONTRACT_GC_NOTRIGGER;
593 STATIC_CONTRACT_FAULT;
594 STATIC_CONTRACT_SO_TOLERANT; // The memory management routines should be SO-tolerant.
595
596 INCONTRACT(_ASSERTE(!ARE_FAULTS_FORBIDDEN()));
597
598 HANDLE hExecutableHeap = ClrGetProcessExecutableHeap();
599 if (hExecutableHeap == NULL)
600 return NULL;
601
602 void * result = ClrHeapAlloc(hExecutableHeap, 0, S_SIZE_T(n));
603 TRASH_LASTERROR;
604 return result;
605}
606
607#endif // FEATURE_PAL
608
609#ifdef _DEBUG
610
611// This is a DEBUG routing to verify that a memory region complies with executable requirements
612BOOL DbgIsExecutable(LPVOID lpMem, SIZE_T length)
613{
614#if defined(CROSSGEN_COMPILE) || defined(FEATURE_PAL)
615 // No NX support on PAL or for crossgen compilations.
616 return TRUE;
617#else // !(CROSSGEN_COMPILE || FEATURE_PAL)
618 BYTE *regionStart = (BYTE*) ALIGN_DOWN((BYTE*)lpMem, GetOsPageSize());
619 BYTE *regionEnd = (BYTE*) ALIGN_UP((BYTE*)lpMem+length, GetOsPageSize());
620 _ASSERTE(length > 0);
621 _ASSERTE(regionStart < regionEnd);
622
623 while(regionStart < regionEnd)
624 {
625 MEMORY_BASIC_INFORMATION mbi;
626
627 SIZE_T cbBytes = ClrVirtualQuery(regionStart, &mbi, sizeof(mbi));
628 _ASSERTE(cbBytes);
629
630 // The pages must have EXECUTE set
631 if(!(mbi.Protect & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)))
632 return FALSE;
633
634 _ASSERTE((BYTE*)mbi.BaseAddress + mbi.RegionSize > regionStart);
635 regionStart = (BYTE*)mbi.BaseAddress + mbi.RegionSize;
636 }
637
638 return TRUE;
639#endif // CROSSGEN_COMPILE || FEATURE_PAL
640}
641
642#endif //_DEBUG
643
644
645
646
647// Access various ExecutionEngine support services, like a logical TLS that abstracts
648// fiber vs. thread issues. We obtain it from a DLL export via the shim.
649
650typedef IExecutionEngine * (__stdcall * IEE_FPTR) ();
651
652//
653// Access various ExecutionEngine support services, like a logical TLS that abstracts
654// fiber vs. thread issues.
655// From an IExecutionEngine is possible to get other services via QueryInterfaces such
656// as memory management
657//
658IExecutionEngine *g_pExecutionEngine = NULL;
659
660#ifdef SELF_NO_HOST
661BYTE g_ExecutionEngineInstance[sizeof(UtilExecutionEngine)];
662#endif
663
664
665IExecutionEngine *GetExecutionEngine()
666{
667 STATIC_CONTRACT_NOTHROW;
668 STATIC_CONTRACT_GC_NOTRIGGER;
669 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
670 STATIC_CONTRACT_SO_TOLERANT;
671 SUPPORTS_DAC_HOST_ONLY;
672
673 if (g_pExecutionEngine == NULL)
674 {
675 IExecutionEngine* pExecutionEngine;
676#ifdef SELF_NO_HOST
677 // Create a local copy on the stack and then copy it over to the static instance.
678 // This avoids race conditions caused by multiple initializations of vtable in the constructor
679 UtilExecutionEngine local;
680 memcpy((void*)&g_ExecutionEngineInstance, (void*)&local, sizeof(UtilExecutionEngine));
681 pExecutionEngine = (IExecutionEngine*)(UtilExecutionEngine*)&g_ExecutionEngineInstance;
682#else
683 // statically linked.
684 VALIDATECORECLRCALLBACKS();
685 pExecutionEngine = g_CoreClrCallbacks.m_pfnIEE();
686#endif // SELF_NO_HOST
687
688 //We use an explicit memory barrier here so that the reference g_pExecutionEngine is valid when
689 //it is used, This ia a requirement on platforms with weak memory model . We cannot use VolatileStore
690 //because they are the same as normal assignment for DAC builds [see code:VOLATILE]
691
692 MemoryBarrier();
693 g_pExecutionEngine = pExecutionEngine;
694 }
695
696 // It's a bug to ask for the ExecutionEngine interface in scenarios where the
697 // ExecutionEngine cannot be loaded.
698 _ASSERTE(g_pExecutionEngine);
699 return g_pExecutionEngine;
700} // GetExecutionEngine
701
702IEEMemoryManager * GetEEMemoryManager()
703{
704 STATIC_CONTRACT_SO_TOLERANT;
705 STATIC_CONTRACT_GC_NOTRIGGER;
706 STATIC_CONTRACT_NOTHROW;
707 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
708 SUPPORTS_DAC_HOST_ONLY;
709
710 static IEEMemoryManager *pEEMemoryManager = NULL;
711 if (NULL == pEEMemoryManager) {
712 IExecutionEngine *pExecutionEngine = GetExecutionEngine();
713 _ASSERTE(pExecutionEngine);
714
715 // It is dangerous to pass a global pointer to QueryInterface. The pointer may be set
716 // to NULL in the call. Imagine that thread 1 calls QI, and get a pointer. But before thread 1
717 // returns the pointer to caller, thread 2 calls QI and the pointer is set to NULL.
718 IEEMemoryManager *pEEMM;
719 pExecutionEngine->QueryInterface(IID_IEEMemoryManager, (void**)&pEEMM);
720 pEEMemoryManager = pEEMM;
721 }
722 // It's a bug to ask for the MemoryManager interface in scenarios where it cannot be loaded.
723 _ASSERTE(pEEMemoryManager);
724 return pEEMemoryManager;
725}
726
727// should return some error code or exception
728void SetExecutionEngine(IExecutionEngine *pExecutionEngine)
729{
730 STATIC_CONTRACT_NOTHROW;
731 STATIC_CONTRACT_GC_NOTRIGGER;
732
733 _ASSERTE(pExecutionEngine && !g_pExecutionEngine);
734 if (!g_pExecutionEngine) {
735 g_pExecutionEngine = pExecutionEngine;
736 g_pExecutionEngine->AddRef();
737 }
738}
739
740void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback)
741{
742 WRAPPER_NO_CONTRACT;
743
744 GetExecutionEngine()->TLS_AssociateCallback(slot, callback);
745}
746
747LPVOID *ClrFlsGetBlockGeneric()
748{
749 WRAPPER_NO_CONTRACT;
750 STATIC_CONTRACT_SO_TOLERANT;
751
752 return (LPVOID *) GetExecutionEngine()->TLS_GetDataBlock();
753}
754
755CLRFLSGETBLOCK __ClrFlsGetBlock = ClrFlsGetBlockGeneric;
756
757CRITSEC_COOKIE ClrCreateCriticalSection(CrstType crstType, CrstFlags flags)
758{
759 WRAPPER_NO_CONTRACT;
760
761 return GetExecutionEngine()->CreateLock(NULL, (LPCSTR)crstType, flags);
762}
763
764HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie)
765{
766 WRAPPER_NO_CONTRACT;
767 GetExecutionEngine()->DestroyLock(cookie);
768 return S_OK;
769}
770
771void ClrEnterCriticalSection(CRITSEC_COOKIE cookie)
772{
773 WRAPPER_NO_CONTRACT;
774
775 return GetExecutionEngine()->AcquireLock(cookie);
776}
777
778void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie)
779{
780 WRAPPER_NO_CONTRACT;
781
782 return GetExecutionEngine()->ReleaseLock(cookie);
783}
784
785EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState)
786{
787 WRAPPER_NO_CONTRACT;
788
789 return GetExecutionEngine()->CreateAutoEvent(bInitialState);
790}
791
792EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState)
793{
794 WRAPPER_NO_CONTRACT;
795
796 return GetExecutionEngine()->CreateManualEvent(bInitialState);
797}
798
799void ClrCloseEvent(EVENT_COOKIE event)
800{
801 WRAPPER_NO_CONTRACT;
802
803 GetExecutionEngine()->CloseEvent(event);
804}
805
806BOOL ClrSetEvent(EVENT_COOKIE event)
807{
808 WRAPPER_NO_CONTRACT;
809
810 return GetExecutionEngine()->ClrSetEvent(event);
811}
812
813BOOL ClrResetEvent(EVENT_COOKIE event)
814{
815 WRAPPER_NO_CONTRACT;
816
817 return GetExecutionEngine()->ClrResetEvent(event);
818}
819
820DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable)
821{
822 WRAPPER_NO_CONTRACT;
823
824 return GetExecutionEngine()->WaitForEvent(event, dwMilliseconds, bAlertable);
825}
826
827SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax)
828{
829 WRAPPER_NO_CONTRACT;
830
831 return GetExecutionEngine()->ClrCreateSemaphore(dwInitial, dwMax);
832}
833
834void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore)
835{
836 WRAPPER_NO_CONTRACT;
837
838 GetExecutionEngine()->ClrCloseSemaphore(semaphore);
839}
840
841BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount)
842{
843 WRAPPER_NO_CONTRACT;
844
845 return GetExecutionEngine()->ClrReleaseSemaphore(semaphore, lReleaseCount, lpPreviousCount);
846}
847
848DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable)
849{
850 WRAPPER_NO_CONTRACT;
851
852 return GetExecutionEngine()->ClrWaitForSemaphore(semaphore, dwMilliseconds, bAlertable);
853}
854
855MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,
856 BOOL bInitialOwner,
857 LPCTSTR lpName)
858{
859 WRAPPER_NO_CONTRACT;
860
861 return GetExecutionEngine()->ClrCreateMutex(lpMutexAttributes, bInitialOwner, lpName);
862}
863
864void ClrCloseMutex(MUTEX_COOKIE mutex)
865{
866 WRAPPER_NO_CONTRACT;
867
868 GetExecutionEngine()->ClrCloseMutex(mutex);
869}
870
871BOOL ClrReleaseMutex(MUTEX_COOKIE mutex)
872{
873 WRAPPER_NO_CONTRACT;
874
875 return GetExecutionEngine()->ClrReleaseMutex(mutex);
876}
877
878DWORD ClrWaitForMutex(MUTEX_COOKIE mutex, DWORD dwMilliseconds, BOOL bAlertable)
879{
880 WRAPPER_NO_CONTRACT;
881
882 return GetExecutionEngine()->ClrWaitForMutex(mutex, dwMilliseconds, bAlertable);
883}
884
885DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable)
886{
887 WRAPPER_NO_CONTRACT;
888
889 return GetExecutionEngine()->ClrSleepEx(dwMilliseconds, bAlertable);
890}
891
892LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect)
893{
894 WRAPPER_NO_CONTRACT;
895
896 LPVOID result = GetEEMemoryManager()->ClrVirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect);
897 LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualAlloc (0x%p, 0x%06x, 0x%06x, 0x%02x) = 0x%p\n", lpAddress, dwSize, flAllocationType, flProtect, result));
898
899 return result;
900}
901
902BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType)
903{
904 WRAPPER_NO_CONTRACT;
905
906 LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualFree (0x%p, 0x%06x, 0x%04x)\n", lpAddress, dwSize, dwFreeType));
907 BOOL result = GetEEMemoryManager()->ClrVirtualFree(lpAddress, dwSize, dwFreeType);
908
909 return result;
910}
911
912SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength)
913{
914 WRAPPER_NO_CONTRACT;
915
916 LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualQuery (0x%p)\n", lpAddress));
917 return GetEEMemoryManager()->ClrVirtualQuery(lpAddress, lpBuffer, dwLength);
918}
919
920BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect)
921{
922 WRAPPER_NO_CONTRACT;
923
924 LOG((LF_EEMEM, LL_INFO100000, "ClrVirtualProtect(0x%p, 0x%06x, 0x%02x)\n", lpAddress, dwSize, flNewProtect));
925 return GetEEMemoryManager()->ClrVirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
926}
927
928HANDLE ClrGetProcessHeap()
929{
930 WRAPPER_NO_CONTRACT;
931
932 return GetEEMemoryManager()->ClrGetProcessHeap();
933}
934
935HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize)
936{
937 WRAPPER_NO_CONTRACT;
938
939 return GetEEMemoryManager()->ClrHeapCreate(flOptions, dwInitialSize, dwMaximumSize);
940}
941
942BOOL ClrHeapDestroy(HANDLE hHeap)
943{
944 WRAPPER_NO_CONTRACT;
945
946 return GetEEMemoryManager()->ClrHeapDestroy(hHeap);
947}
948
949LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes)
950{
951 WRAPPER_NO_CONTRACT;
952
953 if(dwBytes.IsOverflow()) return NULL;
954
955 LPVOID result = GetEEMemoryManager()->ClrHeapAlloc(hHeap, dwFlags, dwBytes.Value());
956
957 return result;
958}
959
960BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem)
961{
962 WRAPPER_NO_CONTRACT;
963
964 BOOL result = GetEEMemoryManager()->ClrHeapFree(hHeap, dwFlags, lpMem);
965
966 return result;
967}
968
969BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem)
970{
971 WRAPPER_NO_CONTRACT;
972
973 return GetEEMemoryManager()->ClrHeapValidate(hHeap, dwFlags, lpMem);
974}
975
976HANDLE ClrGetProcessExecutableHeap()
977{
978 WRAPPER_NO_CONTRACT;
979
980 return GetEEMemoryManager()->ClrGetProcessExecutableHeap();
981}
982
983void GetLastThrownObjectExceptionFromThread(void **ppvException)
984{
985 WRAPPER_NO_CONTRACT;
986
987 GetExecutionEngine()->GetLastThrownObjectExceptionFromThread(ppvException);
988}
989