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
9#ifndef __CLRHOST_H__
10#define __CLRHOST_H__
11
12#include "windows.h" // worth to include before mscoree.h so we are guaranteed to pick few definitions
13#ifdef CreateSemaphore
14#undef CreateSemaphore
15#endif
16#include "mscoree.h"
17#include "clrinternal.h"
18#include "switches.h"
19#include "holder.h"
20#include "new.hpp"
21#include "staticcontract.h"
22#include "predeftlsslot.h"
23#include "safemath.h"
24#include "debugreturn.h"
25
26#if !defined(_DEBUG_IMPL) && defined(_DEBUG) && !defined(DACCESS_COMPILE)
27#define _DEBUG_IMPL 1
28#endif
29
30#define BEGIN_PRESERVE_LAST_ERROR \
31 { \
32 DWORD __dwLastError = ::GetLastError(); \
33 DEBUG_ASSURE_NO_RETURN_BEGIN(PRESERVE_LAST_ERROR); \
34 {
35
36#define END_PRESERVE_LAST_ERROR \
37 } \
38 DEBUG_ASSURE_NO_RETURN_END(PRESERVE_LAST_ERROR); \
39 ::SetLastError(__dwLastError); \
40 }
41
42//
43// TRASH_LASTERROR macro sets bogus last error in debug builds to help find places that fail to save it
44//
45#ifdef _DEBUG
46
47#define LAST_ERROR_TRASH_VALUE 42424 /* = 0xa5b8 */
48
49#define TRASH_LASTERROR \
50 SetLastError(LAST_ERROR_TRASH_VALUE)
51
52#else // _DEBUG
53
54#define TRASH_LASTERROR
55
56#endif // _DEBUG
57
58IExecutionEngine *GetExecutionEngine();
59IEEMemoryManager *GetEEMemoryManager();
60
61LPVOID ClrVirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect);
62BOOL ClrVirtualFree(LPVOID lpAddress, SIZE_T dwSize, DWORD dwFreeType);
63SIZE_T ClrVirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer, SIZE_T dwLength);
64BOOL ClrVirtualProtect(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
65LPVOID ClrDebugAlloc (size_t size, LPCSTR pszFile, int iLineNo);
66HANDLE ClrGetProcessHeap();
67HANDLE ClrHeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximumSize);
68BOOL ClrHeapDestroy(HANDLE hHeap);
69LPVOID ClrHeapAlloc(HANDLE hHeap, DWORD dwFlags, S_SIZE_T dwBytes);
70BOOL ClrHeapFree(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem);
71BOOL ClrHeapValidate(HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);
72HANDLE ClrGetProcessExecutableHeap();
73
74
75#ifdef FAILPOINTS_ENABLED
76extern int RFS_HashStack();
77#endif
78
79
80void ClrFlsAssociateCallback(DWORD slot, PTLS_CALLBACK_FUNCTION callback);
81
82typedef LPVOID* (*CLRFLSGETBLOCK)();
83extern CLRFLSGETBLOCK __ClrFlsGetBlock;
84
85// Combining getter/setter into a single call
86inline void ClrFlsIncrementValue(DWORD slot, int increment)
87{
88 STATIC_CONTRACT_NOTHROW;
89 STATIC_CONTRACT_GC_NOTRIGGER;
90 STATIC_CONTRACT_MODE_ANY;
91 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
92 STATIC_CONTRACT_SO_TOLERANT;
93
94 _ASSERTE(increment != 0);
95
96 void **block = (*__ClrFlsGetBlock)();
97 size_t value;
98
99 if (block != NULL)
100 {
101 value = (size_t) block[slot];
102
103 _ASSERTE((increment > 0) || (value + increment < value));
104 block[slot] = (void *) (value + increment);
105 }
106 else
107 {
108 BEGIN_PRESERVE_LAST_ERROR;
109
110 ANNOTATION_VIOLATION(SOToleranceViolation);
111
112 IExecutionEngine * pEngine = GetExecutionEngine();
113 value = (size_t) pEngine->TLS_GetValue(slot);
114
115 _ASSERTE((increment > 0) || (value + increment < value));
116 pEngine->TLS_SetValue(slot, (void *) (value + increment));
117
118 END_PRESERVE_LAST_ERROR;
119 }
120}
121
122
123inline void * ClrFlsGetValue (DWORD slot)
124{
125 STATIC_CONTRACT_NOTHROW;
126 STATIC_CONTRACT_GC_NOTRIGGER;
127 STATIC_CONTRACT_MODE_ANY;
128 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
129 STATIC_CONTRACT_SO_TOLERANT;
130
131 void **block = (*__ClrFlsGetBlock)();
132 if (block != NULL)
133 {
134 return block[slot];
135 }
136 else
137 {
138 ANNOTATION_VIOLATION(SOToleranceViolation);
139
140 void * value = GetExecutionEngine()->TLS_GetValue(slot);
141 return value;
142 }
143}
144
145
146inline BOOL ClrFlsCheckValue(DWORD slot, void ** pValue)
147{
148 STATIC_CONTRACT_NOTHROW;
149 STATIC_CONTRACT_GC_NOTRIGGER;
150 STATIC_CONTRACT_MODE_ANY;
151 STATIC_CONTRACT_SO_TOLERANT;
152
153#ifdef _DEBUG
154 *pValue = ULongToPtr(0xcccccccc);
155#endif //_DEBUG
156 void **block = (*__ClrFlsGetBlock)();
157 if (block != NULL)
158 {
159 *pValue = block[slot];
160 return TRUE;
161 }
162 else
163 {
164 ANNOTATION_VIOLATION(SOToleranceViolation);
165 BOOL result = GetExecutionEngine()->TLS_CheckValue(slot, pValue);
166 return result;
167 }
168}
169
170inline void ClrFlsSetValue(DWORD slot, void *pData)
171{
172 STATIC_CONTRACT_NOTHROW;
173 STATIC_CONTRACT_GC_NOTRIGGER;
174 STATIC_CONTRACT_MODE_ANY;
175 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
176 STATIC_CONTRACT_SO_TOLERANT;
177
178 void **block = (*__ClrFlsGetBlock)();
179 if (block != NULL)
180 {
181 block[slot] = pData;
182 }
183 else
184 {
185 BEGIN_PRESERVE_LAST_ERROR;
186
187 ANNOTATION_VIOLATION(SOToleranceViolation);
188 GetExecutionEngine()->TLS_SetValue(slot, pData);
189
190 END_PRESERVE_LAST_ERROR;
191 }
192}
193
194typedef LPVOID (*FastAllocInProcessHeapFunc)(DWORD dwFlags, SIZE_T dwBytes);
195extern FastAllocInProcessHeapFunc __ClrAllocInProcessHeap;
196inline LPVOID ClrAllocInProcessHeap(DWORD dwFlags, S_SIZE_T dwBytes)
197{
198 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
199 if (dwBytes.IsOverflow())
200 {
201 return NULL;
202 }
203
204#ifndef SELF_NO_HOST
205 return __ClrAllocInProcessHeap(dwFlags, dwBytes.Value());
206#else
207#undef HeapAlloc
208#undef GetProcessHeap
209 static HANDLE ProcessHeap = NULL;
210 if (ProcessHeap == NULL)
211 ProcessHeap = GetProcessHeap();
212 return ::HeapAlloc(ProcessHeap,dwFlags,dwBytes.Value());
213#define HeapAlloc(hHeap, dwFlags, dwBytes) Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
214#define GetProcessHeap() Dont_Use_GetProcessHeap()
215#endif
216}
217
218typedef BOOL (*FastFreeInProcessHeapFunc)(DWORD dwFlags, LPVOID lpMem);
219extern FastFreeInProcessHeapFunc __ClrFreeInProcessHeap;
220inline BOOL ClrFreeInProcessHeap(DWORD dwFlags, LPVOID lpMem)
221{
222 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
223#ifndef SELF_NO_HOST
224 return __ClrFreeInProcessHeap(dwFlags, lpMem);
225#else
226#undef HeapFree
227#undef GetProcessHeap
228 static HANDLE ProcessHeap = NULL;
229 if (ProcessHeap == NULL)
230 ProcessHeap = GetProcessHeap();
231 return (BOOL)(BYTE)::HeapFree(ProcessHeap, dwFlags, lpMem);
232#define HeapFree(hHeap, dwFlags, lpMem) Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
233#define GetProcessHeap() Dont_Use_GetProcessHeap()
234#endif
235}
236
237// Critical section support for CLR DLLs other than the the EE.
238// Include the header defining each Crst type and its corresponding level (relative rank). This is
239// auto-generated from a tool that takes a high-level description of each Crst type and its dependencies.
240#include "crsttypes.h"
241
242// critical section api
243CRITSEC_COOKIE ClrCreateCriticalSection(CrstType type, CrstFlags flags);
244HRESULT ClrDeleteCriticalSection(CRITSEC_COOKIE cookie);
245void ClrEnterCriticalSection(CRITSEC_COOKIE cookie);
246void ClrLeaveCriticalSection(CRITSEC_COOKIE cookie);
247
248// event api
249EVENT_COOKIE ClrCreateAutoEvent(BOOL bInitialState);
250EVENT_COOKIE ClrCreateManualEvent(BOOL bInitialState);
251void ClrCloseEvent(EVENT_COOKIE event);
252BOOL ClrSetEvent(EVENT_COOKIE event);
253BOOL ClrResetEvent(EVENT_COOKIE event);
254DWORD ClrWaitEvent(EVENT_COOKIE event, DWORD dwMilliseconds, BOOL bAlertable);
255
256// semaphore api
257SEMAPHORE_COOKIE ClrCreateSemaphore(DWORD dwInitial, DWORD dwMax);
258void ClrCloseSemaphore(SEMAPHORE_COOKIE semaphore);
259BOOL ClrReleaseSemaphore(SEMAPHORE_COOKIE semaphore, LONG lReleaseCount, LONG *lpPreviousCount);
260DWORD ClrWaitSemaphore(SEMAPHORE_COOKIE semaphore, DWORD dwMilliseconds, BOOL bAlertable);
261
262// mutex api
263MUTEX_COOKIE ClrCreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes,BOOL bInitialOwner,LPCTSTR lpName);
264void ClrCloseMutex(MUTEX_COOKIE mutex);
265BOOL ClrReleaseMutex(MUTEX_COOKIE mutex);
266DWORD ClrWaitForMutex(MUTEX_COOKIE mutex,DWORD dwMilliseconds,BOOL bAlertable);
267DWORD ClrSleepEx(DWORD dwMilliseconds, BOOL bAlertable);
268
269// Rather than use the above APIs directly, it is recommended that holder classes
270// be used. This guarantees that the locks will be vacated when the scope is popped,
271// either on exception or on return.
272
273typedef Holder<CRITSEC_COOKIE, ClrEnterCriticalSection, ClrLeaveCriticalSection, NULL> CRITSEC_Holder;
274
275// Use this holder to manage CRITSEC_COOKIE allocation to ensure it will be released if anything goes wrong
276FORCEINLINE void VoidClrDeleteCriticalSection(CRITSEC_COOKIE cs) { if (cs != NULL) ClrDeleteCriticalSection(cs); }
277typedef Wrapper<CRITSEC_COOKIE, DoNothing<CRITSEC_COOKIE>, VoidClrDeleteCriticalSection, NULL> CRITSEC_AllocationHolder;
278
279class Event {
280public:
281 Event ()
282 : m_event(NULL)
283 {STATIC_CONTRACT_LEAF;}
284 ~Event ()
285 {
286 STATIC_CONTRACT_WRAPPER;
287 CloseEvent();
288 }
289
290 void CreateAutoEvent(BOOL bInitialState)
291 {
292 STATIC_CONTRACT_WRAPPER;
293 m_event = ClrCreateAutoEvent(bInitialState);
294 }
295 void CreateManualEvent(BOOL bInitialState)
296 {
297 STATIC_CONTRACT_WRAPPER;
298 m_event = ClrCreateManualEvent(bInitialState);
299 }
300 void CloseEvent()
301 {
302 STATIC_CONTRACT_WRAPPER;
303 if (m_event != NULL)
304 ClrCloseEvent(m_event);
305 m_event = NULL;
306 }
307
308 BOOL Set()
309 {
310 STATIC_CONTRACT_WRAPPER;
311 return ClrSetEvent(m_event);
312 }
313 BOOL Reset()
314 {
315 STATIC_CONTRACT_WRAPPER;
316 return ClrResetEvent(m_event);
317 }
318 DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable)
319 {
320 STATIC_CONTRACT_WRAPPER;
321 return ClrWaitEvent(m_event, dwMilliseconds, bAlertable);
322 }
323
324private:
325 EVENT_COOKIE m_event;
326};
327
328class Semaphore {
329public:
330 Semaphore ()
331 : m_semaphore(NULL)
332 {STATIC_CONTRACT_LEAF;}
333 ~Semaphore ()
334 {
335 STATIC_CONTRACT_WRAPPER;
336 Close();
337 }
338
339 void Create(DWORD dwInitial, DWORD dwMax)
340 {
341 STATIC_CONTRACT_WRAPPER;
342 m_semaphore = ClrCreateSemaphore(dwInitial, dwMax);
343 }
344 void Close()
345 {
346 STATIC_CONTRACT_WRAPPER;
347 if (m_semaphore != NULL)
348 ClrCloseSemaphore(m_semaphore);
349 m_semaphore = NULL;
350 }
351
352 BOOL Release(LONG lReleaseCount, LONG* lpPreviousCount)
353 {
354 STATIC_CONTRACT_WRAPPER;
355 return ClrReleaseSemaphore(m_semaphore, lReleaseCount, lpPreviousCount);
356 }
357 DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable)
358 {
359 STATIC_CONTRACT_WRAPPER;
360 return ClrWaitSemaphore(m_semaphore, dwMilliseconds, bAlertable);
361 }
362
363private:
364 SEMAPHORE_COOKIE m_semaphore;
365};
366
367HMODULE GetCLRModule ();
368
369#ifndef FEATURE_NO_HOST
370/*
371 Here we start the list of functions we want to deprecate.
372 We use a define to generate a linker error.
373 We must insure to include the header file that has the definition we are about
374 to deprecate before we use the #define otherwise we will run into a linker error
375 when legitimately undef'ing the function
376*/
377
378//
379// following are windows deprecates
380//
381#include <windows.h>
382
383/*
384 If you are reading this, you have probably tracked down the fact that memory Alloc,
385 etc. don't work inside your DLL because you are using src\inc & src\utilcode
386 services.
387 You need to use the ClrXXX equivalent functions to properly guarantee your code
388 works correctly wrt hosting and others execution engine requirements.
389 Check the list of Clr functions above
390*/
391
392#define GetProcessHeap() \
393 Dont_Use_GetProcessHeap()
394
395#define VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect) \
396 Dont_Use_VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect)
397
398#define VirtualFree(lpAddress, dwSize, dwFreeType) \
399 Dont_Use_VirtualFree(lpAddress, dwSize, dwFreeType)
400
401#define VirtualQuery(lpAddress, lpBuffer, dwLength) \
402 Dont_Use_VirtualQuery(lpAddress, lpBuffer, dwLength)
403
404#define VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect) \
405 Dont_Use_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect)
406
407#define HeapCreate(flOptions, dwInitialSize, dwMaximumSize) \
408 Dont_Use_HeapCreate(flOptions, dwInitialSize, dwMaximumSize)
409
410#define HeapDestroy(hHeap) \
411 Dont_Use_HeapDestroy(hHeap)
412
413#define HeapAlloc(hHeap, dwFlags, dwBytes) \
414 Dont_Use_HeapAlloc(hHeap, dwFlags, dwBytes)
415
416#define HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes) \
417 Dont_Use_HeapReAlloc(hHeap, dwFlags, lpMem, dwBytes)
418
419#define HeapFree(hHeap, dwFlags, lpMem) \
420 Dont_Use_HeapFree(hHeap, dwFlags, lpMem)
421
422#define HeapValidate(hHeap, dwFlags, lpMem) \
423 Dont_Use_HeapValidate(hHeap, dwFlags, lpMem)
424
425#define LocalAlloc(uFlags, uBytes) \
426 Dont_Use_LocalAlloc(uFlags, uBytes)
427
428#define LocalFree(hMem) \
429 Dont_Use_LocalFree(hMem)
430
431#define LocalReAlloc(hMem, uBytes, uFlags) \
432 Dont_Use_LocalReAlloc(hMem, uBytes, uFlags)
433
434#define GlobalAlloc(uFlags, dwBytes) \
435 Dont_Use_GlobalAlloc(uFlags, dwBytes)
436
437#define GlobalFree(hMem) \
438 Dont_Use_GlobalFree(hMem)
439
440//#define ExitThread Dont_Use_ExitThread
441
442#define ExitProcess Dont_Use_ExitProcess
443
444/*
445 If you are reading this, you have probably tracked down the fact that TlsAlloc,
446 etc. don't work inside your DLL because you are using src\inc & src\utilcode
447 services.
448
449 This is because the CLR can operate in a fiberized environment under host control.
450 When this is the case, logical thread local storage must be fiber-relative rather
451 than thread-relative.
452
453 Although the OS provides FLS routines on .NET Server, it does not yet provide
454 those services on WinXP or Win2K. So you cannot just use fiber routines from
455 the OS.
456
457 Instead, you must use the ClrFls_ routines described above. However, there are
458 some important differences between these EE-provided services and the OS TLS
459 services that you are used to:
460
461 1) There is no TlsAlloc/FlsAlloc equivalent. You must statically describe
462 your needs via the PredefinedTlsSlots below. If you have dynamic requirements,
463 you should give yourself a single static slot and then build your dynamic
464 requirements on top of this. The lack of a dynamic API is a deliberate
465 choice on my part, rather than lack of time.
466
467 2) You can provide a cleanup routine, which we will call on your behalf. However,
468 this can be called on a different thread than the "thread" (fiber or thread)
469 which holds the data. It can be called after that thread has actually been
470 terminated. It can be called before you see a DLL_THREAD_DETACH on your
471 physical thread. The circumstances vary based on whether the process is hosted
472 and based on whether TS_WeOwn is set on the internal Thread object. Make
473 no assumptions here.
474*/
475#define TlsAlloc() \
476 Dont_Use_TlsAlloc()
477
478#define TlsSetValue(dwTlsIndex, lpTlsValue) \
479 Dont_Use_TlsSetValue(dwTlsIndex, lpTlsValue)
480
481#define TlsGetValue(dwTlsIndex) \
482 Dont_Use_TlsGetValue(dwTlsIndex)
483
484#define TlsFree(dwTlsIndex) \
485 Dont_Use_TlsFree(dwTlsIndex)
486
487
488/*
489 If you are reading this, you have probably tracked down the fact that synchronization objects
490 and critical sections don't work inside your DLL because you are using src\inc & src\utilcode services.
491 Please refer to the ClrXXX functions described above to make proper use of synchronization obejct, etc.
492
493 Also it's extremely useful to look at the Holder classes defined above.
494 Those classes provide a nice encapsulation for synchronization object that allows automatic release of locks.
495*/
496#define InitializeCriticalSection(lpCriticalSection) \
497 Dont_Use_InitializeCriticalSection(lpCriticalSection)
498
499#define InitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount) \
500 Dont_Use_InitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount)
501
502#define DeleteCriticalSection(lpCriticalSection) \
503 Dont_Use_DeleteCriticalSection(lpCriticalSection)
504
505#define EnterCriticalSection(lpCriticalSection) \
506 Dont_Use_EnterCriticalSection(lpCriticalSection)
507
508#define TryEnterCriticalSection(lpCriticalSection) \
509 Dont_Use_TryEnterCriticalSection(lpCriticalSection)
510
511#define LeaveCriticalSection(lpCriticalSection) \
512 Dont_Use_LeaveCriticalSection(lpCriticalSection)
513
514#ifdef CreateEvent
515#undef CreateEvent
516#endif
517#define CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName) \
518 Dont_Use_CreateEvent(lpEventAttributes, bManualReset, bInitialState, lpName)
519
520#ifdef OpenEvent
521#undef OpenEvent
522#endif
523#define OpenEvent(dwDesiredAccess, bInheritHandle, lpName) \
524 Dont_Use_OpenEvent(dwDesiredAccess, bInheritHandle, lpName)
525
526#define ResetEvent(hEvent) \
527 Dont_Use_ResetEvent(hEvent)
528
529#define SetEvent(hEvent) \
530 Dont_Use_SetEvent(hEvent)
531
532#define PulseEvent(hEvent) \
533 Dont_Use_PulseEvent(hEvent)
534
535#ifdef CreateSemaphore
536#undef CreateSemaphore
537#endif
538#define CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName) \
539 Dont_Use_CreateSemaphore(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName)
540
541#ifdef OpenSemaphore
542#undef OpenSemaphore
543#endif
544#define OpenSemaphore(dwDesiredAccess, bInheritHandle, lpName) \
545 Dont_Use_OpenSemaphore(dwDesiredAccess, bInheritHandle, lpName)
546
547#define ReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount) \
548 Dont_Use_ReleaseSemaphore(hSemaphore, lReleaseCount, lpPreviousCount)
549
550#ifdef Sleep
551#undef Sleep
552#endif
553#define Sleep(dwMilliseconds) \
554 Dont_Use_Sleep(dwMilliseconds)
555
556#ifdef SleepEx
557#undef SleepEx
558#endif
559#define SleepEx(dwMilliseconds,bAlertable) \
560 Dont_Use_SleepEx(dwMilliseconds,bAlertable)
561
562//
563// following are clib deprecates
564//
565#include <stdlib.h>
566#include <malloc.h>
567
568#ifdef malloc
569#undef malloc
570#endif
571
572#define _CRT_EXCEPTION_NO_MALLOC
573#define malloc(size) \
574 Dont_Use_malloc(size)
575
576#ifdef realloc
577#undef realloc
578#endif
579#define realloc(memblock, size) \
580 Dont_Use_realloc(memblock, size)
581
582#ifdef free
583#undef free
584#endif
585#define free(memblock) \
586 Dont_Use_free(memblock)
587
588#endif //!FEATURE_NO_HOST
589
590extern void IncCantAllocCount();
591extern void DecCantAllocCount();
592
593class CantAllocHolder
594{
595public:
596 CantAllocHolder ()
597 {
598 IncCantAllocCount ();
599 }
600 ~CantAllocHolder()
601 {
602 DecCantAllocCount ();
603 }
604};
605
606// At places where want to allocate stress log, we need to first check if we are allowed to do so.
607// If ClrTlsInfo doesn't exist for this thread, we take it as can alloc
608inline bool IsInCantAllocRegion ()
609{
610 size_t count = 0;
611 if (ClrFlsCheckValue(TlsIdx_CantAllocCount, (LPVOID *)&count))
612 {
613 _ASSERTE (count >= 0);
614 return count > 0;
615 }
616 return false;
617}
618// for stress log the rule is more restrict, we have to check the global counter too
619extern BOOL IsInCantAllocStressLogRegion();
620
621#include "genericstackprobe.inl"
622
623#endif
624