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.

2167 lines
55 KiB

  1. // LMEM.C
  2. //
  3. // (C) Copyright Microsoft Corp., 1988-1994
  4. //
  5. // Win32 wrappers for heap functions (Local* and some Heap*)
  6. //
  7. // Origin: <Chicago>
  8. //
  9. // Change history:
  10. //
  11. // Date Who Description
  12. // --------- --------- -------------------------------------------------
  13. // BrianSm Local* and Heap* APIs
  14. // AtsushiK Toolhelp
  15. // 15-Feb-94 JonT Code cleanup and precompiled headers
  16. #include <EmulateHeap_kernel32.h>
  17. #pragma hdrstop("kernel32.pch")
  18. #include <tlhelp32.h>
  19. #define GACF_HEAPSLACK 0x400000 // Copied from windows.h (16-bit)
  20. SetFile();
  21. /*
  22. * Structure and equates for LocalAlloc handle management. Some things
  23. * to remember:
  24. *
  25. * When a handle is returned to the user, we really pass him the address
  26. * of the lh_pdata field because some bad apps like Excel just dereference the
  27. * handle to find the pointer, rather than call LocalLock.
  28. *
  29. * It is important that the handle value returned also be word aligned but not
  30. * dword aligned (ending in a 2,6,a, or e). We use the 0x2 bit to detect
  31. * that a value is a handle and not a pointer (which will always be dword
  32. * aligned).
  33. *
  34. * If the data block get discarded, the lh_pdata field will be set to 0.
  35. *
  36. * Free handles are kept on a free list linked through the lh_freelink
  37. * field which overlays some other fields. You can tell if a handle is free
  38. * and has a valid freelink by checking that lh_sig == LH_FREESIG
  39. *
  40. * The handles themselves are kept in heap blocks layed out as a
  41. * lharray_s. We link these blocks on a per-process list so that
  42. * the heap-walking functions can enumerate them.
  43. */
  44. #pragma pack(1)
  45. struct lhandle_s {
  46. unsigned short lh_signature; /* signature (LH_BUSYSIG or LH_FREESIG)*/
  47. void *lh_pdata; /* pointer to data for heap block */
  48. unsigned char lh_flags; /* flags (LH_DISCARDABLE) */
  49. unsigned char lh_clock; /* lock count */
  50. };
  51. #define lh_freelink lh_pdata /* free list overlays first field */
  52. /* if LH_FREE is set in lh_flags */
  53. #define LH_BUSYSIG 'SB' /* signature for allocated handle */
  54. #define LH_FREESIG 'SF' /* signature for free handle */
  55. #define LH_DISCARDABLE 0x02 /* lh_flags value for discardable mem */
  56. #define LH_CLOCKMAX 0xff /* maximum possible lock count */
  57. #define LH_HANDLEBIT 2 /* bit that is set on handles but not */
  58. /* pointers */
  59. #define CLHGROW 8
  60. #define CBLHGROW (sizeof(struct lhandle_s) * CLHGROW)
  61. struct lharray_s {
  62. unsigned short lha_signature; /* signature (LHA_SIG) */
  63. unsigned short lha_membercount; /* position in linked list (for detecting loops) */
  64. struct lharray_s *lha_next; /* ptr to next lharray_s */
  65. //!!! This array *must* be dword aligned so that the handles will be
  66. // *not* dword-aligned.
  67. struct lhandle_s lha_lh[CLHGROW];
  68. };
  69. #define LHA_SIGNATURE 'AL' /* signature for lhaarray_s blocks */
  70. #define TH32_MEMBUFFERSIZE (max(CBLHGROW,1024))
  71. // A pointer to this private block of state info is kept in the dwResvd
  72. // field of the HEAPENTRY32 structure.
  73. typedef struct {
  74. CRST *pcrst; // Pointer to critical section (unencoded)
  75. // !!! pcrst must be the first field!!!
  76. PDB *ppdb; // PDB of process
  77. HHEAP hHeap; // Real Heap handle
  78. DWORD lpbMin; // Lowest allowed address for a heap block
  79. DWORD nlocalHnd; // # of lhandle_s structures allocated in heap
  80. struct heapinfo_s hi; // Snapshot of heapinfo_s
  81. DWORD nSuppAvail; // size of lpdwSuppress array in dwords
  82. DWORD nSuppUsed; // # of lpdwSuppress array dwords used.
  83. DWORD *lpdwSuppress; // Either NULL or a pointer to a NULL-terminated
  84. // array of heap blocks to suppress.
  85. DWORD dwMode; // Current mode
  86. DWORD nNextLH; // 0 based index of next lhandle to read in curlha (THM_LHANDLES)
  87. DWORD lpHBlock; // Address of next heap block to read (THM_FIXEDHANDLES)
  88. DWORD dwBlkAddr; // Address of start of block data
  89. DWORD dwBlkSize; // Size of heap block (including header)
  90. DWORD dwBlkFlags; // HP_ flags.
  91. DWORD curlhaaddr; // Actual base address of curlha.
  92. struct lharray_s curlha; // Snapshot of current lharray_s
  93. } THSTATE, *LPTHSTATE;
  94. #define THM_INIT 0 //Init state
  95. #define THM_LHANDLES 1 //Next object is an lhandle
  96. #define THM_FIXEDHANDLES 2 //Next object is a fixed handle
  97. #define THM_DONE 3 //Normal end
  98. #define THM_ERROR 4 //Found heap error in previous advance
  99. /*
  100. * these externs are needed to know whether we should destroy or dispose heap
  101. * critical sections
  102. */
  103. extern HANDLE hheapKernel; /* heap handle for the kernel heap */
  104. VOID APIENTRY MakeCriticalSectionGlobal( LPCRITICAL_SECTION lpcsCriticalSection );
  105. /*
  106. * The HP_* flags and LMEM_* flags should be interchangeable
  107. */
  108. #if ((HP_ZEROINIT - LMEM_ZEROINIT) || (HP_MOVEABLE - LMEM_MOVEABLE) || (HP_FIXED - LMEM_FIXED))
  109. # error Equates busted
  110. #endif
  111. extern ULONG INTERNAL VerifyOnHeap(HHEAP hheap, PVOID p);
  112. extern KERNENTRY HouseCleanLogicallyDeadHandles(VOID);
  113. extern BOOL KERNENTRY ReadProcessMemoryFromPDB(PPDB ppdb,
  114. LPVOID lpBaseAddress,
  115. LPVOID lpBuffer,
  116. DWORD nSize,
  117. LPDWORD lpNumberOfBytesRead);
  118. extern DWORD KERNENTRY GetAppCompatFlags(VOID);
  119. extern HANDLE _GetProcessHeap(void);
  120. /*
  121. Utility function to check the local memory handle
  122. */
  123. BOOL
  124. _IsValidHandle(HANDLE hMem)
  125. {
  126. BOOL bRet = FALSE;
  127. struct lhandle_s *plh;
  128. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  129. /*
  130. * Do our own little parameter validation here because the normal
  131. * validation layer can't handle the odd-ball error return of hMem
  132. */
  133. {
  134. volatile UCHAR tryerror = 0;
  135. _try {
  136. tryerror &= (plh->lh_clock + (UCHAR)plh->lh_signature);
  137. } _except (EXCEPTION_EXECUTE_HANDLER) {
  138. tryerror = 1;
  139. }
  140. if (tryerror) {
  141. goto error;
  142. }
  143. }
  144. if ((plh->lh_signature != LH_BUSYSIG) &&
  145. (plh->lh_signature != LH_FREESIG)){
  146. goto error;
  147. }
  148. // Set the return value to TRUE
  149. bRet = TRUE;
  150. error:
  151. return bRet;
  152. }
  153. /*
  154. Utility function to check whether the passed memory
  155. is in the memory range. Uses VerifyOnHeap function.
  156. */
  157. BOOL
  158. _IsOnOurHeap(LPCVOID lpMem)
  159. {
  160. HANDLE hHeap = _GetProcessHeap();
  161. return (VerifyOnHeap(hHeap, (PVOID)lpMem));
  162. }
  163. /*
  164. Utility function to check the local memory handle
  165. and the memory range. Uses VerifyOnHeap function.
  166. */
  167. BOOL
  168. _IsOurLocalHeap(HANDLE hMem)
  169. {
  170. BOOL bRet = FALSE;
  171. HANDLE hHeap = _GetProcessHeap();
  172. if ((ULONG)hMem & LH_HANDLEBIT)
  173. {
  174. // This is a handle
  175. bRet = (VerifyOnHeap(hHeap, hMem)) &&
  176. (_IsValidHandle(hMem));
  177. }
  178. else
  179. {
  180. bRet = VerifyOnHeap(hHeap, hMem);
  181. }
  182. return bRet;
  183. }
  184. /***EP LocalAllocNG - allocate a block from the current process's default heap
  185. *
  186. * ENTRY: flags - LMEM_FIXED, LMEM_MOVEABLE, LMEM_DISCARDABLE, LMEM_ZEROINIT
  187. * dwBytes - counts of bytes to allocate
  188. * EXIT: flat pointer to block allocated, or 0 if failure
  189. *
  190. * Special entry point used by the handle-grouping code to avoid unwanted
  191. * recursion.
  192. */
  193. HANDLE APIENTRY
  194. LocalAllocNG(UINT dwFlags, UINT dwBytes)
  195. {
  196. void *pmem;
  197. struct lhandle_s *plh;
  198. struct lhandle_s *plhend;
  199. dwFlags &= ~( ((DWORD)GMEM_DDESHARE) |
  200. ((DWORD)GMEM_NOTIFY) |
  201. ((DWORD)GMEM_NOT_BANKED) );
  202. /*
  203. * Enter the heap critical section which serializes access to the handle
  204. * tables as well as the heap.
  205. */
  206. hpEnterCriticalSection(((*pppdbCur)->hheapLocal));
  207. /*
  208. * Make sure there are no extra flags
  209. */
  210. if (dwFlags & ~(LMEM_MOVEABLE | LMEM_DISCARDABLE | LMEM_ZEROINIT |
  211. LMEM_NOCOMPACT | LMEM_NODISCARD)) {
  212. mmError(ERROR_INVALID_PARAMETER, "LocalAlloc: invalid flags\n");
  213. goto error;
  214. }
  215. /*
  216. * If they want moveable memory, adjust dwBytes to leave room for a back
  217. * pointer to the handle structure and allocate a handle structure.
  218. */
  219. if (dwFlags & LMEM_MOVEABLE) {
  220. /*
  221. * Allocate a handle structure. If there aren't any on the free
  222. * list, allocate another block of memory to hold some more handles.
  223. */
  224. if ((*pppdbCur)->plhFree == 0) {
  225. struct lharray_s *plha;
  226. if ((plha = HPAlloc((HHEAP)(*pppdbCur)->hheapLocal,
  227. sizeof(struct lharray_s),
  228. HP_NOSERIALIZE)) == 0) {
  229. goto error;
  230. }
  231. plha->lha_signature = LHA_SIGNATURE;
  232. plha->lha_membercount =
  233. (*pppdbCur)->plhBlock ?
  234. (*pppdbCur)->plhBlock->lha_membercount + 1 :
  235. 0;
  236. plh = &(plha->lha_lh[0]);
  237. /*
  238. * If the allocation worked, put the handle structures on the free
  239. * list and null terminate the list. Actually, we put all of the
  240. * new blocks on the list but one, who is the guy we are trying
  241. * to allocate (he will be in plh when we are done).
  242. */
  243. (*pppdbCur)->plhFree = plh;
  244. for (plhend = plh + CLHGROW - 1; plh < plhend; plh++) {
  245. plh->lh_freelink = plh + 1;
  246. plh->lh_signature = LH_FREESIG;
  247. }
  248. (plh-1)->lh_freelink = 0;
  249. plha->lha_next = (*pppdbCur)->plhBlock;
  250. (*pppdbCur)->plhBlock = plha;
  251. /*
  252. * If there is something on the free list, just take the guy off of it
  253. */
  254. } else {
  255. plh = (*pppdbCur)->plhFree;
  256. mmAssert(plh->lh_signature == LH_FREESIG,
  257. "LocalAlloc: bad handle free list 2\n");
  258. (*pppdbCur)->plhFree = plh->lh_freelink;
  259. }
  260. /*
  261. * Initialize the handle structure
  262. */
  263. plh->lh_clock = 0;
  264. plh->lh_signature = LH_BUSYSIG;
  265. plh->lh_flags = (dwFlags & LMEM_DISCARDABLE) ? LH_DISCARDABLE : 0;
  266. /*
  267. * Now actually allocate the memory unless the caller wanted the
  268. * block initially discarded (dwBytes == 0)
  269. */
  270. if (dwBytes != 0) {
  271. /*
  272. * Need to check for wacky size here to make sure adding on
  273. * the 4 bytes below to the size doesn't bring it from negative
  274. * to positive.
  275. */
  276. if (dwBytes > hpMAXALLOC) {
  277. mmError(ERROR_NOT_ENOUGH_MEMORY,
  278. "LocalAlloc: requested size too big\n");
  279. goto errorfreehandle;
  280. }
  281. if ((pmem = HPAlloc((HHEAP)(*pppdbCur)->hheapLocal,
  282. dwBytes+sizeof(struct lhandle_s *),
  283. dwFlags | HP_NOSERIALIZE)) == 0) {
  284. goto errorfreehandle;
  285. }
  286. plh->lh_pdata = (char *)pmem + sizeof(struct lhandle_s *);
  287. /*
  288. * Initialize the back pointer to the handle structure at the
  289. * front of the data block.
  290. */
  291. *((struct lhandle_s **)pmem) = plh;
  292. } else {
  293. plh->lh_pdata = 0;
  294. }
  295. /*
  296. * Set "pmem" (the return value) to the lh_pdata field in the
  297. * handle structure.
  298. *
  299. * When a handle is returned to the user, we really pass him the address
  300. * of the lh_pdata field because some bad apps like Excel just dereference the
  301. * handle to find the pointer, rather than call LocalLock.
  302. *
  303. * It is important that the handle value returned also be word aligned but not
  304. * dword aligned (ending in a 2,6,a, or e). We use the 0x2 bit to detect
  305. * that a value is a handle and not a pointer (which will always be dword
  306. * aligned).
  307. */
  308. pmem = &plh->lh_pdata;
  309. mmAssert(((ULONG)pmem & LH_HANDLEBIT),
  310. "LocalAlloc: handle value w/o LH_HANDLEBIT set\n");
  311. /*
  312. * For fixed memory, just allocate the sucker
  313. */
  314. } else {
  315. if ((pmem = HPAlloc((HHEAP)(*pppdbCur)->hheapLocal, dwBytes,
  316. dwFlags | HP_NOSERIALIZE)) == 0) {
  317. goto errorfreehandle;
  318. }
  319. mmAssert(((ULONG)pmem & LH_HANDLEBIT) == 0,
  320. "LocalAlloc: pointer value w/ LH_HANDLEBIT set\n");
  321. }
  322. exit:
  323. hpLeaveCriticalSection(((*pppdbCur)->hheapLocal));
  324. return(pmem);
  325. /*
  326. * Error paths.
  327. */
  328. errorfreehandle:
  329. if (dwFlags & LMEM_MOVEABLE) {
  330. plh->lh_freelink = (*pppdbCur)->plhFree;
  331. (*pppdbCur)->plhFree = plh;
  332. plh->lh_signature = LH_FREESIG;
  333. }
  334. error:
  335. pmem = 0;
  336. goto exit;
  337. }
  338. /***EP LocalReAlloc - resize a memory block on the default heap
  339. *
  340. * ENTRY: hMem - pointer to block to resize
  341. * dwBytes - new size requested
  342. * dwFlags - LMEM_MOVEABLE: ok to move the block if needed
  343. * EXIT: flat pointer to resized block, or 0 if failure
  344. *
  345. */
  346. HANDLE APIENTRY
  347. LocalReAlloc(HANDLE hMem, UINT dwBytes, UINT dwFlags)
  348. {
  349. struct heapinfo_s *hheap;
  350. struct lhandle_s *plh;
  351. void *pmem;
  352. dwFlags &= ~((DWORD)GMEM_DDESHARE);
  353. HouseCleanLogicallyDeadHandles();
  354. hheap = (*pppdbCur)->hheapLocal;
  355. /*
  356. * Enter the heap critical section which serializes access to the handle
  357. * tables as well as the heap.
  358. */
  359. hpEnterCriticalSection(hheap);
  360. /*
  361. * Make sure there are no extra flags
  362. */
  363. if ((dwFlags & ~(LMEM_MOVEABLE | LMEM_DISCARDABLE | LMEM_ZEROINIT |
  364. LMEM_NOCOMPACT | LMEM_MODIFY)) ||
  365. ((dwFlags & LMEM_DISCARDABLE) && (dwFlags & LMEM_MODIFY) == 0)) {
  366. mmError(ERROR_INVALID_PARAMETER, "LocalReAlloc: invalid flags\n");
  367. goto error;
  368. }
  369. /*
  370. * Figure out if this is a handle by checking if the adress is aligned
  371. * in the right (wrong) way.
  372. */
  373. if ((ULONG)hMem & LH_HANDLEBIT) {
  374. /*
  375. * The handle value is aligned like a handle, but is it really one?
  376. * Verify it by making sure it is within the address range of the heap
  377. * and that it's signature is set right. HPReAlloc will verify things
  378. * more by checking that the pmem is valid.
  379. */
  380. if (VerifyOnHeap(hheap, hMem) == 0) {
  381. mmError(ERROR_INVALID_HANDLE, "LocalReAlloc: hMem out of range\n");
  382. goto error;
  383. }
  384. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  385. if (plh->lh_signature != LH_BUSYSIG) {
  386. mmError(ERROR_INVALID_HANDLE,
  387. "LocalReAlloc: invalid hMem, bad signature\n");
  388. goto error;
  389. }
  390. pmem = (char *)plh->lh_pdata - sizeof(struct lhandle_s *);
  391. /*
  392. * If the caller just wanted to change the flags for the block,
  393. * do it here.
  394. */
  395. if (dwFlags & LMEM_MODIFY) {
  396. plh->lh_flags &= ~LH_DISCARDABLE;
  397. plh->lh_flags |= (dwFlags & LMEM_DISCARDABLE) ? LH_DISCARDABLE : 0;
  398. /*
  399. * If someone wants to realloc the block to size 0 (meaning discard the
  400. * sucker) do so here. For discarding, we free the actual heap block
  401. * and store null in the lh_pdata field.
  402. */
  403. } else if (dwBytes == 0) {
  404. /*
  405. * If the lock count is not zero, you aren't allow to discard
  406. */
  407. if (plh->lh_clock != 0) {
  408. mmError(ERROR_INVALID_HANDLE,
  409. "LocalReAlloc: discard of locked block\n");
  410. goto error;
  411. }
  412. /*
  413. * Don't bother discarding the block if it is already discarded
  414. */
  415. if (plh->lh_pdata != 0) {
  416. if (HeapFree(hheap, HP_NOSERIALIZE, pmem) == 0) {
  417. goto error;
  418. }
  419. plh->lh_pdata = 0;
  420. }
  421. /*
  422. * If we get here, the caller actually wanted to reallocate the block
  423. */
  424. } else {
  425. dwBytes += sizeof(struct lhandle_s *);
  426. /*
  427. * If the block is currently discarded, then we need to allocate
  428. * a new memory chunk for it, otherwise, do a realloc
  429. */
  430. if (plh->lh_pdata == 0) {
  431. if (dwBytes != 0) {
  432. if ((pmem = HPAlloc(hheap, dwBytes,
  433. dwFlags | HP_NOSERIALIZE)) == 0) {
  434. goto error;
  435. }
  436. *((struct lhandle_s **)pmem) = plh;
  437. }
  438. } else {
  439. if (plh->lh_clock == 0) {
  440. dwFlags |= LMEM_MOVEABLE;
  441. }
  442. if ((pmem = HPReAlloc(hheap, pmem, dwBytes,
  443. dwFlags | HP_NOSERIALIZE)) == 0) {
  444. goto error;
  445. }
  446. }
  447. /*
  448. * Update the lh_pdata field in the handle to point to the new
  449. * memory.
  450. */
  451. plh->lh_pdata = (char *)pmem + sizeof(struct lhandle_s *);
  452. }
  453. /*
  454. * The caller did not pass in a handle. Treat the value as a pointer.
  455. * HPReAlloc will do parameter validation on it.
  456. */
  457. } else if ((dwFlags & LMEM_MODIFY) == 0) {
  458. hMem = HPReAlloc(hheap, hMem, dwBytes, dwFlags | HP_NOSERIALIZE);
  459. } else {
  460. mmError(ERROR_INVALID_PARAMETER,
  461. "LocalReAlloc: can't use LMEM_MODIFY on fixed block\n");
  462. goto error;
  463. }
  464. exit:
  465. hpLeaveCriticalSection(hheap);
  466. return(hMem);
  467. error:
  468. hMem = 0;
  469. goto exit;
  470. }
  471. /***EP LocalLock - lock a local memory handle on the default heap
  472. *
  473. * ENTRY: hMem - handle to block
  474. * EXIT: flat pointer to block or 0 if error
  475. */
  476. LPVOID APIENTRY
  477. LocalLock(HANDLE hMem)
  478. {
  479. LPSTR pmem;
  480. struct heapinfo_s *hheap;
  481. struct lhandle_s *plh;
  482. hheap = (*pppdbCur)->hheapLocal;
  483. hpEnterCriticalSection(hheap);
  484. /*
  485. * Verify hMem is within the address range of the heap
  486. */
  487. if (VerifyOnHeap(hheap, hMem) == 0) {
  488. /*
  489. * We don't want this error to break into the debugger by default
  490. * user can call this with random address in some dialog routine
  491. * that it doesn't know if it has a handle or a pointer
  492. */
  493. DebugOut((DEB_WARN, "LocalLock: hMem out of range"));
  494. SetError(ERROR_INVALID_HANDLE);
  495. // mmError(ERROR_INVALID_HANDLE, "LocalLock: hMem out of range\n");
  496. goto error;
  497. }
  498. /*
  499. * Figure out if this is a handle by checking if the adress is aligned
  500. * in the right (wrong) way.
  501. */
  502. if ((ULONG)hMem & LH_HANDLEBIT) {
  503. /*
  504. * The handle value is aligned like a handle, but is it really one?
  505. * Verify it by checking the signature.
  506. */
  507. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  508. if (plh->lh_signature != LH_BUSYSIG) {
  509. mmError(ERROR_INVALID_HANDLE,
  510. "LocalLock: invalid hMem, bad signature\n");
  511. goto error;
  512. }
  513. /*
  514. * Increment the lock count unless we are already at the max
  515. */
  516. #ifdef HPDEBUG
  517. if (plh->lh_clock == LH_CLOCKMAX - 1) {
  518. dprintf(("LocalLock: lock count overflow, handle cannot be unlocked\n"));
  519. }
  520. #endif
  521. if (plh->lh_clock != LH_CLOCKMAX) {
  522. plh->lh_clock++;
  523. }
  524. pmem = plh->lh_pdata;
  525. /*
  526. * If the hMem passed in isn't a handle, it is supposed to be the
  527. * base address of a fixed block. We should validate that more, but NT
  528. * doesn't and I would hate to be incompatible. So instead, just
  529. * return the parameter except for the obvious error case of the block
  530. * being free.
  531. */
  532. } else {
  533. if (hpIsFreeSignatureValid((struct freeheap_s *)
  534. (((struct busyheap_s *)hMem) - 1))) {
  535. mmError(ERROR_INVALID_HANDLE,
  536. "LocalLock: hMem is pointer to free block\n");
  537. goto error;
  538. }
  539. pmem = hMem;
  540. }
  541. exit:
  542. hpLeaveCriticalSection(hheap);
  543. return(pmem);
  544. error:
  545. pmem = 0;
  546. goto exit;
  547. }
  548. /*** LocalCompact - obsolete function
  549. *
  550. * ENTRY: uMinFree - ignored
  551. * EXIT: 0
  552. */
  553. UINT APIENTRY
  554. LocalCompact(UINT uMinFree)
  555. {
  556. return(0);
  557. }
  558. /*** LocalShrink - obsolete function
  559. *
  560. * ENTRY: hMem - ignored
  561. * cbNewSize - ignored
  562. * EXIT: reserved size of the local heap
  563. */
  564. UINT APIENTRY
  565. LocalShrink(HANDLE hMem, UINT cbNewSize)
  566. {
  567. return((*pppdbCur)->hheapLocal->hi_cbreserve);
  568. }
  569. /*** LocalUnlock - unlock a local memory handle on the default heap
  570. *
  571. * ENTRY: hMem - handle to block
  572. * EXIT: 0 if unlocked or 1 is still locked
  573. */
  574. BOOL APIENTRY
  575. LocalUnlock(HANDLE hMem)
  576. {
  577. struct lhandle_s *plh;
  578. struct heapinfo_s *hheap;
  579. BOOL rc = 0;
  580. hheap = (*pppdbCur)->hheapLocal;
  581. hpEnterCriticalSection(hheap);
  582. /*
  583. * Verify hMem is within the address range of the heap
  584. */
  585. if (VerifyOnHeap(hheap, hMem) == 0) {
  586. mmError(ERROR_INVALID_HANDLE, "LocalUnlock: hMem out of range\n");
  587. goto exit;
  588. }
  589. /*
  590. * Figure out if this is a handle by checking if the adress is aligned
  591. * in the right (wrong) way.
  592. */
  593. if ((ULONG)hMem & LH_HANDLEBIT) {
  594. /*
  595. * Validate handle signature
  596. */
  597. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  598. if (plh->lh_signature != LH_BUSYSIG) {
  599. mmError(ERROR_INVALID_HANDLE,
  600. "LocalUnlock: invalid hMem, bad signature\n");
  601. goto exit;
  602. }
  603. /*
  604. * Decrement the lock count unless we are at the max
  605. */
  606. if (plh->lh_clock != LH_CLOCKMAX) {
  607. if (plh->lh_clock == 0) {
  608. /*
  609. * Just do a DebugOut since this is not an error per se,
  610. * though it probably indicates a bug in the app.
  611. */
  612. DebugOut((DEB_WARN, "LocalUnlock: not locked"));
  613. goto exit;
  614. }
  615. if (--plh->lh_clock != 0) {
  616. rc++;
  617. }
  618. }
  619. }
  620. exit:
  621. hpLeaveCriticalSection(hheap);
  622. return(rc);
  623. }
  624. /*** LocalSize - return the size of a memory block on the default heap
  625. *
  626. * ENTRY: hMem - handle (pointer) to block
  627. * EXIT: size in bytesof the block (not including header) or 0 if error
  628. */
  629. UINT APIENTRY
  630. LocalSize(HANDLE hMem)
  631. {
  632. struct heapinfo_s *hheap;
  633. struct lhandle_s *plh;
  634. DWORD rc = 0;
  635. DWORD delta = 0;
  636. hheap = (*pppdbCur)->hheapLocal;
  637. hpEnterCriticalSection(hheap);
  638. /*
  639. * Figure out if this is a handle by checking if the adress is aligned
  640. * in the right (wrong) way.
  641. */
  642. if ((ULONG)hMem & LH_HANDLEBIT) {
  643. /*
  644. * Verify hMem is within the address range of the heap
  645. */
  646. if (VerifyOnHeap(hheap, hMem) == 0) {
  647. mmError(ERROR_INVALID_HANDLE, "LocalSize: hMem out of range\n");
  648. goto error;
  649. }
  650. /*
  651. * Validate handle signature
  652. */
  653. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  654. if (plh->lh_signature != LH_BUSYSIG) {
  655. mmError(ERROR_INVALID_HANDLE,
  656. "LocalSize: invalid hMem, bad signature\n");
  657. goto error;
  658. }
  659. /*
  660. * Discarded handles have no size
  661. */
  662. if (plh->lh_pdata == 0) {
  663. goto error;
  664. }
  665. /*
  666. * Load up hMem with pointer to data for HeapSize call below
  667. */
  668. delta = sizeof(struct lhandle_s *);
  669. hMem = (char *)plh->lh_pdata - sizeof(struct lhandle_s *);
  670. }
  671. /*
  672. * Either this is a fixed block or we just loaded up the data address
  673. * above if it was moveable. Call HeapSize to do the real work.
  674. */
  675. rc = HeapSize(hheap, HP_NOSERIALIZE, hMem);
  676. /*
  677. * If this was a moveable block, subtract the 4 bytes for the back pointer
  678. */
  679. rc -= delta;
  680. exit:
  681. hpLeaveCriticalSection(hheap);
  682. return(rc);
  683. error:
  684. rc = 0;
  685. goto exit;
  686. }
  687. /*** LocalFlags - return the flags and lock count of block of def heap
  688. *
  689. * ENTRY: hMem - handle (pointer) to block on default heap
  690. * EXIT: flags in high 3 bytes, lock count in low byte (always 1)
  691. */
  692. UINT APIENTRY
  693. LocalFlags(HANDLE hMem)
  694. {
  695. struct heapinfo_s *hheap;
  696. struct lhandle_s *plh;
  697. DWORD rc = LMEM_INVALID_HANDLE;
  698. hheap = (*pppdbCur)->hheapLocal;
  699. hpEnterCriticalSection(hheap);
  700. /*
  701. * Verify hMem is within the address range of the heap
  702. */
  703. if (VerifyOnHeap(hheap, hMem) == 0) {
  704. mmError(ERROR_INVALID_HANDLE, "LocalFlags: hMem out of range\n");
  705. goto exit;
  706. }
  707. /*
  708. * We have to do our own pointer validation because the normal validation
  709. * layer doesn't support returning LMEM_INVALID_HANDLE for errors.
  710. */
  711. _try {
  712. /*
  713. * Figure out if this is a handle by checking if the adress is aligned
  714. * in the right (wrong) way.
  715. */
  716. if ((ULONG)hMem & LH_HANDLEBIT) {
  717. /*
  718. * Validate handle signature
  719. */
  720. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  721. if (plh->lh_signature != LH_BUSYSIG) {
  722. mmError(ERROR_INVALID_HANDLE,
  723. "LocalFlags: invalid hMem, bad signature\n");
  724. } else {
  725. rc = (ULONG)plh->lh_clock;
  726. if (plh->lh_pdata == 0) {
  727. rc |= LMEM_DISCARDED;
  728. }
  729. if (plh->lh_flags & LH_DISCARDABLE) {
  730. rc |= LMEM_DISCARDABLE;
  731. }
  732. }
  733. /*
  734. * For fixed blocks, validate the signature. NT always returns
  735. * 0 for most fixed-like values even if they aren't really
  736. * the start of blocks. If this causes an incompatibility we
  737. * can change this later.
  738. */
  739. } else {
  740. if (hpIsBusySignatureValid(((struct busyheap_s *)hMem) - 1)) {
  741. rc = 0;
  742. } else {
  743. mmError(ERROR_INVALID_HANDLE, "LocalFlags: invalid hMem\n");
  744. }
  745. }
  746. } _except (EXCEPTION_EXECUTE_HANDLER) {
  747. mmError(ERROR_INVALID_HANDLE, "LocalFlags: bad hMem");
  748. }
  749. exit:
  750. hpLeaveCriticalSection(hheap);
  751. return(rc);
  752. }
  753. /*** LocalHandle - return the handle for a block given its start address
  754. *
  755. * ENTRY: pMem - pointer to block on default heap
  756. * EXIT: handle for the block
  757. */
  758. HANDLE APIENTRY
  759. LocalHandle(PVOID pMem)
  760. {
  761. struct heapinfo_s *hheap;
  762. struct busyheap_s *pbh;
  763. unsigned long prevdword;
  764. struct lhandle_s *plh;
  765. HANDLE rc;
  766. hheap = (*pppdbCur)->hheapLocal;
  767. hpEnterCriticalSection(hheap);
  768. /*
  769. * Verify pMem is within the address range of the heap and aligned like
  770. * a heap block should be.
  771. */
  772. if (VerifyOnHeap(hheap, pMem) == 0) {
  773. mmError(ERROR_INVALID_HANDLE, "LocalHandle: pMem out of range\n");
  774. goto error;
  775. }
  776. /*
  777. * Figure out if this is a moveable block by seeing if the previous
  778. * dword points back to a handle.
  779. */
  780. prevdword = *(((unsigned long *)pMem) - 1);
  781. if (VerifyOnHeap(hheap, (PVOID)prevdword) != 0) {
  782. if (((struct lhandle_s *)prevdword)->lh_signature == LH_BUSYSIG) {
  783. /*
  784. * This sure looks like a moveable block with a handle. Return it.
  785. */
  786. rc = (HANDLE)(prevdword + LH_HANDLEBIT);
  787. goto exit;
  788. }
  789. }
  790. /*
  791. * Did they pass in a Handle???
  792. */
  793. if ((ULONG)pMem & LH_HANDLEBIT) {
  794. plh = (struct lhandle_s *)((char *)pMem - LH_HANDLEBIT);
  795. if (plh->lh_signature == LH_BUSYSIG) {
  796. rc = (HANDLE)pMem;
  797. SetError(ERROR_INVALID_HANDLE); /* NT Compat */
  798. goto exit;
  799. }
  800. }
  801. /*
  802. * If we get to here, the block is not preceded by a handle back pointer.
  803. * So either it is an invalid address or a fixed block.
  804. */
  805. pbh = (struct busyheap_s *)pMem - 1;
  806. if (hpIsBusySignatureValid(pbh) == 0) {
  807. /*
  808. * Not a heap block. Return error.
  809. */
  810. mmError(ERROR_INVALID_HANDLE, "LocalHandle: address not a heap block\n");
  811. goto error;
  812. /*
  813. * If we get here, we passed all the tests. Looks like we have a fixed
  814. * heap block, so just return the pointer as the handle.
  815. */
  816. } else {
  817. rc = pMem;
  818. }
  819. exit:
  820. hpLeaveCriticalSection(hheap);
  821. return(rc);
  822. error:
  823. rc = 0;
  824. goto exit;
  825. }
  826. extern WINBASEAPI BOOL WINAPI vHeapFree(HANDLE hHeap, DWORD dwFlags,
  827. LPVOID lpMem);
  828. /***EP LocalFreeNG - free a block on the default heap
  829. *
  830. * ENTRY: hMem - handle (pointer) to block to free
  831. * EXIT: NULL if success, else hMem if failure
  832. *
  833. * Special entry point used by the handle-grouping code to avoid unwanted
  834. * recursion.
  835. */
  836. HANDLE APIENTRY
  837. LocalFreeNG(HANDLE hMem)
  838. {
  839. struct heapinfo_s *hheap;
  840. struct lhandle_s *plh;
  841. void *pmem;
  842. /*
  843. * The spec says to ignore null pointers
  844. */
  845. if (hMem == 0) {
  846. goto exit;
  847. }
  848. hheap = (*pppdbCur)->hheapLocal;
  849. /*
  850. * Enter the heap critical section which serializes access to the handle
  851. * tables as well as the heap.
  852. */
  853. hpEnterCriticalSection(hheap);
  854. /*
  855. * Figure out if this is a handle by checking if the adress is aligned
  856. * in the right (wrong) way.
  857. */
  858. if ((ULONG)hMem & LH_HANDLEBIT) {
  859. /*
  860. * The handle value is aligned like a handle, but is it really one?
  861. * Verify it by making sure it is within the address range of the heap
  862. * and that it's signature is set right. HeapFree will verify things
  863. * more by checking that the pmem is valid.
  864. */
  865. if (VerifyOnHeap(hheap, hMem) == 0) {
  866. mmError(ERROR_INVALID_HANDLE, "LocalFree: hMem out of range\n");
  867. goto error;
  868. }
  869. plh = (struct lhandle_s *)((char *)hMem - LH_HANDLEBIT);
  870. /*
  871. * Do our own little parameter validation here because the normal
  872. * validation layer can't handle the odd-ball error return of hMem
  873. */
  874. {
  875. volatile UCHAR tryerror = 0;
  876. _try {
  877. tryerror &= (plh->lh_clock + (UCHAR)plh->lh_signature);
  878. } _except (EXCEPTION_EXECUTE_HANDLER) {
  879. tryerror = 1;
  880. }
  881. if (tryerror) {
  882. mmError(ERROR_INVALID_HANDLE, "LocalFree: invalid handle");
  883. goto error;
  884. }
  885. }
  886. if (plh->lh_signature != LH_BUSYSIG) {
  887. mmError(ERROR_INVALID_HANDLE,
  888. "LocalFree: invalid hMem, bad signature\n");
  889. goto error;
  890. }
  891. /*
  892. * You can't free a locked block
  893. */
  894. // Commenting out to keep MFC apps from ripping under debug.
  895. // Not that I'm a fan of shooting the messenger, but this particular
  896. // case seems to happen a lot because of the way Win3.x defined
  897. // GlobalLock. See Win95C:#12103 for the non-technical reasons for
  898. // this being a pri-1.
  899. //
  900. #if 0
  901. #ifdef HPDEBUG
  902. if (plh->lh_clock) {
  903. mmError(ERROR_INVALID_HANDLE, "LocalFree: locked\n");
  904. }
  905. #endif
  906. #endif
  907. /*
  908. * Don't bother freeing the block if it is already discarded.
  909. * When freeing we zero out the back pointer to the handle so
  910. * we don't get confused if someone tried to free a block twice.
  911. */
  912. if (plh->lh_pdata != 0) {
  913. pmem = (char *)plh->lh_pdata - sizeof(struct lhandle_s *);
  914. /*
  915. * Under some conditions with Office, this pointer can get trashed. We
  916. * need to make sure we don't AV
  917. */
  918. if (!IsBadWritePtr(pmem, sizeof(unsigned long))) {
  919. *((unsigned long *)pmem) = 0;
  920. if (HeapFree(hheap, HP_NOSERIALIZE, pmem) == 0) {
  921. goto error;
  922. }
  923. }
  924. }
  925. /*
  926. * Now free the handle structure and we are done.
  927. */
  928. plh->lh_freelink = (*pppdbCur)->plhFree;
  929. (*pppdbCur)->plhFree = plh;
  930. plh->lh_signature = LH_FREESIG;
  931. /*
  932. * The caller did not pass in a handle. Treat the value as a pointer.
  933. * HeapFree will do parameter validation on it.
  934. */
  935. } else {
  936. if (vHeapFree(hheap, HP_NOSERIALIZE, hMem) == 0) {
  937. goto error;
  938. }
  939. }
  940. hMem = 0; /* success */
  941. error:
  942. hpLeaveCriticalSection(hheap);
  943. exit:
  944. return(hMem);
  945. }
  946. /***EP HeapCreate - initialize a memory block as a flat heap
  947. *
  948. * ENTRY: flOptions - HEAP_NO_SERIALIZE: don't serialize access within process
  949. * (caller MUST)
  950. * HEAP_LOCKED: make memory fixed
  951. * HEAP_SHARED: put it in shared arena
  952. * dwInitialSize - initial committed memory in heap
  953. * dwMaximumSize - reserved size of heap memory
  954. * EXIT: handle to new heap, or 0 if error
  955. */
  956. HANDLE APIENTRY
  957. HeapCreate(DWORD flOptions, DWORD dwInitialSize, DWORD dwMaximumSize)
  958. {
  959. char *pmem;
  960. ULONG rc = 0; /* assume failure */
  961. /*
  962. * Don't allowed shared heaps - this only works on Win9x because there is a shared arena.
  963. */
  964. if (flOptions & HEAP_SHARED) {
  965. flOptions &= ~HEAP_SHARED;
  966. }
  967. /*
  968. * Although we don't really use InitialSize any more (except in growable
  969. * heaps) we should still enforce its sanity so apps don't get lazy
  970. */
  971. if (dwInitialSize > dwMaximumSize && dwMaximumSize != 0) {
  972. mmError(ERROR_INVALID_PARAMETER,
  973. "HeapCreate: dwInitialSize > dwMaximumSize\n");
  974. goto exit;
  975. }
  976. /*
  977. * Round the sizes up to the nearest page boundary
  978. */
  979. dwMaximumSize = (dwMaximumSize + PAGEMASK) & ~PAGEMASK;
  980. /*
  981. * A maximum size of 0 means growable. Start him out with 1meg, but allow
  982. * more.
  983. */
  984. if (dwMaximumSize == 0) {
  985. flOptions |= HP_GROWABLE;
  986. dwMaximumSize = 1*1024*1024 + (dwInitialSize & ~PAGEMASK);
  987. }
  988. /*
  989. * Allocate memory for the heap. Use PageCommit etc... rather than
  990. * VirtualAlloc for committing so we don't get zero-initialized stuff
  991. * and also we can commit fixed pages and reserve shared memory.
  992. */
  993. if (((ULONG)pmem =
  994. PageReserve((flOptions & HEAP_SHARED) ? PR_SHARED : PR_PRIVATE,
  995. dwMaximumSize / PAGESIZE,
  996. PR_STATIC |
  997. ((flOptions & HEAP_LOCKED) ? PR_FIXED : 0))) == -1) {
  998. mmError(ERROR_NOT_ENOUGH_MEMORY, "HeapCreate: reserve failed\n");
  999. goto exit;
  1000. }
  1001. /*
  1002. * Call HPInit to initialize the heap structures within the new memory
  1003. */
  1004. #if HEAP_NO_SERIALIZE - HP_NOSERIALIZE
  1005. # error HEAP_NO_SERIALIZE != HP_NOSERIALIZE
  1006. #endif
  1007. #if HEAP_GENERATE_EXCEPTIONS - HP_EXCEPT
  1008. # error HEAP_GENERATE_EXCEPTIONS != HP_EXCEPT
  1009. #endif
  1010. if (((PVOID)rc = HPInit(pmem, pmem, dwMaximumSize,
  1011. (flOptions &
  1012. (HP_EXCEPT|HP_NOSERIALIZE|HP_GROWABLE)))) == 0) {
  1013. goto free;
  1014. }
  1015. // if this is a shared heap and not the kernel heap, we don't
  1016. // want the critical section to go away until the heap is destroyed
  1017. if ( (flOptions & HEAP_SHARED) && hheapKernel ) {
  1018. MakeCriticalSectionGlobal( (CRITICAL_SECTION *)(&(((HHEAP)pmem)->hi_critsec)) );
  1019. }
  1020. /*
  1021. * Link private heaps onto the per-process heap list.
  1022. */
  1023. if ((flOptions & HEAP_SHARED) == 0) {
  1024. mmAssert(pppdbCur, "HeapCreate: private heap created too early");
  1025. ((struct heapinfo_s *)pmem)->hi_procnext = GetCurrentPdb()->hhi_procfirst;
  1026. GetCurrentPdb()->hhi_procfirst = (struct heapinfo_s *)pmem;
  1027. }
  1028. exit:
  1029. return((HANDLE)rc);
  1030. free:
  1031. PageFree(pmem, PR_STATIC);
  1032. goto exit;
  1033. }
  1034. /***EP HeapDestroy - free a heap allocated with HeapCreate
  1035. *
  1036. * ENTRY: hHeap - handle to heap to free
  1037. * EXIT: non-0 if success, or 0 if failure
  1038. */
  1039. BOOL APIENTRY
  1040. HeapDestroy(HHEAP hHeap)
  1041. {
  1042. ULONG rc;
  1043. struct heapinfo_s **ppheap;
  1044. struct heapseg_s *pseg;
  1045. struct heapseg_s *psegnext;
  1046. EnterMustComplete();
  1047. if ((rc = hpTakeSem(hHeap, 0, 0)) == 0) {
  1048. goto exit;
  1049. }
  1050. /*
  1051. * We now hold the heap's semaphore. Quickly clear the semaphore and
  1052. * delete the semaphore. If someone comes in and blocks on the semaphore
  1053. * between the time we clear it and destroy it, tough luck. They will
  1054. * probably fault in a second.
  1055. */
  1056. hpClearSem(hHeap, 0);
  1057. if ((hHeap->hi_flags & HP_NOSERIALIZE) == 0) {
  1058. if (hHeap == hheapKernel) {
  1059. DestroyCrst(hHeap->hi_pcritsec);
  1060. } else {
  1061. Assert(hHeap->hi_pcritsec->typObj == typObjCrst);
  1062. if (hHeap->hi_pcritsec->typObj == typObjCrst) {
  1063. DisposeCrst(hHeap->hi_pcritsec);
  1064. }
  1065. }
  1066. }
  1067. /*
  1068. * For private heaps, find it on the per-process heap list and remove it.
  1069. */
  1070. if ((ULONG)hHeap < MAXPRIVATELADDR) {
  1071. ppheap = &(GetCurrentPdb()->hhi_procfirst);
  1072. for (; *ppheap != hHeap; ppheap = &((*ppheap)->hi_procnext)) {
  1073. mmAssert(*ppheap != 0, "HeapDestroy: heap not on list");
  1074. }
  1075. *ppheap = hHeap->hi_procnext; /* remove from list */
  1076. }
  1077. /*
  1078. * Free the heap memory
  1079. */
  1080. pseg = (struct heapseg_s *)hHeap;
  1081. do {
  1082. psegnext = pseg->hs_psegnext;
  1083. PageFree(pseg, PR_STATIC);
  1084. pseg = psegnext;
  1085. } while (pseg != 0);
  1086. exit:
  1087. LeaveMustComplete();
  1088. return(rc);
  1089. }
  1090. /***EP HeapAlloc - allocate a fixed/zero-init'ed block from the specified heap
  1091. *
  1092. * ENTRY: hHeap - heap handle (pointer to base of heap)
  1093. * dwFlags - HEAP_ZERO_MEMORY
  1094. * dwBytes - count of bytes to allocate
  1095. * EXIT: pointer to block or 0 if failure
  1096. */
  1097. LPVOID APIENTRY
  1098. HeapAlloc(HANDLE hHeap, DWORD dwFlags, DWORD dwBytes)
  1099. {
  1100. // WordArt (32) overwrites some of his local heap blocks. So
  1101. // we pad his allocations some. Slacker.
  1102. if (GetAppCompatFlags() & GACF_HEAPSLACK) {
  1103. if (hHeap == GetCurrentPdb()->hheapLocal) {
  1104. dwBytes += 16;
  1105. }
  1106. }
  1107. return(HPAlloc((HHEAP)hHeap, dwBytes, (dwFlags & HEAP_GENERATE_EXCEPTIONS) |
  1108. ((dwFlags & HEAP_ZERO_MEMORY) ? HP_ZEROINIT : 0)));
  1109. }
  1110. /***EP HeapReAlloc - resize a memory block on a specified heap
  1111. *
  1112. * ENTRY: hHeap - heap handle (pointer to base of heap)
  1113. * dwFlags - HEAP_REALLOC_IN_PLACE_ONLY
  1114. * HEAP_ZERO_MEMORY
  1115. * lpMem - pointer to block to resize
  1116. * dwBytes - new size requested
  1117. * EXIT: flat pointer to resized block, or 0 if failure
  1118. */
  1119. LPVOID APIENTRY
  1120. HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPSTR lpMem, DWORD dwBytes)
  1121. {
  1122. return((HANDLE)HPReAlloc((HHEAP)hHeap,
  1123. lpMem,
  1124. dwBytes,
  1125. (dwFlags & (HEAP_NO_SERIALIZE | HP_EXCEPT)) |
  1126. ((dwFlags & HEAP_REALLOC_IN_PLACE_ONLY) ? 0 : HP_MOVEABLE) |
  1127. ((dwFlags & HEAP_ZERO_MEMORY) ? HP_ZEROINIT : 0)));
  1128. }
  1129. //--------------------------------------------------------------------------
  1130. // ToolHelp32 heapwalking code.
  1131. //--------------------------------------------------------------------------
  1132. /*---------------------------------------------------------------------------
  1133. * BOOL SafeReadProcessMemory(PPDB ppdb,
  1134. * LPVOID lpBuffer,
  1135. * DWORD cbSizeOfBuffer,
  1136. * DWORD cbBytesToRead);
  1137. *
  1138. * Reads memory from another process's context.
  1139. *---------------------------------------------------------------------------*/
  1140. BOOL KERNENTRY SafeReadProcessMemory(PPDB ppdb,
  1141. DWORD dwBaseAddr,
  1142. LPVOID lpBuffer,
  1143. DWORD cbSizeOfBuffer,
  1144. DWORD cbBytesToRead)
  1145. {
  1146. BOOL fRes;
  1147. #ifdef DEBUG
  1148. if (cbSizeOfBuffer != 0) {
  1149. FillBytes(lpBuffer, cbSizeOfBuffer, 0xcc);
  1150. }
  1151. if (cbSizeOfBuffer < cbBytesToRead) {
  1152. DebugOut((DEB_ERR, "SafeReadProcessMemory: Input buffer too small."));
  1153. return FALSE;
  1154. }
  1155. #endif
  1156. if (!(fRes = ReadProcessMemoryFromPDB(ppdb,
  1157. (LPVOID)dwBaseAddr,
  1158. lpBuffer,
  1159. cbBytesToRead,
  1160. NULL))) {
  1161. #ifdef DEBUG
  1162. DebugOut((DEB_WARN, "SafeReadProcessMemory: Failed ReadProcessMemory()"));
  1163. #endif
  1164. return FALSE;
  1165. }
  1166. return TRUE;
  1167. }
  1168. /*---------------------------------------------------------------------------
  1169. * Make sure the caller initialized HEAPENTRY32 properly.
  1170. *---------------------------------------------------------------------------*/
  1171. BOOL KERNENTRY ValidateHeapEntry32(LPHEAPENTRY32 lphe32)
  1172. {
  1173. if ((lphe32 == NULL) || (lphe32->dwSize != sizeof(HEAPENTRY32))) {
  1174. DebugOut((DEB_ERR, "HEAPENTRY32: Wrong version or dwSize."));
  1175. return FALSE;
  1176. }
  1177. return TRUE;
  1178. }
  1179. /*---------------------------------------------------------------------------
  1180. * Test if a linear address could plausibly be the start of a block header.
  1181. *---------------------------------------------------------------------------*/
  1182. BOOL KERNENTRY IsValidBlockHdrAddr(LPHEAPENTRY32 lphe32, DWORD dwAddr)
  1183. {
  1184. LPTHSTATE lpts;
  1185. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1186. /*
  1187. * A good block is always in the user address space and dword aligned
  1188. */
  1189. if ((dwAddr & 0x3) || dwAddr < MINPRIVATELADDR || dwAddr >= MAXSHAREDLADDR) {
  1190. return FALSE;
  1191. }
  1192. return TRUE;
  1193. }
  1194. /*---------------------------------------------------------------------------
  1195. * Test if a linear address could plausibly be the start of block data.
  1196. *---------------------------------------------------------------------------*/
  1197. BOOL KERNENTRY IsValidBlockDataAddr(LPHEAPENTRY32 lphe32, DWORD dwAddr)
  1198. {
  1199. return(IsValidBlockHdrAddr(lphe32, dwAddr));
  1200. }
  1201. /*---------------------------------------------------------------------------
  1202. * Read in and validate a lharray_s.
  1203. *---------------------------------------------------------------------------*/
  1204. BOOL KERNENTRY SafeRdCurLHA(LPHEAPENTRY32 lphe32, DWORD dwBaseAddr)
  1205. {
  1206. LPTHSTATE lpts;
  1207. struct lharray_s lha;
  1208. if (!(ValidateHeapEntry32(lphe32))) {
  1209. return FALSE;
  1210. }
  1211. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1212. if (!IsValidBlockDataAddr(lphe32, dwBaseAddr)) {
  1213. return FALSE;
  1214. }
  1215. if (!SafeReadProcessMemory(lpts->ppdb,
  1216. dwBaseAddr,
  1217. &lha,
  1218. sizeof(lha),
  1219. sizeof(lha))) {
  1220. return FALSE;
  1221. }
  1222. // Check signature.
  1223. if (lha.lha_signature != LHA_SIGNATURE) {
  1224. DebugOut((DEB_WARN, "lharray_s (%lx) has bad signature.", dwBaseAddr));
  1225. return FALSE;
  1226. }
  1227. if (lha.lha_next && !IsValidBlockDataAddr(lphe32, (DWORD)lha.lha_next)) {
  1228. DebugOut((DEB_WARN, "lharray_s (%lx) has bad next link.", dwBaseAddr));
  1229. return FALSE;
  1230. }
  1231. lpts->curlha = lha;
  1232. lpts->curlhaaddr = dwBaseAddr;
  1233. return TRUE;
  1234. }
  1235. /*---------------------------------------------------------------------------
  1236. * Insert a handle value to be suppressed when reading fixed blocks later.
  1237. *---------------------------------------------------------------------------*/
  1238. BOOL KERNENTRY InsertSuppress(LPHEAPENTRY32 lphe32, DWORD dwSupp)
  1239. {
  1240. LPTHSTATE lpts;
  1241. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1242. if (!(lpts->lpdwSuppress)) {
  1243. #ifdef DEBUG
  1244. DebugOut((DEB_ERR, "Internal error: lpdwSuppress == NULL."));
  1245. #endif
  1246. return FALSE;
  1247. }
  1248. if (lpts->nSuppUsed >= lpts->nSuppAvail) {
  1249. #ifdef DEBUG
  1250. DebugOut((DEB_ERR, "Internal error: lpdwSuppress too small."));
  1251. #endif
  1252. return FALSE;
  1253. }
  1254. lpts->lpdwSuppress[lpts->nSuppUsed++] = dwSupp;
  1255. return TRUE;
  1256. }
  1257. /*---------------------------------------------------------------------------
  1258. * Validate and decode a heap block header.
  1259. *---------------------------------------------------------------------------*/
  1260. BOOL KERNENTRY DissectBlockHdr(LPHEAPENTRY32 lphe32,
  1261. DWORD dwAddr,
  1262. DWORD *lpdwSize,
  1263. DWORD *lpdwFlags,
  1264. DWORD *lpdwAddr)
  1265. {
  1266. DWORD dwHdr;
  1267. LPTHSTATE lpts;
  1268. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1269. if (!IsValidBlockHdrAddr(lphe32, dwAddr)) {
  1270. return FALSE;
  1271. }
  1272. *lpdwFlags = HP_SIGNATURE ^ ((DWORD)0xffffffff);
  1273. if (!SafeReadProcessMemory(lpts->ppdb,
  1274. dwAddr,
  1275. &dwHdr,
  1276. sizeof(dwHdr),
  1277. sizeof(DWORD))) {
  1278. return FALSE;
  1279. }
  1280. if ( (dwHdr & HP_SIGBITS) != HP_SIGNATURE ) {
  1281. return FALSE;
  1282. }
  1283. *lpdwSize = dwHdr & HP_SIZE;
  1284. *lpdwFlags = dwHdr & HP_FLAGS;
  1285. *lpdwAddr = dwAddr + ( (dwHdr & HP_FREE) ?
  1286. sizeof(struct freeheap_s) :
  1287. sizeof(struct busyheap_s) );
  1288. if (*lpdwSize != 0 &&
  1289. !IsValidBlockHdrAddr(lphe32, dwAddr + (*lpdwSize))) {
  1290. return FALSE;
  1291. }
  1292. return TRUE;
  1293. }
  1294. /*---------------------------------------------------------------------------
  1295. * Check if we're at the end of the heap (heap is terminated by a
  1296. * busy block of size 0).
  1297. *---------------------------------------------------------------------------*/
  1298. BOOL KERNENTRY AtEndOfHeap32(LPHEAPENTRY32 lphe32)
  1299. {
  1300. LPTHSTATE lpts;
  1301. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1302. if (lpts->dwMode != THM_FIXEDHANDLES) {
  1303. return FALSE;
  1304. }
  1305. return (!((lpts->dwBlkFlags) & HP_FREE) &&
  1306. (lpts->dwBlkSize) == 0);
  1307. }
  1308. /*---------------------------------------------------------------------------
  1309. * Internal routine (maybe make it an api?). Deallocate all internal
  1310. * state used for heap-walking.
  1311. *---------------------------------------------------------------------------*/
  1312. VOID KERNENTRY RealHeap32End(LPHEAPENTRY32 lphe32)
  1313. {
  1314. LPTHSTATE lpts;
  1315. if (!(ValidateHeapEntry32(lphe32))) {
  1316. return;
  1317. }
  1318. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1319. // In case someone calls this after they've fallen off the end.
  1320. if (lpts == NULL) {
  1321. return;
  1322. }
  1323. EnterMustComplete();
  1324. if (lpts->pcrst) {
  1325. DisposeCrst(lpts->pcrst);
  1326. lpts->pcrst = NULL;
  1327. }
  1328. LeaveMustComplete();
  1329. if (lpts->lpdwSuppress) {
  1330. FKernelFree(lpts->lpdwSuppress);
  1331. lpts->lpdwSuppress = NULL;
  1332. }
  1333. FKernelFree(lpts);
  1334. lphe32->dwResvd = 0;
  1335. FillBytes(( (char*)lphe32 ) + 4, sizeof(HEAPENTRY32) - 4, 0);
  1336. }
  1337. /*---------------------------------------------------------------------------
  1338. * Copy current heap object into HEAPENTRY32 for caller's consumption.
  1339. * To skip this object, set *pfInteresting to FALSE.
  1340. *---------------------------------------------------------------------------*/
  1341. BOOL KERNENTRY CopyIntoHeap32Entry(LPHEAPENTRY32 lphe32, BOOL *pfInteresting)
  1342. {
  1343. LPTHSTATE lpts;
  1344. *pfInteresting = TRUE;
  1345. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1346. switch (lpts->dwMode) {
  1347. case THM_LHANDLES: {
  1348. DWORD dwSize;
  1349. DWORD dwFlags;
  1350. DWORD dwAddr;
  1351. DWORD dwHnd;
  1352. struct lhandle_s *plh;
  1353. plh = &(lpts->curlha.lha_lh[lpts->nNextLH]);
  1354. if (plh->lh_signature == LH_FREESIG) {
  1355. *pfInteresting = FALSE;
  1356. return TRUE;
  1357. }
  1358. if (plh->lh_signature != LH_BUSYSIG) {
  1359. DebugOut((DEB_WARN, "lhandle_s has bad signature."));
  1360. return FALSE;
  1361. }
  1362. dwHnd = ( (DWORD)(&(plh->lh_pdata)) ) -
  1363. ( (DWORD)(&(lpts->curlha)) ) +
  1364. lpts->curlhaaddr;
  1365. if (!plh->lh_pdata) {
  1366. // Discarded handle.
  1367. lphe32->hHandle = (HANDLE)dwHnd;
  1368. lphe32->dwAddress = 0;
  1369. lphe32->dwBlockSize = 0;
  1370. lphe32->dwFlags = LF32_MOVEABLE;
  1371. lphe32->dwLockCount = (DWORD)(plh->lh_clock);
  1372. return TRUE;
  1373. }
  1374. if (!DissectBlockHdr(lphe32,
  1375. ( (DWORD)(plh->lh_pdata) ) - 4 - sizeof(struct busyheap_s),
  1376. &dwSize,
  1377. &dwFlags,
  1378. &dwAddr
  1379. )) {
  1380. return FALSE; // This will be caught someplace else.
  1381. }
  1382. if (dwFlags & HP_FREE) {
  1383. DebugOut((DEB_WARN, "Local handle points to freed block!"));
  1384. return FALSE;
  1385. }
  1386. if (!InsertSuppress(lphe32,
  1387. dwAddr-sizeof(struct busyheap_s))) {
  1388. return FALSE;
  1389. }
  1390. lphe32->hHandle = (HANDLE)dwHnd;
  1391. lphe32->dwAddress = dwAddr + 4;
  1392. lphe32->dwBlockSize = dwSize - sizeof(struct busyheap_s) - 4;
  1393. lphe32->dwFlags = LF32_MOVEABLE;
  1394. lphe32->dwLockCount = (DWORD)(plh->lh_clock);
  1395. return TRUE;
  1396. }
  1397. case THM_FIXEDHANDLES: {
  1398. if ((lpts->dwBlkFlags) & HP_FREE) {
  1399. lphe32->hHandle = NULL;
  1400. lphe32->dwAddress = lpts->dwBlkAddr;
  1401. lphe32->dwBlockSize = lpts->dwBlkSize - sizeof(struct freeheap_s);
  1402. lphe32->dwFlags = LF32_FREE;
  1403. lphe32->dwLockCount = 0;
  1404. } else {
  1405. // Supress if it's a lharray_s or the target of
  1406. // an lhandle. Opt: we could check the first dword
  1407. // to rule out lots of blocks.
  1408. if (lpts->lpdwSuppress) {
  1409. DWORD *lpdw, *lpdwEnd;
  1410. DWORD dwHdrAddr = lpts->lpHBlock;
  1411. lpdwEnd = &(lpts->lpdwSuppress[lpts->nSuppUsed]);
  1412. for (lpdw = lpts->lpdwSuppress; lpdw < lpdwEnd; lpdw++) {
  1413. if (dwHdrAddr == *lpdw) {
  1414. *pfInteresting = FALSE;
  1415. return TRUE;
  1416. }
  1417. }
  1418. }
  1419. lphe32->hHandle = (HANDLE)(lpts->dwBlkAddr);
  1420. lphe32->dwAddress = lpts->dwBlkAddr;
  1421. lphe32->dwBlockSize = lpts->dwBlkSize - sizeof(struct busyheap_s);
  1422. lphe32->dwFlags = LF32_FIXED;
  1423. lphe32->dwLockCount = 0;
  1424. }
  1425. return TRUE;
  1426. }
  1427. case THM_ERROR:
  1428. DebugOut((DEB_ERR, "Internal error: Can't get here"));
  1429. return FALSE;
  1430. case THM_DONE:
  1431. DebugOut((DEB_ERR, "Internal error: Can't get here"));
  1432. return FALSE;
  1433. default:
  1434. DebugOut((DEB_ERR, "Internal error: Bad lpthstate.dwmode"));
  1435. return FALSE;
  1436. }
  1437. }
  1438. /*---------------------------------------------------------------------------
  1439. * Worker routine for AdvanceHeap32(): handles the init case.
  1440. *
  1441. * If the heap is the owning pdb's default heap (determined by
  1442. * comparing hHeap with ppdb->hHeapLocal), point the state to
  1443. * the first lharray_s. Otherwise, point the state to the first heap block.
  1444. *
  1445. *---------------------------------------------------------------------------*/
  1446. BOOL KERNENTRY AdvanceHeap32Init(LPHEAPENTRY32 lphe32)
  1447. {
  1448. LPTHSTATE lpts;
  1449. struct lharray_s *lpha;
  1450. DWORD dwNumSupp;
  1451. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1452. lpha = lpts->ppdb->plhBlock;
  1453. if (lpts->ppdb->hheapLocal != lpts->hHeap || lpha == NULL) {
  1454. lpts->dwMode = THM_FIXEDHANDLES;
  1455. lpts->lpHBlock = lpts->lpbMin;
  1456. if (!DissectBlockHdr(lphe32,
  1457. lpts->lpHBlock,
  1458. &(lpts->dwBlkSize),
  1459. &(lpts->dwBlkFlags),
  1460. &(lpts->dwBlkAddr))) {
  1461. return FALSE;
  1462. }
  1463. return TRUE;
  1464. }
  1465. if (!SafeRdCurLHA(lphe32, (DWORD)lpha)) {
  1466. return FALSE;
  1467. }
  1468. dwNumSupp = (lpts->curlha.lha_membercount + 1) * (1 + CLHGROW);
  1469. if (!(lpts->lpdwSuppress = PvKernelAlloc0(dwNumSupp * sizeof(DWORD)))) {
  1470. return FALSE;
  1471. }
  1472. lpts->nSuppAvail = dwNumSupp * sizeof(DWORD);
  1473. lpts->nSuppUsed = 0;
  1474. if (!(InsertSuppress(lphe32, ((DWORD)lpha) - sizeof(struct busyheap_s)))) {
  1475. return FALSE;
  1476. }
  1477. lpts->nNextLH = 0;
  1478. lpts->dwMode = THM_LHANDLES;
  1479. return TRUE;
  1480. }
  1481. /*---------------------------------------------------------------------------
  1482. * Worker routine for AdvanceHeap32(): handles the lhandle case.
  1483. *---------------------------------------------------------------------------*/
  1484. BOOL KERNENTRY AdvanceHeap32Movable(LPHEAPENTRY32 lphe32)
  1485. {
  1486. LPTHSTATE lpts;
  1487. WORD wOldMemberCnt;
  1488. DWORD dwAddrNext;
  1489. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1490. if (lpts->nNextLH < CLHGROW-1) {
  1491. lpts->nNextLH++;
  1492. return TRUE;
  1493. }
  1494. // End of current lhandle clump reached. Any new ones?
  1495. if (lpts->curlha.lha_next == NULL) {
  1496. // Nope. Go on to fixed handles.
  1497. lpts->dwMode = THM_FIXEDHANDLES;
  1498. lpts->lpHBlock = lpts->lpbMin;
  1499. if (!DissectBlockHdr(lphe32,
  1500. lpts->lpHBlock,
  1501. &(lpts->dwBlkSize),
  1502. &(lpts->dwBlkFlags),
  1503. &(lpts->dwBlkAddr))) {
  1504. return FALSE;
  1505. }
  1506. return TRUE;
  1507. }
  1508. // Get next lhandle clump.
  1509. wOldMemberCnt = lpts->curlha.lha_membercount;
  1510. dwAddrNext = (DWORD)(lpts->curlha.lha_next);
  1511. if (!SafeRdCurLHA(lphe32, dwAddrNext)) {
  1512. return FALSE;
  1513. }
  1514. if (lpts->curlha.lha_membercount >= wOldMemberCnt) {
  1515. DebugOut((DEB_WARN, "lha_array clusters in wrong order."));
  1516. return FALSE;
  1517. }
  1518. lpts->nNextLH = 0;
  1519. return TRUE;
  1520. }
  1521. /*---------------------------------------------------------------------------
  1522. * Worker routine for AdvanceHeap32(): handles the fixed block case.
  1523. *---------------------------------------------------------------------------*/
  1524. BOOL KERNENTRY AdvanceHeap32Fixed(LPHEAPENTRY32 lphe32)
  1525. {
  1526. LPTHSTATE lpts;
  1527. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1528. // Diassect block has already checked monotonocity and range.
  1529. lpts->lpHBlock += lpts->dwBlkSize;
  1530. if (!DissectBlockHdr(lphe32,
  1531. lpts->lpHBlock,
  1532. &(lpts->dwBlkSize),
  1533. &(lpts->dwBlkFlags),
  1534. &(lpts->dwBlkAddr)
  1535. )) {
  1536. return FALSE;
  1537. }
  1538. return TRUE;
  1539. }
  1540. /*---------------------------------------------------------------------------
  1541. * Advance the internal state to the next heap object. Validate the
  1542. * next heap object.
  1543. *---------------------------------------------------------------------------*/
  1544. BOOL KERNENTRY AdvanceHeap32(LPHEAPENTRY32 lphe32)
  1545. {
  1546. LPTHSTATE lpts;
  1547. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1548. switch (lpts->dwMode) {
  1549. case THM_INIT:
  1550. return AdvanceHeap32Init(lphe32);
  1551. case THM_LHANDLES:
  1552. return AdvanceHeap32Movable(lphe32);
  1553. case THM_FIXEDHANDLES:
  1554. return AdvanceHeap32Fixed(lphe32);
  1555. default:
  1556. DebugOut((DEB_ERR, "Illegal or unexpected THM mode."));
  1557. return FALSE;
  1558. }
  1559. }
  1560. /*---------------------------------------------------------------------------
  1561. * Does the real work of heap32next().
  1562. *---------------------------------------------------------------------------*/
  1563. VOID KERNENTRY Heap32NextWorker(LPHEAPENTRY32 lphe32)
  1564. {
  1565. LPTHSTATE lpts;
  1566. BOOL fInteresting;
  1567. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1568. do {
  1569. if (!AdvanceHeap32(lphe32)) {
  1570. goto rh_error;
  1571. }
  1572. if (AtEndOfHeap32(lphe32)) {
  1573. /*
  1574. * We might be at the end of the heap, or just at the end of
  1575. * this heap segment. If there is another segment, read its
  1576. * header in and process its blocks.
  1577. */
  1578. if (lpts->hi.hi_psegnext) {
  1579. lpts->lpbMin = ((DWORD)lpts->hi.hi_psegnext) + sizeof(struct heapseg_s);
  1580. /*
  1581. * Read in the next heap segment header and setup our bounds to
  1582. * refer to it
  1583. */
  1584. if (!(SafeReadProcessMemory(lpts->ppdb,
  1585. (DWORD)lpts->hi.hi_psegnext,
  1586. &(lpts->hi),
  1587. sizeof(struct heapseg_s),
  1588. sizeof(struct heapseg_s)))) {
  1589. #ifdef DEBUG
  1590. DebugOut((DEB_WARN, "Heap32NextWorker(): Invalid or corrupt psegnext: %lx\n", lpts->hi.hi_psegnext));
  1591. #endif
  1592. goto rh_error;
  1593. }
  1594. if (lpts->hi.hi_cbreserve > hpMAXALLOC ||
  1595. ((lpts->hi.hi_cbreserve) & PAGEMASK)) {
  1596. #ifdef DEBUG
  1597. DebugOut((DEB_WARN, "Heap32NextWorker(): Invalid or corrupt psegnext (3): %lx\n", lpts->lpbMin - sizeof(struct heapseg_s)));
  1598. #endif
  1599. goto rh_error;
  1600. }
  1601. /*
  1602. * Setup first block on new segment
  1603. */
  1604. lpts->lpHBlock = lpts->lpbMin;
  1605. if (!DissectBlockHdr(lphe32,
  1606. lpts->lpHBlock,
  1607. &(lpts->dwBlkSize),
  1608. &(lpts->dwBlkFlags),
  1609. &(lpts->dwBlkAddr))) {
  1610. goto rh_error;
  1611. }
  1612. /*
  1613. * If we really are at the end of the heap, we are all done
  1614. */
  1615. } else {
  1616. lpts->dwMode = THM_DONE;
  1617. return;
  1618. }
  1619. }
  1620. fInteresting = TRUE;
  1621. if (!CopyIntoHeap32Entry(lphe32, &fInteresting)) {
  1622. goto rh_error;
  1623. }
  1624. } while (!fInteresting);
  1625. return;
  1626. rh_error:
  1627. lpts->dwMode = THM_ERROR;
  1628. return;
  1629. }
  1630. /*---------------------------------------------------------------------------
  1631. * Does the real work of Heap32Next().
  1632. *---------------------------------------------------------------------------*/
  1633. BOOL KERNENTRY RealHeap32Next(LPHEAPENTRY32 lphe32)
  1634. {
  1635. LPTHSTATE lpts;
  1636. DWORD dwMode;
  1637. if (!(ValidateHeapEntry32(lphe32))) {
  1638. SetError(ERROR_INVALID_PARAMETER);
  1639. return FALSE;
  1640. }
  1641. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1642. // In case someone calls this after they've fallen off the end.
  1643. if (lpts == NULL) {
  1644. SetError(ERROR_INVALID_PARAMETER);
  1645. return FALSE;
  1646. }
  1647. EnterCrst(lpts->pcrst);
  1648. Heap32NextWorker(lphe32);
  1649. dwMode = lpts->dwMode;
  1650. LeaveCrst(lpts->pcrst);
  1651. if (dwMode == THM_ERROR ||
  1652. dwMode == THM_DONE) {
  1653. if (dwMode == THM_ERROR) {
  1654. DebugOut((DEB_WARN, "Heap32Next detected corrupted or moving heap. Bailing."));
  1655. SetError(ERROR_INVALID_DATA);
  1656. } else {
  1657. SetError(ERROR_NO_MORE_FILES);
  1658. }
  1659. RealHeap32End(lphe32);
  1660. return FALSE;
  1661. }
  1662. return TRUE;
  1663. }
  1664. /*---------------------------------------------------------------------------
  1665. * Create the internal state used inside HEAPENTRY32.
  1666. *---------------------------------------------------------------------------*/
  1667. BOOL KERNENTRY InitHeapEntry32(PPDB ppdb,
  1668. HANDLE hHeap,
  1669. LPHEAPENTRY32 lphe32)
  1670. {
  1671. LPTHSTATE lpts = NULL;
  1672. CRST *pcrst = NULL;
  1673. if (!ValidateHeapEntry32(lphe32)) {
  1674. return FALSE;
  1675. }
  1676. EnterMustComplete();
  1677. if (!(lphe32->dwResvd = (DWORD)PvKernelAlloc0(sizeof(THSTATE)))) {
  1678. goto ih_error;
  1679. }
  1680. lpts = (LPTHSTATE)(lphe32->dwResvd);
  1681. if (!(pcrst = lpts->pcrst = NewCrst())) {
  1682. goto ih_error;
  1683. }
  1684. lpts->ppdb = ppdb;
  1685. lpts->hHeap = hHeap;
  1686. if (!(SafeReadProcessMemory(ppdb,
  1687. (DWORD)hHeap,
  1688. &(lpts->hi),
  1689. sizeof(lpts->hi),
  1690. sizeof(struct heapinfo_s)))) {
  1691. #ifdef DEBUG
  1692. DebugOut((DEB_WARN, "Heap32First(): Invalid hHeap: %lx\n", hHeap));
  1693. #endif
  1694. goto ih_error;
  1695. }
  1696. if (lpts->hi.hi_signature != HI_SIGNATURE) {
  1697. #ifdef DEBUG
  1698. DebugOut((DEB_WARN, "Heap32First(): Invalid or corrupt hHeap: %lx\n", hHeap));
  1699. #endif
  1700. goto ih_error;
  1701. }
  1702. lpts->lpbMin = ( (DWORD)hHeap ) + sizeof(struct heapinfo_s);
  1703. if (lpts->hi.hi_cbreserve > hpMAXALLOC ||
  1704. ((lpts->hi.hi_cbreserve) & PAGEMASK)) {
  1705. #ifdef DEBUG
  1706. DebugOut((DEB_WARN, "Heap32First(): Invalid or corrupt hHeap: %lx\n", hHeap));
  1707. #endif
  1708. goto ih_error;
  1709. }
  1710. lpts->dwMode = THM_INIT;
  1711. LeaveMustComplete();
  1712. return TRUE;
  1713. ih_error:
  1714. if (lpts) {
  1715. FKernelFree(lpts);
  1716. }
  1717. if (pcrst) {
  1718. DisposeCrst(pcrst);
  1719. }
  1720. lphe32->dwResvd = 0;
  1721. LeaveMustComplete();
  1722. return FALSE;
  1723. }
  1724. /***LP VerifyOnHeap - verifies a given address is on a given heap
  1725. *
  1726. * Note that no validation is done on the given address except
  1727. * to check that it is in the range of the heap.
  1728. *
  1729. * ENTRY: hheap - heap handle
  1730. * p - address to verify
  1731. * EXIT: 0 if not within specified heap, non-zero if on
  1732. */
  1733. ULONG INTERNAL
  1734. VerifyOnHeap(HHEAP hheap, PVOID p)
  1735. {
  1736. struct heapseg_s *pseg;
  1737. /*
  1738. * Loop through each heap segment and see if the specified address
  1739. * is within it.
  1740. */
  1741. pseg = (struct heapseg_s *)hheap;
  1742. do {
  1743. if ((unsigned)p > (unsigned)pseg &&
  1744. (unsigned)p < (unsigned)pseg + pseg->hs_cbreserve) {
  1745. return(1); /* found it */
  1746. }
  1747. pseg = pseg->hs_psegnext;
  1748. } while (pseg != 0);
  1749. return(0); /* didn't find it */
  1750. }
  1751. /***LP CheckHeapFreeAppHack - See if CVPACK app-hack applies
  1752. *
  1753. * Check to see if an absolutely sick, disgusting and vomit-inducing
  1754. * app-hack for link.exe (msvc 1.5) is needed. msvc 1.5. Link.exe
  1755. * uses the contents of a heap block after it has freed it.
  1756. * This routine stack-traces and reads the caller's code
  1757. * to see if it matches the offending profile. This part is written
  1758. * in C so we can use try-except.
  1759. */
  1760. BOOL KERNENTRY
  1761. CheckHeapFreeAppHack(DWORD *lpdwESP, DWORD *lpdwEBP, DWORD dwESI)
  1762. {
  1763. BOOL fDoAppHack = FALSE;
  1764. _try {
  1765. DWORD *lpdwEIPCaller;
  1766. lpdwEIPCaller = (DWORD*)(*lpdwESP);
  1767. if (0xc35de58b == *lpdwEIPCaller) { // "mov esp,ebp;pop ebp; retd"
  1768. DWORD *lpdwEIPCallersCaller;
  1769. lpdwEIPCallersCaller = (DWORD*)(*(lpdwEBP + 1));
  1770. if (0x8b04c483 == *lpdwEIPCallersCaller &&
  1771. 0xf60b0876 == *(lpdwEIPCallersCaller+1)) {
  1772. //"add esp,4; mov esi, [esi+8]; or esi,esi"
  1773. if (dwESI == *(lpdwESP+3)) {
  1774. fDoAppHack = TRUE;
  1775. }
  1776. }
  1777. }
  1778. } _except (EXCEPTION_EXECUTE_HANDLER) {
  1779. }
  1780. return fDoAppHack;
  1781. }