Windows NT 4.0 source code leak
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.

446 lines
13 KiB

4 years ago
  1. // VMBuffer.c -- Copied from the PDC sample application
  2. // by Ron Murray
  3. // 15 December 1992
  4. #include "stdafx.h"
  5. #include "VMBuffer.h"
  6. #include "Memex.h"
  7. #include "AbrtSrch.h"
  8. #include "Except.h"
  9. #ifdef _DEBUG
  10. BOOL
  11. _CreateVirtualBuffer(
  12. OUT PMY_VIRTUAL_BUFFER pvb,
  13. IN DWORD CommitSize,
  14. IN DWORD ReserveSize OPTIONAL,
  15. BOOL fForceExceptions,
  16. PSZ pszWhichFile,
  17. UINT iWhichLine
  18. )
  19. #else // _DEBUG
  20. BOOL CreateVirtualBuffer(PMY_VIRTUAL_BUFFER pvb, DWORD CommitSize, DWORD ReserveSize, BOOL fForceExceptions)
  21. #endif // _DEBUG
  22. /*++
  23. Routine Description:
  24. This function is called to create a virtual buffer. A virtual
  25. buffer is a contiguous range of virtual memory, where some initial
  26. prefix portion of the memory is committed and the remainder is only
  27. reserved virtual address space. A routine is provided to extend the
  28. size of the committed region incrementally or to trim the size of
  29. the committed region back to some specified amount.
  30. Arguments:
  31. pvb - Pointer to the virtual buffer control structure that is
  32. filled in by this function.
  33. CommitSize - Size of the initial committed portion of the buffer.
  34. May be zero.
  35. ReserveSize - Amount of virtual address space to reserve for the
  36. buffer. May be zero, in which case amount reserved is the
  37. committed size plus one, rounded up to the next 64KB boundary.
  38. Return Value:
  39. TRUE if operation was successful. Otherwise returns FALSE and
  40. extended error information is available from GetLastError()
  41. --*/
  42. {
  43. BOOL fResult= FALSE;
  44. CAbortSearch::CheckContinueState();
  45. SYSTEM_INFO SystemInformation;
  46. ASSERT(pvb->Base == NULL);
  47. pvb->fForceExceptions= fForceExceptions;
  48. __try
  49. {
  50. // Query the page size from the system for rounding
  51. // our memory allocations.
  52. GetSystemInfo( &SystemInformation);
  53. pvb->PageSize = SystemInformation.dwPageSize;
  54. // If the reserve size was not specified, default it by
  55. // rounding up the initial committed size to a 64KB
  56. // boundary. This is because the Win32 Virtual Memory
  57. // API calls always allocate virtual address space on
  58. // 64KB boundaries, so we might well have it available
  59. // for commitment.
  60. if (!ReserveSize) ReserveSize = ROUND_UP(CommitSize + 1, 0x10000);
  61. // Attempt to reserve the address space.
  62. ReserveSize= ROUND_UP(ReserveSize+SystemInformation.dwPageSize, 0x10000 );
  63. pvb->Base= VirtualAlloc(NULL, ReserveSize, MEM_RESERVE, PAGE_READWRITE);
  64. ASSERT(pvb->Base); // Generally if the MEM_RESERVE call above fails, it's because we've made
  65. // a mistake in the way we've partitioned our 32-bit address space. That is,
  66. // we really have tried to reserve more than 2^31 bytes of address space.
  67. // I've left in the exception code below to force a clean recovery in the
  68. // retail version of the code if we ever make this mistake.
  69. if (pvb->Base == NULL)
  70. if (fForceExceptions)
  71. {
  72. #ifdef _DEBUG
  73. MessageBox(NULL, "In CreateVirtualBuffer; Failure: pvb->Base == NULL", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  74. #endif // _DEBUG
  75. RaiseException(STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
  76. }
  77. else __leave;
  78. // Attempt to commit some initial portion of the reserved region.
  79. CommitSize = ROUND_UP(CommitSize, pvb->PageSize);
  80. for (;;)
  81. {
  82. CAbortSearch::CheckContinueState();
  83. if ( CommitSize == 0
  84. || VirtualAlloc(pvb->Base, CommitSize, MEM_COMMIT, PAGE_READWRITE) != NULL
  85. )
  86. {
  87. // Either the size of the committed region was zero or the
  88. // commitment succeeded. In either case calculate the
  89. // address of the first byte after the committed region
  90. // and the address of the first byte after the reserved
  91. // region and return successs.
  92. pvb->CommitLimit= (LPVOID) ((char *)pvb->Base + CommitSize);
  93. pvb->ReserveLimit=(LPVOID) ((char *)pvb->Base + ReserveSize);
  94. #ifdef _DEBUG
  95. CreateVARecord(pvb->Base, pvb->CommitLimit, pvb->ReserveLimit,
  96. pszWhichFile, iWhichLine
  97. );
  98. #endif // _DEBUG
  99. fResult= TRUE;
  100. __leave;
  101. }
  102. else
  103. if (fForceExceptions)
  104. {
  105. extern char szMem_Err[];
  106. extern char szNeed_More_Memory[];
  107. if (!AskForMemory())
  108. RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
  109. else continue;
  110. }
  111. else
  112. {
  113. VirtualFree(pvb->Base, 0, MEM_RELEASE);
  114. pvb->Base= NULL;
  115. __leave;
  116. }
  117. }
  118. }
  119. __finally
  120. {
  121. if (_abnormal_termination())
  122. {
  123. // If unable to commit the memory, release the virtual address
  124. // range allocated above and return failure.
  125. if (pvb->Base) {
  126. VirtualFree(pvb->Base, 0, MEM_RELEASE );
  127. pvb->Base= NULL;
  128. }
  129. }
  130. }
  131. return fResult;
  132. }
  133. BOOL ExtendVirtualBuffer(PMY_VIRTUAL_BUFFER pvb, LPVOID Address)
  134. /*++
  135. Routine Description:
  136. This function is called to extend the committed portion of a virtual
  137. buffer.
  138. Arguments:
  139. pvb - Pointer to the virtual buffer control structure.
  140. Address - Byte at this address is committed, along with all memory
  141. from the beginning of the buffer to this address. If the
  142. address is already within the committed portion of the virtual
  143. buffer, then this routine does nothing. If outside the reserved
  144. portion of the virtual buffer, then this routine returns an
  145. error.
  146. Otherwise enough pages are committed so that the memory from the
  147. base of the buffer to the passed address is a contiguous region
  148. of committed memory.
  149. Return Value:
  150. TRUE if operation was successful. Otherwise returns FALSE and
  151. extended error information is available from GetLastError()
  152. --*/
  153. {
  154. DWORD NewCommitSize;
  155. LPVOID NewCommitLimit;
  156. // See if address is within the buffer.
  157. ASSERT(Address >= pvb->Base && Address < pvb->ReserveLimit);
  158. // The above assert is here to catch the cases where we haven't
  159. // reserved enough of our address space for a particular virtual
  160. // buffer. The code below recovers gracefully in the retail build
  161. // when we've made that mistake.
  162. // Note that we don't need a __try/__finally mechanism here because
  163. // the side effects only occur if we succeed.
  164. if (Address < pvb->Base || Address >= pvb->ReserveLimit)
  165. if (pvb->fForceExceptions)
  166. {
  167. #ifdef _DEBUG
  168. MessageBox(NULL, "In ExtendVirtualBuffer; Failure: Address < pvb->Base || Address >= pvb->ReserveLimit", "Search System Failure", MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  169. #endif // _DEBUG
  170. RaiseException(STATUS_SYSTEM_ERROR, EXCEPTION_NONCONTINUABLE, 0, NULL);
  171. }
  172. else return FALSE;
  173. // See if the address is within the committed portion of
  174. // the buffer. If so return success immediately.
  175. if (Address < pvb->CommitLimit) return TRUE;
  176. // Address is within the reserved portion. Determine how many
  177. // bytes are between the address and the end of the committed
  178. // portion of the buffer. Round this size to a multiple of
  179. // the page size and this is the amount we will attempt to
  180. // commit.
  181. NewCommitSize = ((DWORD)ROUND_UP( (DWORD) Address + 1, pvb->PageSize ) - (DWORD)pvb->CommitLimit);
  182. // Attempt to commit the memory.
  183. for (;;)
  184. {
  185. CAbortSearch::CheckContinueState();
  186. NewCommitLimit= VirtualAlloc(pvb->CommitLimit, NewCommitSize, MEM_COMMIT, PAGE_READWRITE);
  187. if (NewCommitLimit) break;
  188. else
  189. if (pvb->fForceExceptions)
  190. {
  191. extern char szMem_Err[];
  192. extern char szNeed_More_Memory[];
  193. if (!AskForMemory())
  194. RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
  195. else continue;
  196. }
  197. else return FALSE;
  198. }
  199. // Successful, so update the upper limit of the committed
  200. // region of the buffer and return success.
  201. pvb->CommitLimit = (LPVOID) ((DWORD)NewCommitLimit + NewCommitSize);
  202. #ifdef _DEBUG
  203. AdjustVARecord(pvb->Base, pvb->CommitLimit);
  204. #endif // _DEBUG
  205. return TRUE;
  206. }
  207. BOOL
  208. TrimVirtualBuffer(PMY_VIRTUAL_BUFFER pvb)
  209. /*++
  210. Routine Description:
  211. This function is called to decommit any memory that has been
  212. committed for this virtual buffer.
  213. Arguments:
  214. pvb - Pointer to the virtual buffer control structure.
  215. Return Value:
  216. TRUE if operation was successful. Otherwise returns FALSE and
  217. extended error information is available from GetLastError()
  218. --*/
  219. {
  220. if (!VirtualFree(pvb->Base, 0, MEM_DECOMMIT))
  221. if (pvb->fForceExceptions)
  222. RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
  223. else return FALSE;
  224. pvb->CommitLimit = pvb->Base;
  225. #ifdef _DEBUG
  226. AdjustVARecord(pvb->Base, pvb->Base);
  227. #endif // _DEBUG
  228. return TRUE;
  229. }
  230. BOOL
  231. FreeVirtualBuffer(PMY_VIRTUAL_BUFFER pvb)
  232. /*++
  233. Routine Description:
  234. This function is called to free all the memory that is associated
  235. with this virtual buffer.
  236. Arguments:
  237. pvb - Pointer to the virtual buffer control structure.
  238. Return Value:
  239. TRUE if operation was successful. Otherwise returns FALSE and
  240. extended error information is available from GetLastError()
  241. --*/
  242. {
  243. //
  244. // Decommit and release all virtual memory associated with
  245. // this virtual buffer.
  246. //
  247. if (!VirtualFree( pvb->Base, 0, MEM_RELEASE ))
  248. if (pvb->fForceExceptions)
  249. RaiseException(STATUS_NO_MEMORY, EXCEPTION_NONCONTINUABLE, 0, NULL);
  250. else return FALSE;
  251. #ifdef _DEBUG
  252. DestroyVARecord(pvb->Base);
  253. #endif // _DEBUG
  254. pvb->Base= NULL;
  255. return TRUE;
  256. }
  257. int VirtualBufferExceptionFilter(IN DWORD ExceptionCode, IN PEXCEPTION_POINTERS ExceptionInfo,
  258. IN OUT PMY_VIRTUAL_BUFFER pvb,
  259. IN UINT cbIncrement
  260. )
  261. /*++
  262. Routine Description:
  263. This function is an exception filter that handles exceptions that
  264. referenced uncommitted but reserved memory contained in the passed
  265. virtual buffer. It this filter routine is able to commit the
  266. additional pages needed to allow the memory reference to succeed,
  267. then it will re-execute the faulting instruction. If it is unable
  268. to commit the pages, it will execute the callers exception handler.
  269. If the exception is not an access violation or is an access
  270. violation but does not reference memory contained in the reserved
  271. portion of the virtual buffer, then this filter passes the exception
  272. on up the exception chain.
  273. Arguments:
  274. ExceptionCode - Reason for the exception.
  275. ExceptionInfo - Information about the exception and the context
  276. that it occurred in.
  277. pvb - Points to a virtual buffer control structure that defines
  278. the reserved memory region that is to be committed whenever an
  279. attempt is made to access it.
  280. Return Value:
  281. Exception disposition code that tells the exception dispatcher what
  282. to do with this exception. One of three values is returned:
  283. EXCEPTION_EXECUTE_HANDLER - execute the exception handler
  284. associated with the exception clause that called this filter
  285. procedure.
  286. EXCEPTION_CONTINUE_SEARCH - Continue searching for an exception
  287. handler to handle this exception.
  288. EXCEPTION_CONTINUE_EXECUTION - Dismiss this exception and return
  289. control to the instruction that caused the exception.
  290. --*/
  291. {
  292. LPVOID FaultingAddress;
  293. // If this is an access violation touching memory within
  294. // our reserved buffer, but outside of the committed portion
  295. // of the buffer, then we are going to take this exception.
  296. if (ExceptionCode != STATUS_ACCESS_VIOLATION) return EXCEPTION_CONTINUE_SEARCH;
  297. // Get the virtual address that caused the access violation
  298. // from the exception record. Determine if the address
  299. // references memory within the reserved but uncommitted
  300. // portion of the virtual buffer.
  301. FaultingAddress = (LPVOID)ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
  302. if ( FaultingAddress >= pvb->CommitLimit
  303. && FaultingAddress < pvb->ReserveLimit
  304. )
  305. {
  306. // This is our exception. Try to extend the buffer
  307. // to including the faulting address.
  308. FaultingAddress = PVOID(PBYTE(FaultingAddress) + cbIncrement);
  309. if (FaultingAddress >= pvb->ReserveLimit)
  310. FaultingAddress = PVOID(PBYTE(pvb->ReserveLimit) - 1);
  311. if (ExtendVirtualBuffer(pvb, FaultingAddress))
  312. return EXCEPTION_CONTINUE_EXECUTION;
  313. else return EXCEPTION_EXECUTE_HANDLER;
  314. }
  315. return EXCEPTION_CONTINUE_SEARCH;
  316. }