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.

375 lines
10 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. Enumfn.cpp
  5. Abstract:
  6. Private functions used by the directory
  7. enumeration class.
  8. Notes:
  9. Unicode only right now.
  10. History:
  11. 02/22/2001 rparsons Created
  12. --*/
  13. #include "enumdir.h"
  14. /*++
  15. Routine Description:
  16. This function is called to create a virtual buffer. A virtual
  17. buffer is a contiguous range of virtual memory, where some initial
  18. prefix portion of the memory is committed and the remainder is only
  19. reserved virtual address space. A routine is provided to extend the
  20. size of the committed region incrementally or to trim the size of
  21. the committed region back to some specified amount.
  22. Arguments:
  23. Buffer - Pointer to the virtual buffer control structure that is
  24. filled in by this function.
  25. CommitSize - Size of the initial committed portion of the buffer.
  26. May be zero.
  27. ReserveSize - Amount of virtual address space to reserve for the
  28. buffer. May be zero, in which case amount reserved is the
  29. committed size plus one, rounded up to the next 64KB boundary.
  30. Return Value:
  31. TRUE if operation was successful. Otherwise returns FALSE and
  32. extended error information is available from GetLastError()
  33. --*/
  34. BOOL
  35. CEnumDir::CreateVirtualBuffer(
  36. OUT PVIRTUAL_BUFFER Buffer,
  37. IN DWORD CommitSize,
  38. IN DWORD ReserveSize OPTIONAL
  39. )
  40. {
  41. SYSTEM_INFO SystemInformation;
  42. //
  43. // Query the page size from the system for rounding
  44. // our memory allocations.
  45. //
  46. GetSystemInfo(&SystemInformation);
  47. Buffer->PageSize = SystemInformation.dwPageSize;
  48. //
  49. // If the reserve size was not specified, default it by
  50. // rounding up the initial committed size to a 64KB
  51. // boundary. This is because the Win32 Virtual Memory
  52. // API calls always allocate virtual address space on
  53. // 64KB boundaries, so we might well have it available
  54. // for commitment.
  55. //
  56. if (!ARGUMENT_IS_PRESENT(ReserveSize)) {
  57. ReserveSize = ROUND_UP(CommitSize + 1, 0x10000);
  58. }
  59. //
  60. // Attempt to reserve the address space.
  61. //
  62. Buffer->Base = VirtualAlloc(NULL,
  63. ReserveSize,
  64. MEM_RESERVE,
  65. PAGE_READWRITE);
  66. if (Buffer->Base == NULL) {
  67. //
  68. // Unable to reserve address space, return failure.
  69. //
  70. return FALSE;
  71. }
  72. //
  73. // Attempt to commit some initial portion of the reserved region.
  74. //
  75. //
  76. CommitSize = ROUND_UP(CommitSize, Buffer->PageSize);
  77. if (CommitSize == 0 ||
  78. VirtualAlloc(Buffer->Base,
  79. CommitSize,
  80. MEM_COMMIT,
  81. PAGE_READWRITE) != NULL) {
  82. //
  83. // Either the size of the committed region was zero or the
  84. // commitment succeeded. In either case calculate the
  85. // address of the first byte after the committed region
  86. // and the address of the first byte after the reserved
  87. // region and return successs.
  88. //
  89. Buffer->CommitLimit = (LPVOID)
  90. ((char *)Buffer->Base + CommitSize);
  91. Buffer->ReserveLimit = (LPVOID)
  92. ((char *)Buffer->Base + ReserveSize);
  93. return TRUE;
  94. }
  95. //
  96. // If unable to commit the memory, release the virtual address
  97. // range allocated above and return failure.
  98. //
  99. VirtualFree(Buffer->Base, 0, MEM_RELEASE);
  100. return FALSE;
  101. }
  102. /*++
  103. Routine Description:
  104. This function is called to extend the committed portion of a virtual
  105. buffer.
  106. Arguments:
  107. Buffer - Pointer to the virtual buffer control structure.
  108. Address - Byte at this address is committed, along with all memory
  109. from the beginning of the buffer to this address. If the
  110. address is already within the committed portion of the virtual
  111. buffer, then this routine does nothing. If outside the reserved
  112. portion of the virtual buffer, then this routine returns an
  113. error.
  114. Otherwise enough pages are committed so that the memory from the
  115. base of the buffer to the passed address is a contiguous region
  116. of committed memory.
  117. Return Value:
  118. TRUE if operation was successful. Otherwise returns FALSE and
  119. extended error information is available from GetLastError()
  120. --*/
  121. BOOL
  122. CEnumDir::ExtendVirtualBuffer(
  123. IN PVIRTUAL_BUFFER Buffer,
  124. IN LPVOID Address
  125. )
  126. {
  127. DWORD NewCommitSize;
  128. LPVOID NewCommitLimit;
  129. //
  130. // See if address is within the buffer.
  131. //
  132. if (Address >= Buffer->Base && Address < Buffer->ReserveLimit) {
  133. //
  134. // See if the address is within the committed portion of
  135. // the buffer. If so return success immediately.
  136. //
  137. if (Address < Buffer->CommitLimit) {
  138. return TRUE;
  139. }
  140. //
  141. // Address is within the reserved portion. Determine how many
  142. // bytes are between the address and the end of the committed
  143. // portion of the buffer. Round this size to a multiple of
  144. // the page size and this is the amount we will attempt to
  145. // commit.
  146. //
  147. NewCommitSize =
  148. ((DWORD)ROUND_UP((DWORD)Address + 1, Buffer->PageSize) -
  149. (DWORD)Buffer->CommitLimit);
  150. //
  151. // Attempt to commit the memory.
  152. //
  153. NewCommitLimit = VirtualAlloc(Buffer->CommitLimit,
  154. NewCommitSize,
  155. MEM_COMMIT,
  156. PAGE_READWRITE);
  157. if (NewCommitLimit != NULL) {
  158. //
  159. // Successful, so update the upper limit of the committed
  160. // region of the buffer and return success.
  161. //
  162. Buffer->CommitLimit = (LPVOID)
  163. ((DWORD)NewCommitLimit + NewCommitSize);
  164. return TRUE;
  165. }
  166. }
  167. //
  168. // Address is outside of the buffer, return failure.
  169. //
  170. return FALSE;
  171. }
  172. /*++
  173. Routine Description:
  174. This function is called to decommit any memory that has been
  175. committed for this virtual buffer.
  176. Arguments:
  177. Buffer - Pointer to the virtual buffer control structure.
  178. Return Value:
  179. TRUE if operation was successful. Otherwise returns FALSE and
  180. extended error information is available from GetLastError()
  181. --*/
  182. BOOL
  183. CEnumDir::TrimVirtualBuffer(
  184. IN PVIRTUAL_BUFFER Buffer
  185. )
  186. {
  187. Buffer->CommitLimit = Buffer->Base;
  188. return VirtualFree(Buffer->Base, 0, MEM_DECOMMIT);
  189. }
  190. /*++
  191. Routine Description:
  192. This function is called to free all the memory that is associated
  193. with this virtual buffer.
  194. Arguments:
  195. Buffer - Pointer to the virtual buffer control structure.
  196. Return Value:
  197. TRUE if operation was successful. Otherwise returns FALSE and
  198. extended error information is available from GetLastError()
  199. --*/
  200. BOOL
  201. CEnumDir::FreeVirtualBuffer(
  202. IN PVIRTUAL_BUFFER Buffer
  203. )
  204. {
  205. //
  206. // Decommit and release all virtual memory associated with
  207. // this virtual buffer.
  208. //
  209. return VirtualFree(Buffer->Base, 0, MEM_RELEASE);
  210. }
  211. /*++
  212. Routine Description:
  213. This function is an exception filter that handles exceptions that
  214. referenced uncommitted but reserved memory contained in the passed
  215. virtual buffer. It this filter routine is able to commit the
  216. additional pages needed to allow the memory reference to succeed,
  217. then it will re-execute the faulting instruction. If it is unable
  218. to commit the pages, it will execute the callers exception handler.
  219. If the exception is not an access violation or is an access
  220. violation but does not reference memory contained in the reserved
  221. portion of the virtual buffer, then this filter passes the exception
  222. on up the exception chain.
  223. Arguments:
  224. ExceptionCode - Reason for the exception.
  225. ExceptionInfo - Information about the exception and the context
  226. that it occurred in.
  227. Buffer - Points to a virtual buffer control structure that defines
  228. the reserved memory region that is to be committed whenever an
  229. attempt is made to access it.
  230. Return Value:
  231. Exception disposition code that tells the exception dispatcher what
  232. to do with this exception. One of three values is returned:
  233. EXCEPTION_EXECUTE_HANDLER - execute the exception handler
  234. associated with the exception clause that called this filter
  235. procedure.
  236. EXCEPTION_CONTINUE_SEARCH - Continue searching for an exception
  237. handler to handle this exception.
  238. EXCEPTION_CONTINUE_EXECUTION - Dismiss this exception and return
  239. control to the instruction that caused the exception.
  240. --*/
  241. int
  242. CEnumDir::VirtualBufferExceptionFilter(
  243. IN DWORD ExceptionCode,
  244. IN PEXCEPTION_POINTERS ExceptionInfo,
  245. IN OUT PVIRTUAL_BUFFER Buffer
  246. )
  247. {
  248. LPVOID FaultingAddress;
  249. //
  250. // If this is an access violation touching memory within
  251. // our reserved buffer, but outside of the committed portion
  252. // of the buffer, then we are going to take this exception.
  253. //
  254. if (ExceptionCode == STATUS_ACCESS_VIOLATION) {
  255. //
  256. // Get the virtual address that caused the access violation
  257. // from the exception record. Determine if the address
  258. // references memory within the reserved but uncommitted
  259. // portion of the virtual buffer.
  260. //
  261. FaultingAddress = (LPVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ];
  262. if (FaultingAddress >= Buffer->CommitLimit &&
  263. FaultingAddress <= Buffer->ReserveLimit
  264. ) {
  265. //
  266. // This is our exception. Try to extend the buffer
  267. // to including the faulting address.
  268. //
  269. if (ExtendVirtualBuffer(Buffer, FaultingAddress)) {
  270. //
  271. // Buffer successfully extended, so re-execute the
  272. // faulting instruction.
  273. //
  274. return EXCEPTION_CONTINUE_EXECUTION;
  275. } else {
  276. //
  277. // Unable to extend the buffer. Stop searching
  278. // for exception handlers and execute the caller's
  279. // handler.
  280. //
  281. return EXCEPTION_EXECUTE_HANDLER;
  282. }
  283. }
  284. }
  285. //
  286. // Not an exception we care about, so pass it up the chain.
  287. //
  288. return EXCEPTION_CONTINUE_SEARCH;
  289. }