Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

278 lines
5.6 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. alloca.c
  5. Abstract:
  6. This module implements a safe stack-based allocator with fallback to the heap.
  7. Author:
  8. Jonathan Schwartz (JSchwart) 16-Mar-2001
  9. Revision History:
  10. --*/
  11. #include <nt.h>
  12. #include <ntrtl.h>
  13. #include <nturtl.h>
  14. #include <windows.h>
  15. #include <malloc.h> // _resetstkoflw()
  16. #include <alloca.h>
  17. //
  18. // Globals used to control SafeAlloca behavior
  19. //
  20. SIZE_T g_ulMaxStackAllocSize;
  21. SIZE_T g_ulAdditionalProbeSize;
  22. SAFEALLOC_ALLOC_PROC g_pfnAllocate;
  23. SAFEALLOC_FREE_PROC g_pfnFree;
  24. //
  25. // Local function declarations
  26. //
  27. PVOID
  28. SafeAllocaAllocateFromHeap(
  29. SIZE_T Size
  30. );
  31. VOID
  32. SafeAllocaFreeToHeap(
  33. PVOID BaseAddress
  34. );
  35. //+-------------------------------------------------------------------------
  36. //
  37. // Function: SafeAllocaInitialize
  38. //
  39. // Synopsis: Initialize globals used to control SafeAlloca behavior
  40. //
  41. // Effects:
  42. //
  43. // Arguments:
  44. //
  45. // Requires:
  46. //
  47. // Returns:
  48. //
  49. // Notes: Must be called before SafeAlloca is used to allocate space
  50. //
  51. //--------------------------------------------------------------------------
  52. VOID
  53. SafeAllocaInitialize(
  54. IN OPTIONAL SIZE_T ulMaxStackAllocSize,
  55. IN OPTIONAL SIZE_T ulAdditionalProbeSize,
  56. IN OPTIONAL SAFEALLOC_ALLOC_PROC pfnAllocate,
  57. IN OPTIONAL SAFEALLOC_FREE_PROC pfnFree
  58. )
  59. {
  60. PIMAGE_NT_HEADERS NtHeaders = NULL;
  61. PPEB Peb = NtCurrentPeb();
  62. //
  63. // Make sure this is the first and only time the init is being called for this
  64. // binary (either DLL or EXE since this is a code LIB). Otherwise, we could
  65. // end up with the free routine after memory is allocated using a completely
  66. // unrelated allocator.
  67. //
  68. ASSERT(g_pfnAllocate == NULL && g_pfnFree == NULL);
  69. if (NtCurrentPeb()->BeingDebugged)
  70. {
  71. //
  72. // Usermode debugger is attached to this process, which can cause issues
  73. // when the first-chance overflow exception on stack probes is caught by
  74. // the debugger rather than the probe exception handler. Force all
  75. // allocations to the heap.
  76. //
  77. g_ulMaxStackAllocSize = 0;
  78. }
  79. else if (ulMaxStackAllocSize == SAFEALLOCA_USE_DEFAULT)
  80. {
  81. //
  82. // Default is stack size from the image header
  83. //
  84. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  85. if (NtHeaders == NULL)
  86. {
  87. //
  88. // This shouldn't happen -- it implies the binary is bad.
  89. // Set the default to force heap allocations only.
  90. //
  91. ASSERT(NtHeaders != NULL);
  92. g_ulMaxStackAllocSize = 0;
  93. }
  94. else
  95. {
  96. g_ulMaxStackAllocSize = NtHeaders->OptionalHeader.SizeOfStackCommit;
  97. }
  98. }
  99. else
  100. {
  101. g_ulMaxStackAllocSize = ulMaxStackAllocSize;
  102. }
  103. if (ulAdditionalProbeSize == SAFEALLOCA_USE_DEFAULT)
  104. {
  105. //
  106. // Default is stack size from the image header
  107. //
  108. if (NtHeaders == NULL)
  109. {
  110. NtHeaders = RtlImageNtHeader(Peb->ImageBaseAddress);
  111. if (NtHeaders == NULL)
  112. {
  113. //
  114. // This shouldn't happen -- it implies the binary is bad.
  115. // Set the default to force heap allocations only.
  116. //
  117. ASSERT(NtHeaders != NULL);
  118. g_ulAdditionalProbeSize = 0xffffffff;
  119. }
  120. }
  121. if (NtHeaders != NULL)
  122. {
  123. g_ulAdditionalProbeSize = NtHeaders->OptionalHeader.SizeOfStackCommit;
  124. }
  125. }
  126. else
  127. {
  128. g_ulAdditionalProbeSize = ulAdditionalProbeSize;
  129. }
  130. if (pfnAllocate == NULL)
  131. {
  132. g_pfnAllocate = SafeAllocaAllocateFromHeap;
  133. }
  134. else
  135. {
  136. g_pfnAllocate = pfnAllocate;
  137. }
  138. if (pfnFree == NULL)
  139. {
  140. g_pfnFree = SafeAllocaFreeToHeap;
  141. }
  142. else
  143. {
  144. g_pfnFree = pfnFree;
  145. }
  146. }
  147. //+-------------------------------------------------------------------------
  148. //
  149. // Function: SafeAllocaAllocateFromHeap
  150. //
  151. // Synopsis: Default fallback heap allocator for SafeAlloca
  152. //
  153. // Effects:
  154. //
  155. // Arguments:
  156. //
  157. // Requires:
  158. //
  159. // Returns:
  160. //
  161. // Notes:
  162. //
  163. //--------------------------------------------------------------------------
  164. PVOID
  165. SafeAllocaAllocateFromHeap(
  166. SIZE_T Size
  167. )
  168. {
  169. return RtlAllocateHeap(RtlProcessHeap(), 0, Size);
  170. }
  171. //+-------------------------------------------------------------------------
  172. //
  173. // Function: SafeAllocaFreeToHeap
  174. //
  175. // Synopsis: Default fallback heap free routine for SafeAlloca
  176. //
  177. // Effects:
  178. //
  179. // Arguments:
  180. //
  181. // Requires:
  182. //
  183. // Returns:
  184. //
  185. // Notes:
  186. //
  187. //--------------------------------------------------------------------------
  188. VOID
  189. SafeAllocaFreeToHeap(
  190. PVOID BaseAddress
  191. )
  192. {
  193. RtlFreeHeap(RtlProcessHeap(), 0, BaseAddress);
  194. }
  195. //+-------------------------------------------------------------------------
  196. //
  197. // Function: VerifyStackAvailable
  198. //
  199. // Synopsis: Routine to probe the stack to ensure the allocation size
  200. // plus additional probe size is available.
  201. //
  202. // Effects:
  203. //
  204. // Arguments:
  205. //
  206. // Requires:
  207. //
  208. // Returns:
  209. //
  210. // Notes:
  211. //
  212. //--------------------------------------------------------------------------
  213. BOOL
  214. VerifyStackAvailable(
  215. SIZE_T Size
  216. )
  217. {
  218. BOOL fStackAvailable = TRUE;
  219. __try
  220. {
  221. PVOID p = _alloca(Size);
  222. }
  223. __except ((EXCEPTION_STACK_OVERFLOW == GetExceptionCode()) ?
  224. EXCEPTION_EXECUTE_HANDLER :
  225. EXCEPTION_CONTINUE_SEARCH)
  226. {
  227. fStackAvailable = FALSE;
  228. _resetstkoflw();
  229. }
  230. return fStackAvailable;
  231. }