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.

1164 lines
30 KiB

  1. /*************************************************************************
  2. * *
  3. * MEMALLO.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990-1992 *
  6. * All Rights reserved. *
  7. * *
  8. **************************************************************************
  9. * *
  10. * Module Intent *
  11. * Debugging memory management module. The purpose of this module is *
  12. * to ensure that memories are allocated, locked, unlocked and freed *
  13. * properly. The following examples show some common mistakes, which *
  14. * may cause havoc, and are hard to find: *
  15. * - Use LocalFree() instead GlobalFree() for a global memory, and *
  16. * vice versa. This bug will cause subtle error and possible system *
  17. * crashes *
  18. * - Lock or free garbage handle: will cause random system crashes *
  19. * - Check for unfreed memory *
  20. * *
  21. * Note: All the local memory management scheme have been removed *
  22. * - Since it will not work for DLL (using DS of the DLL instead *
  23. * of the app *
  24. * - There is plan to not to use local memory (to avoid 64K limit) *
  25. **************************************************************************
  26. * *
  27. * Current Owner: BinhN *
  28. * *
  29. *************************************************************************/
  30. #include <mvopsys.h>
  31. #ifdef _DEBUG // {
  32. #include <misc.h>
  33. #include <mem.h>
  34. #include <iterror.h>
  35. #include "critsec.h"
  36. #if !defined( MOSMEM ) // {
  37. typedef struct tagMEMPOOL
  38. {
  39. HANDLE hnd;
  40. DWORD size;
  41. char FAR *lszFileName;
  42. UINT line;
  43. } MEMPOOL;
  44. // Under multitasking Win32, protect debug functions by critical section
  45. // We only protect simultaneous ALLOC & FREE. Lock and Unlock are not
  46. // protected against each other because these cases are not supposed to happen
  47. static CCriticalSection gcsMemory;
  48. #define ENTER_CRITICAL_SECTION EnterCriticalSection(gcsMemory)
  49. #define LEAVE_CRITICAL_SECTION LeaveCriticalSection(gcsMemory)
  50. // make sure it is near to allow multiple instances
  51. // for static case
  52. static MEMPOOL FAR *GlobalPool=NULL;
  53. static UINT GlobalPoolIndex = 0;
  54. static UINT GlobalPoolSize=0;
  55. static DWORD GlobalMemUsed = 0;
  56. /*************************************************************************
  57. *
  58. * GLOBAL FUNCTIONS
  59. *************************************************************************/
  60. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalAlloc(UINT, DWORD, LPSTR, UINT);
  61. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalReAlloc(HANDLE, DWORD,
  62. UINT, LPSTR, UINT);
  63. PUBLIC LPVOID EXPORT_API PASCAL FAR _GlobalLock(HANDLE, LPSTR, UINT);
  64. PUBLIC int EXPORT_API PASCAL FAR _GlobalUnlock(HANDLE, LPSTR, UINT);
  65. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalFree(HANDLE, LPSTR, UINT);
  66. /*************************************************************************
  67. * @doc INTERNAL DEBUG
  68. *
  69. * @func VOID NEAR PASCAL | MakeGlobalPool |
  70. * Just break inside CodeView
  71. *************************************************************************/
  72. PUBLIC VOID EXPORT_API PASCAL FAR MakeGlobalPool (void)
  73. {
  74. GlobalPool = (MEMPOOL FAR *)GlobalAllocPtr(DLLGMEM_ZEROINIT,
  75. sizeof(MEMPOOL)*2000);
  76. GlobalPoolSize = 2000;
  77. GlobalMemUsed = 0;
  78. GlobalPoolIndex = 0;
  79. }
  80. PUBLIC VOID EXPORT_API PASCAL FAR FreeGlobalPool (void)
  81. {
  82. if (GlobalPool)
  83. GlobalFreePtr (GlobalPool);
  84. GlobalPool = NULL;
  85. GlobalPoolSize = 0;
  86. }
  87. /*************************************************************************
  88. * @doc INTERNAL DEBUG
  89. *
  90. * @func int NEAR PASCAL | MemErr |
  91. * Output the error
  92. *
  93. * @parm int | err |
  94. * Error code
  95. *
  96. * @parm LPSTR | lszFilename |
  97. * Module where the function is invoked
  98. *
  99. * @parm UINT | line |
  100. * Line where the function is invoked
  101. *
  102. * @rdesc Corresponding error
  103. *************************************************************************/
  104. int NEAR PASCAL MemErr(int err, LPSTR lszFilename, UINT line)
  105. {
  106. char Buffer[510];
  107. switch (err)
  108. {
  109. case E_NOHANDLE:
  110. wsprintf (Buffer, "No memory handle left. File: %s, line:%d\n",
  111. lszFilename, line);
  112. break;
  113. case E_OUTOFMEMORY:
  114. wsprintf (Buffer, "Out of memory. File: %s, line:%d\n",
  115. lszFilename, line);
  116. break;
  117. case E_HANDLE:
  118. wsprintf (Buffer, "Invalid handle. File: %s, line:%d\n",
  119. lszFilename, line);
  120. break;
  121. case E_INVALIDARG:
  122. wsprintf (Buffer, "Free locked handle. File: %s, line:%d\n",
  123. lszFilename, line);
  124. break;
  125. case E_ASSERT:
  126. wsprintf (Buffer, "Releasing invalid handle. File: %s, line:%d\n",
  127. lszFilename, line);
  128. break;
  129. case E_FAIL:
  130. wsprintf (Buffer, "Buffer overwritten. File: %s, line:%d\n",
  131. lszFilename, line);
  132. break;
  133. case S_OK:
  134. // wsprintf (Buffer, "Buffer > 64K. File: %s, line:%d\n",
  135. // lszFilename, line);
  136. return err;
  137. break;
  138. }
  139. OutputDebugString (Buffer);
  140. return(err);
  141. }
  142. void DumpMemory (void)
  143. {
  144. register UINT i;
  145. char szTemp[1024];
  146. ENTER_CRITICAL_SECTION;
  147. /* Check in global memory pool */
  148. for (i = 0; i <= GlobalPoolIndex; i++)
  149. {
  150. wsprintf(szTemp, "%u\t\t%s\t%u\n",
  151. GlobalPool[i].size,
  152. GlobalPool[i].lszFileName,
  153. GlobalPool[i].line);
  154. OutputDebugString(szTemp);
  155. }
  156. LEAVE_CRITICAL_SECTION;
  157. }
  158. /*************************************************************************
  159. * @doc INTERNAL DEBUG
  160. *
  161. * @func UINT NEAR PASCAL | CheckMemValidity |
  162. * Make sure that we really did allocate the specified handle
  163. *
  164. * @parm HANDLE | hnd |
  165. * Handle to be checked
  166. *
  167. * @parm LPSTR | lszFilename |
  168. * Module where the function is invoked
  169. *
  170. * @parm UINT | line |
  171. * Line where the function is invoked
  172. *
  173. * @rdesc GlobalPoolSize + 1 if invalid handle, else the
  174. * index of the pool location
  175. *************************************************************************/
  176. PRIVATE UINT NEAR PASCAL CheckMemValidity (HANDLE hnd, LPSTR lszFilename,
  177. UINT line)
  178. {
  179. register UINT i;
  180. // erinfox: critical section around this function because _GlobalLock
  181. // and _GlobalUnlock use it
  182. ENTER_CRITICAL_SECTION;
  183. /* Check in global memory pool */
  184. for (i = 0; i <= GlobalPoolIndex; i++)
  185. {
  186. if (GlobalPool[i].hnd == hnd)
  187. {
  188. LEAVE_CRITICAL_SECTION;
  189. return i;
  190. }
  191. }
  192. // if i is GlobalPoolSize, handle isn't truly "invalid" - it's
  193. // just not part of the pool (because we've filled the pool)
  194. if (i < GlobalPoolSize)
  195. MemErr (E_HANDLE, lszFilename, line);
  196. LEAVE_CRITICAL_SECTION;
  197. return i;
  198. }
  199. /*************************************************************************
  200. * @doc INTERNAL DEBUG
  201. *
  202. * @func HANDLE PASCAL | _GlobalAlloc |
  203. * Allocate a near block of memory via GlobalAlloc. The number of
  204. * handles is actually limited by GlobalPoolSize
  205. *
  206. * @parm UINT | flag |
  207. * Various windows memory flags (such as GMEM_ZEROINIT)
  208. *
  209. * @parm DWORD | size |
  210. * Size of the block
  211. *
  212. * @parm LPSTR | lpszFile |
  213. * Module where the function is invoked
  214. *
  215. * @parm UINT | line |
  216. * Line where the function is invoked
  217. *
  218. * @rdesc Handle to the block of memory if succeded, 0 otherwise
  219. *************************************************************************/
  220. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalAlloc(UINT flag, DWORD size,
  221. LPSTR lszFilename, UINT line)
  222. {
  223. register UINT i, j;
  224. MEMPOOL FAR *pMem = NULL;
  225. #if 0
  226. BYTE HUGE *lpb;
  227. #endif
  228. HANDLE hnd;
  229. ENTER_CRITICAL_SECTION;
  230. if (GlobalPool==NULL)
  231. MakeGlobalPool();
  232. /* Find an available handle */
  233. for (i = 0; i < GlobalPoolSize; i++)
  234. {
  235. if (GlobalPool[i].hnd == 0)
  236. {
  237. pMem = &GlobalPool[i];
  238. break;
  239. }
  240. }
  241. if (pMem == NULL)
  242. {
  243. LEAVE_CRITICAL_SECTION;
  244. MemErr (E_NOHANDLE, lszFilename, line);
  245. return GlobalAlloc(flag, size);
  246. }
  247. /* Update index */
  248. if (GlobalPoolIndex < i)
  249. GlobalPoolIndex = i;
  250. if ((hnd = GlobalAlloc(flag, size + 1)) == NULL)
  251. {
  252. LEAVE_CRITICAL_SECTION;
  253. MemErr(E_OUTOFMEMORY, lszFilename, line);
  254. return(NULL);
  255. }
  256. #if 0
  257. /* Add buffer overflow checking */
  258. if (lpb = GlobalLock (hnd))
  259. {
  260. *(lpb + size) = 'x';
  261. GlobalUnlock (hnd);
  262. }
  263. #endif
  264. /* Check to see if any other location has the same handle
  265. * If happens since we may return a handle back to the user,
  266. * who will eventually free it without our knowledge
  267. */
  268. for (j = 0; j <= GlobalPoolIndex; j++)
  269. {
  270. if (j == i)
  271. continue;
  272. if (GlobalPool[j].hnd == hnd)
  273. {
  274. if (GlobalPool[j].size == (DWORD)-1)
  275. break; // Reuse that "released" block
  276. else
  277. MemErr (E_ASSERT, lszFilename, line);
  278. pMem = &GlobalPool[j];
  279. }
  280. }
  281. pMem->hnd = hnd;
  282. pMem->size = size;
  283. pMem->lszFileName = lszFilename;
  284. pMem->line = line;
  285. GlobalMemUsed += size;
  286. LEAVE_CRITICAL_SECTION;
  287. return (pMem->hnd);
  288. }
  289. /*************************************************************************
  290. * @doc INTERNAL DEBUG
  291. *
  292. * @func HANDLE PASCAL | _GlobalReAlloc |
  293. * Allocate a near block of memory via GlobalReAlloc. The function
  294. * makes sure that we did allocate the memory block
  295. *
  296. * @parm HANDLE | handle |
  297. * Handle to memory block
  298. *
  299. * @parm DWORD | size |
  300. * Size of the block
  301. *
  302. * @parm WORD | flag |
  303. * Various windows memory flags (such as GMEM_ZEROINIT)
  304. *
  305. * @parm LPSTR | lszFilename |
  306. * Module where the function is invoked
  307. *
  308. * @parm UINT | line |
  309. * Line where the function is invoked
  310. *
  311. * @rdesc Return the new handle, or 0 if failed
  312. *************************************************************************/
  313. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalReAlloc(HANDLE handle,
  314. DWORD size, UINT flag, LPSTR lszFilename, UINT line)
  315. {
  316. register UINT i;
  317. MEMPOOL FAR *pMem = NULL;
  318. ENTER_CRITICAL_SECTION;
  319. for (i = 0; i <= GlobalPoolIndex; i++)
  320. {
  321. if (GlobalPool[i].hnd == handle)
  322. {
  323. pMem = &GlobalPool[i];
  324. break;
  325. }
  326. }
  327. if (pMem == NULL)
  328. {
  329. LEAVE_CRITICAL_SECTION;
  330. MemErr(E_HANDLE, lszFilename, line);
  331. return GlobalReAlloc(handle, size, flag);
  332. }
  333. if (size) {
  334. #if 0
  335. BYTE HUGE *lpb;
  336. if (pMem->size < size)
  337. {
  338. /* We have to remove the last 'x' that we put in */
  339. lpb = GlobalLock (pMem->hnd);
  340. lpb [pMem->size] = 0;
  341. GlobalUnlock (pMem->hnd);
  342. }
  343. #endif
  344. GlobalMemUsed += size - pMem->size;
  345. pMem->size = size;
  346. if ((pMem->hnd = GlobalReAlloc(handle, size + 1, flag)) == NULL)
  347. MemErr(E_OUTOFMEMORY, lszFilename, line);
  348. #if 0
  349. if (lpb = GlobalLock (pMem->hnd))
  350. {
  351. *(lpb + size) = 'x';
  352. GlobalUnlock (pMem->hnd);
  353. }
  354. #endif
  355. }
  356. else
  357. {
  358. if ((pMem->hnd = GlobalReAlloc(handle, size, flag)) == NULL)
  359. MemErr(E_OUTOFMEMORY, lszFilename, line);
  360. }
  361. pMem->lszFileName = lszFilename;
  362. pMem->line = line;
  363. LEAVE_CRITICAL_SECTION;
  364. return (pMem->hnd);
  365. }
  366. /*************************************************************************
  367. * @doc INTERNAL DEBUG
  368. *
  369. * @func LPVOID PASCAL FAR | _GlobalLock |
  370. * Lock a piece of far memory via GlobalLock
  371. *
  372. * @parm HANDLE | hnd |
  373. * Memory handle to be locked
  374. *
  375. * @parm LPSTR | lszFilename |
  376. * Module where the function is invoked
  377. *
  378. * @parm UINT | line |
  379. * Line where the function is invoked
  380. *
  381. * @rdesc Pointer to the block of memory if succeeded, else NULL
  382. *************************************************************************/
  383. PUBLIC LPVOID EXPORT_API PASCAL FAR _GlobalLock(HANDLE hnd,
  384. LPSTR lszFilename, UINT line)
  385. {
  386. if (hnd == 0)
  387. {
  388. // GarrG - removed call to MemErr. Locking a NULL handle
  389. // is a valid thing to try, since it eliminates the necessity
  390. // of checking for NULL twice (on the handle AND on the
  391. // result of GlobalLock).
  392. return NULL;
  393. }
  394. /* Check for data integrity */
  395. CheckMemValidity(hnd, lszFilename, line);
  396. return (LPVOID)GlobalLock(hnd);
  397. }
  398. /*************************************************************************
  399. * @doc INTERNAL DEBUG
  400. *
  401. * @func DWORD PASCAL FAR | _GlobalSize |
  402. * Return the size of a block of memory
  403. *
  404. * @parm HANDLE | hnd |
  405. * Handle to memory block
  406. *
  407. * @parm LPSTR | lszFilename |
  408. * Module where the function is invoked
  409. *
  410. * @parm UINT | line |
  411. * Line where the function is invoked
  412. *
  413. * @rdesc Size of the block of memory
  414. *************************************************************************/
  415. PUBLIC DWORD EXPORT_API PASCAL FAR _GlobalSize(HANDLE hnd,
  416. LPSTR lszFilename, UINT line)
  417. {
  418. UINT i;
  419. if (hnd == 0)
  420. {
  421. MemErr(E_HANDLE, lszFilename, line);
  422. return 0;
  423. }
  424. /* Check for data integrity */
  425. if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
  426. {
  427. MemErr(E_HANDLE, lszFilename, line);
  428. return (DWORD) GlobalSize(hnd);
  429. }
  430. return (GlobalPool[i].size);
  431. }
  432. /*************************************************************************
  433. * @doc INTERNAL DEBUG
  434. *
  435. * @func int PASCAL | _GlobalUnlock |
  436. * Unlock a handle. Memory validity is checked for invalid handle
  437. *
  438. * @parm HANDLE | hnd |
  439. * Handle to be unlocked
  440. *
  441. * @parm LPSTR | lszFilename |
  442. * Module where the function is invoked
  443. *
  444. * @parm UINT | line |
  445. * Line where the function is invoked
  446. *
  447. * @rdesc If the handle is valid, return GlobalUnlock(), else -1.
  448. * In case of failure the returned value has not much validity
  449. *************************************************************************/
  450. PUBLIC int EXPORT_API PASCAL FAR _GlobalUnlock(HANDLE hnd,
  451. LPSTR lszFilename, UINT line)
  452. {
  453. #if 0
  454. BYTE HUGE *lpb;
  455. #endif
  456. register UINT i;
  457. MEMPOOL FAR *pMem;
  458. if (hnd == 0)
  459. {
  460. MemErr(E_HANDLE, lszFilename, line);
  461. return -1;
  462. }
  463. /* Check for data integrity */
  464. if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
  465. {
  466. return(GlobalUnlock(hnd));
  467. }
  468. pMem = &GlobalPool[i];
  469. /* Now check for buffer overflow. This only works for memory allocated
  470. * by us, ie. not through _GlobalAdd(), which in this case, has the
  471. * size = -1
  472. */
  473. #if 0
  474. if (pMem->size != (DWORD)-1)
  475. {
  476. if (lpb = GlobalLock (hnd))
  477. {
  478. if (*(lpb + pMem->size) != 'x')
  479. MemErr(E_FAIL, lszFilename, line);
  480. GlobalUnlock(hnd);
  481. }
  482. }
  483. #endif
  484. return GlobalUnlock(hnd);
  485. }
  486. /*************************************************************************
  487. * @doc INTERNAL DEBUG
  488. *
  489. * @func HANDLE PASCAL | _GlobalFree |
  490. * Free the global memory. Memory validity is checked to ensure that
  491. * we don't free an invalid handle
  492. *
  493. * @parm HANDLE | hnd |
  494. * Handle to the global memory to be freed
  495. *
  496. * @parm LPSTR | lszFilename |
  497. * Module where the function is invoked
  498. *
  499. * @parm UINT | line |
  500. * Line where the function is invoked
  501. *
  502. * @rdesc Return NULL if failed, else the handle
  503. *************************************************************************/
  504. PUBLIC HANDLE EXPORT_API PASCAL FAR _GlobalFree(HANDLE hnd,
  505. LPSTR lszFilename, UINT line)
  506. {
  507. register UINT i;
  508. HANDLE h;
  509. int count;
  510. if (hnd == 0)
  511. {
  512. MemErr(E_HANDLE, lszFilename, line);
  513. return 0;
  514. }
  515. if (hnd == (HANDLE)-1)
  516. DumpMemory();
  517. ENTER_CRITICAL_SECTION;
  518. /* Check for data integrity */
  519. if ((i = (CheckMemValidity(hnd, lszFilename, line))) >= GlobalPoolSize)
  520. {
  521. MemErr (E_ASSERT, lszFilename, line);
  522. return (GlobalFree(hnd));
  523. }
  524. if (GlobalPool[i].size == (DWORD)-1)
  525. {
  526. /* We are freeing a pointer passed to us from the user, who has
  527. * the responsibility to free it. This may be a bug.
  528. */
  529. // MemErr (E_ASSERT, lszFilename, line);
  530. GlobalPool[i].size = 0;
  531. }
  532. if ((count = (GlobalFlags(hnd) & GMEM_LOCKCOUNT)) > 0)
  533. {
  534. /* Freeing locked handle */
  535. MemErr(E_INVALIDARG, lszFilename, line);
  536. while (count > 0)
  537. {
  538. GlobalUnlock (hnd);
  539. count--;
  540. }
  541. }
  542. h = GlobalFree(hnd);
  543. GlobalMemUsed -= GlobalPool[i].size;
  544. GlobalPool[i].size = 0;
  545. GlobalPool[i].lszFileName = NULL;
  546. GlobalPool[i].hnd = 0;
  547. GlobalPool[i].line = 0;
  548. LEAVE_CRITICAL_SECTION ;
  549. return h ;
  550. }
  551. /*************************************************************************
  552. * @doc INTERNAL DEBUG
  553. *
  554. * @func HANDLE PASCAL | _GlobalRelease |
  555. * There are case when we allocated memory blocks in MV and return
  556. * them to the user. It is the user's responsibility to free this
  557. * block.In this case, all the memory allocations scheme can't apply.
  558. * In the meantime, we still want to keep track of all memory
  559. * allocation. So this routine will remove the handle from the
  560. * memory pool without really releasing it. It just stops tracking
  561. * that piece of memory
  562. *
  563. * @parm HANDLE | hnd |
  564. * Handle to be released from the memory pool
  565. *
  566. * @parm LPSTR | lszFilename |
  567. * Module where the function is invoked
  568. *
  569. * @parm UINT | line |
  570. * Line where the function is invoked
  571. *************************************************************************/
  572. HANDLE EXPORT_API PASCAL FAR _GlobalRelease (HANDLE hnd, LPSTR lszFilename,
  573. UINT line)
  574. {
  575. register UINT i;
  576. MEMPOOL FAR *pMem;
  577. ENTER_CRITICAL_SECTION;
  578. if (hnd == 0)
  579. {
  580. LEAVE_CRITICAL_SECTION;
  581. MemErr(E_HANDLE, lszFilename, line);
  582. return (hnd);
  583. }
  584. /* Check for data integrity */
  585. if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
  586. {
  587. LEAVE_CRITICAL_SECTION;
  588. MemErr(E_HANDLE, lszFilename, line);
  589. return (hnd);
  590. }
  591. pMem = &GlobalPool[i];
  592. #if 0
  593. if (pMem->size != (DWORD)-1)
  594. {
  595. BYTE HUGE *lpb;
  596. if (lpb = (LPSTR)GlobalLock (hnd))
  597. {
  598. if (lpb[pMem->size] == 'x')
  599. lpb[pMem->size] = 0;
  600. GlobalUnlock(hnd);
  601. }
  602. GlobalMemUsed -= pMem->size;
  603. }
  604. #endif
  605. pMem->size = 0;
  606. pMem->lszFileName = NULL;
  607. pMem->hnd = 0;
  608. pMem->line = 0;
  609. LEAVE_CRITICAL_SECTION;
  610. return(hnd);
  611. }
  612. /*************************************************************************
  613. * @doc INTERNAL DEBUG
  614. *
  615. * @func EXPORT_API FAR PASCAL | _GlobalAdd |
  616. * There are case when we receive a handle from the user to be
  617. * manipulated (lock, unlock) etc. To make it works with our
  618. * memory scheme, we need to put this into the memory table to be
  619. * able to track it.
  620. *
  621. * @parm HANDLE | hnd |
  622. * Handle to be added to the memory pool
  623. *
  624. * @parm LPSTR | lszFilename |
  625. * Module where the function is invoked
  626. *
  627. * @parm UINT | line |
  628. * Line where the function is invoked
  629. *************************************************************************/
  630. HANDLE EXPORT_API PASCAL FAR _GlobalAdd (HANDLE hnd, LPSTR lszFilename,
  631. UINT line)
  632. {
  633. register UINT i;
  634. UINT j = (UINT)-1;
  635. MEMPOOL FAR *pMem = NULL;
  636. ENTER_CRITICAL_SECTION;
  637. if (GlobalPool==NULL)
  638. MakeGlobalPool();
  639. /* Find an available handle */
  640. for (i = 0; i < GlobalPoolSize; i++)
  641. {
  642. if (GlobalPool[i].hnd == 0)
  643. {
  644. if (j == (UINT)-1)
  645. j = i;
  646. }
  647. else if (GlobalPool[i].hnd == hnd)
  648. {
  649. LEAVE_CRITICAL_SECTION;
  650. return hnd; // Already in the pool
  651. }
  652. }
  653. if (j == (UINT)-1)
  654. {
  655. LEAVE_CRITICAL_SECTION;
  656. MemErr (E_NOHANDLE, lszFilename, line);
  657. return NULL;
  658. }
  659. if (GlobalPoolIndex < j)
  660. GlobalPoolIndex = j;
  661. pMem = &GlobalPool[j];
  662. pMem->size = (DWORD)-1; // Mark that the buffer came from outside
  663. pMem->lszFileName = lszFilename;
  664. pMem->line = line;
  665. pMem->hnd = hnd;
  666. LEAVE_CRITICAL_SECTION;
  667. return hnd;
  668. }
  669. PUBLIC DWORD EXPORT_API PASCAL FAR GetMemUsed()
  670. {
  671. return GlobalMemUsed;
  672. }
  673. /*************************************************************************
  674. * @doc INTERNAL DEBUG
  675. *
  676. * @func DWORD PASCAL | CheckMem |
  677. * Make sure that all memory blocks are freed properly
  678. *
  679. * @rdesc Number of unfreed bytes
  680. *************************************************************************/
  681. PUBLIC DWORD EXPORT_API PASCAL FAR CheckMem()
  682. {
  683. register UINT i;
  684. DWORD dwUnreleasedMem = 0;
  685. HANDLE hnd;
  686. char Buffer[500]; // 100 is not safe when filenames are real long.
  687. LPSTR szFile ;
  688. if ((GlobalMemUsed) == 0) {
  689. FreeGlobalPool();
  690. return 0;
  691. }
  692. if (GlobalPool) // When called several times, protect against null ptr
  693. {
  694. for (i = 0; i <= GlobalPoolIndex; i++)
  695. {
  696. if ((hnd = GlobalPool[i].hnd) && GlobalPool[i].size != (DWORD)-1)
  697. { // This pool is not released
  698. dwUnreleasedMem += GlobalPool[i].size;
  699. #ifdef WIN32
  700. // When the DLL containing the string has been unloaded, we run into big troubles -> check
  701. if (GlobalPool[i].lszFileName && !IsBadStringPtr(GlobalPool[i].lszFileName, sizeof(Buffer)/2))
  702. szFile = GlobalPool[i].lszFileName ;
  703. else
  704. szFile = "File Unavailable" ;
  705. #else // dunno if this would work on other platforms...
  706. szFile = GlobalPool[i].lszFileName ;
  707. #endif
  708. wsprintf (Buffer,
  709. "Unreleased GM at: %d, Size: %ld, Alloc at: %s, Line: %d\r\n",
  710. i, GlobalPool[i].size, szFile,
  711. GlobalPool[i].line);
  712. OutputDebugString (Buffer);
  713. /* Release the pool */
  714. GlobalPool[i].hnd = 0;
  715. GlobalUnlock(hnd);
  716. GlobalFree(hnd);
  717. }
  718. }
  719. }
  720. else
  721. dwUnreleasedMem = GlobalMemUsed ;
  722. GlobalPoolIndex = 0;
  723. FreeGlobalPool();
  724. return dwUnreleasedMem;
  725. }
  726. #ifndef _MAC // {
  727. /*************************************************************************
  728. * @doc INTERNAL DEBUG
  729. *
  730. * @func HANDLE PASCAL | _VirtualAlloc |
  731. * Allocate a block of memory via VirtualAlloc. The number of
  732. * handles is actually limited by GlobalPoolSize
  733. *
  734. * @parm LPVOID | lpAddr |
  735. * Address of region to be allocated
  736. *
  737. * @parm DWORD | size |
  738. * Size of the block
  739. *
  740. * @parm DWORD | flag |
  741. * Type of allocation
  742. *
  743. * @parm DWORD | fProtect |
  744. * Type of access protection
  745. *
  746. * @parm LPSTR | lpszFile |
  747. * Module where the function is invoked
  748. *
  749. * @parm UINT | line |
  750. * Line where the function is invoked
  751. *
  752. * @rdesc Handle to the block of memory if succeded, 0 otherwise
  753. *************************************************************************/
  754. PUBLIC HANDLE EXPORT_API PASCAL FAR _VirtualAlloc(LPVOID lpAddr, DWORD size,
  755. DWORD flag, DWORD fProtect, LPSTR lszFilename, UINT line)
  756. {
  757. register UINT i, j;
  758. MEMPOOL FAR *pMem = NULL;
  759. #if 0
  760. BYTE HUGE *lpb;
  761. #endif
  762. HANDLE hnd;
  763. ENTER_CRITICAL_SECTION;
  764. if (GlobalPool==NULL)
  765. MakeGlobalPool();
  766. /* Find an available handle */
  767. for (i = 0; i < GlobalPoolSize; i++)
  768. {
  769. if (GlobalPool[i].hnd == 0)
  770. {
  771. pMem = &GlobalPool[i];
  772. break;
  773. }
  774. }
  775. if (pMem == NULL)
  776. {
  777. LEAVE_CRITICAL_SECTION;
  778. MemErr (E_NOHANDLE, lszFilename, line);
  779. return (HANDLE)VirtualAlloc(NULL, size, flag, fProtect);
  780. }
  781. /* Update index */
  782. if (GlobalPoolIndex < i)
  783. GlobalPoolIndex = i;
  784. if ((hnd = (HANDLE)VirtualAlloc(NULL, size,
  785. flag, fProtect)) == NULL)
  786. {
  787. MemErr(E_OUTOFMEMORY, lszFilename, line);
  788. return(NULL);
  789. }
  790. /* Check to see if any other location has the same handle
  791. * If happens since we may return a handle back to the user,
  792. * who will eventually free it without our knowledge
  793. */
  794. for (j = 0; j <= GlobalPoolIndex; j++)
  795. {
  796. if (j == i)
  797. continue;
  798. if (GlobalPool[j].hnd == hnd)
  799. {
  800. if (GlobalPool[j].size == (DWORD)-1)
  801. break; // Reuse that "released" block
  802. else
  803. MemErr (E_ASSERT, lszFilename, line);
  804. pMem = &GlobalPool[j];
  805. }
  806. }
  807. pMem->hnd = hnd;
  808. pMem->size = size;
  809. pMem->lszFileName = lszFilename;
  810. pMem->line = line;
  811. GlobalMemUsed += size;
  812. LEAVE_CRITICAL_SECTION;
  813. return (pMem->hnd);
  814. }
  815. /*************************************************************************
  816. * @doc INTERNAL DEBUG
  817. *
  818. * @func LPVOID PASCAL FAR | __VirtualLock |
  819. * Lock a piece of far memory via VirtualLock
  820. *
  821. * @parm HANDLE | hnd |
  822. * Memory handle to be locked
  823. *
  824. * @parm DWORD | size |
  825. * Size of memory to be locked
  826. *
  827. * @parm LPSTR | lszFilename |
  828. * Module where the function is invoked
  829. *
  830. * @parm UINT | line |
  831. * Line where the function is invoked
  832. *
  833. * @rdesc Pointer to the block of memory if succeeded, else NULL
  834. *************************************************************************/
  835. PUBLIC LPVOID EXPORT_API PASCAL FAR _VirtualLock(HANDLE hnd, DWORD size,
  836. LPSTR lszFilename, UINT line)
  837. {
  838. if (hnd == 0)
  839. {
  840. // GarrG - removed call to MemErr. Locking a NULL handle
  841. // is a valid thing to try, since it eliminates the necessity
  842. // of checking for NULL twice (on the handle AND on the
  843. // result of VirtualLock).
  844. return NULL;
  845. }
  846. /* Check for data integrity */
  847. CheckMemValidity(hnd, lszFilename, line);
  848. return (LPVOID)(VirtualLock(hnd, size) ? &hnd : NULL);
  849. }
  850. /*************************************************************************
  851. * @doc INTERNAL DEBUG
  852. *
  853. * @func int PASCAL | _VirtualUnlock |
  854. * Unlock a handle. Memory validity is checked for invalid handle
  855. *
  856. * @parm HANDLE | hnd |
  857. * Handle to be unlocked
  858. *
  859. * @parm LPSTR | lszFilename |
  860. * Module where the function is invoked
  861. *
  862. * @parm UINT | line |
  863. * Line where the function is invoked
  864. *
  865. * @rdesc If the handle is valid, return VirtualUnlock(), else -1.
  866. * In case of failure the returned value has not much validity
  867. *************************************************************************/
  868. PUBLIC int EXPORT_API PASCAL FAR _VirtualUnlock(HANDLE hnd,
  869. DWORD size, LPSTR lszFilename, UINT line)
  870. {
  871. #if 0
  872. BYTE HUGE *lpb;
  873. #endif
  874. register UINT i;
  875. MEMPOOL FAR *pMem;
  876. if (hnd == 0)
  877. {
  878. MemErr(E_HANDLE, lszFilename, line);
  879. return -1;
  880. }
  881. /* Check for data integrity */
  882. if ((i = CheckMemValidity(hnd, lszFilename, line)) >= GlobalPoolSize)
  883. {
  884. return(GlobalUnlock(hnd));
  885. }
  886. pMem = &GlobalPool[i];
  887. /* Now check for buffer overflow. This only works for memory allocated
  888. * by us, ie. not through _GlobalAdd(), which in this case, has the
  889. * size = -1
  890. */
  891. #if 0
  892. if (pMem->size != (DWORD)-1)
  893. {
  894. if (lpb = GlobalLock (hnd))
  895. {
  896. if (*(lpb + pMem->size) != 'x')
  897. MemErr(E_FAIL, lszFilename, line);
  898. GlobalUnlock(hnd);
  899. }
  900. }
  901. #endif
  902. return VirtualUnlock(hnd, size);
  903. }
  904. /*************************************************************************
  905. * @doc INTERNAL DEBUG
  906. *
  907. * @func int PASCAL | _VirtualFree |
  908. * Free the global memory. Memory validity is checked to ensure that
  909. * we don't free an invalid handle
  910. *
  911. * @parm HANDLE | hnd |
  912. * Handle to the global memory to be freed
  913. *
  914. * @parm LPSTR | lszFilename |
  915. * Module where the function is invoked
  916. *
  917. * @parm UINT | line |
  918. * Line where the function is invoked
  919. *
  920. * @rdesc Return NULL if failed, else the handle
  921. *************************************************************************/
  922. PUBLIC int EXPORT_API PASCAL FAR _VirtualFree(HANDLE hnd, DWORD size,
  923. DWORD flag, LPSTR lszFilename, UINT line)
  924. {
  925. register UINT i;
  926. int h;
  927. if (hnd == 0)
  928. {
  929. MemErr(E_HANDLE, lszFilename, line);
  930. return 0;
  931. }
  932. /* Check for data integrity */
  933. if ((i = (CheckMemValidity(hnd, lszFilename, line))) >= GlobalPoolSize)
  934. {
  935. MemErr (E_ASSERT, lszFilename, line);
  936. return (VirtualFree(hnd, 0L, (MEM_DECOMMIT | MEM_RELEASE)));
  937. }
  938. ENTER_CRITICAL_SECTION;
  939. h = VirtualFree(hnd, 0L, MEM_DECOMMIT | MEM_RELEASE);
  940. GlobalMemUsed -= GlobalPool[i].size;
  941. GlobalPool[i].size = 0;
  942. GlobalPool[i].lszFileName = NULL;
  943. GlobalPool[i].hnd = 0;
  944. GlobalPool[i].line = 0;
  945. LEAVE_CRITICAL_SECTION ;
  946. return h ;
  947. }
  948. #endif // } _MAC
  949. #else // }{
  950. /****************************************************
  951. *
  952. * STUBS FOR NON-DEBUG VERSION TO SATISFY MVFS.DEF
  953. *
  954. ****************************************************/
  955. PUBLIC HANDLE PASCAL FAR _GlobalAlloc(UINT flag, DWORD size,
  956. LPSTR lszFile, UINT line)
  957. {
  958. return GlobalAlloc(flag, size);
  959. }
  960. PUBLIC HANDLE PASCAL FAR _GlobalReAlloc(HANDLE handle,
  961. DWORD size, UINT flag, LPSTR lszFile, UINT line)
  962. {
  963. return GlobalReAlloc(handle, size, flag);
  964. }
  965. PUBLIC LPVOID PASCAL FAR _GlobalLock(HANDLE hnd, LPSTR lszFile, UINT line)
  966. {
  967. return (LPVOID)GlobalLock(hnd);
  968. }
  969. PUBLIC int PASCAL FAR _GlobalUnlock(HANDLE hnd, LPSTR lszFile, UINT line)
  970. {
  971. return GlobalUnlock(hnd);
  972. }
  973. PUBLIC HANDLE PASCAL FAR _GlobalFree(HANDLE hnd, LPSTR lszFile, UINT line)
  974. {
  975. return GlobalFree(hnd);
  976. }
  977. PUBLIC DWORD PASCAL FAR _GlobalSize(HANDLE hnd, LPSTR lszFile, UINT line)
  978. {
  979. return GlobalSize(hnd);
  980. }
  981. PUBLIC int PASCAL FAR _GlobalAdd (HANDLE hnd, LPSTR lszFilename,
  982. UINT line)
  983. {
  984. return(S_OK);
  985. }
  986. PUBLIC HANDLE PASCAL FAR _GlobalRelease (HANDLE hnd, LPSTR pszFilename,
  987. UINT line)
  988. {
  989. return(hnd);
  990. }
  991. DWORD PASCAL EXPORT_API FAR GetMemUsed()
  992. {
  993. return 0;
  994. }
  995. DWORD PASCAL EXPORT_API FAR CheckMem()
  996. {
  997. return 0;
  998. }
  999. #ifndef _MAC // {_MAC
  1000. PUBLIC HANDLE EXPORT_API PASCAL FAR _VirtualAlloc(LPVOID lpv,
  1001. DWORD size, DWORD flag, DWORD fProtect, LPSTR lszFilename, UINT line)
  1002. {
  1003. return (HANDLE)VirtualAlloc(lpv, size, flag, fProtect);
  1004. }
  1005. PUBLIC LPVOID EXPORT_API PASCAL FAR _VirtualLock(HANDLE hnd, DWORD size,
  1006. LPSTR lszFilename, UINT line)
  1007. {
  1008. return (LPVOID)VirtualLock(hnd, size);
  1009. }
  1010. PUBLIC int EXPORT_API PASCAL FAR _VirtualUnlock(HANDLE hnd,
  1011. DWORD size, LPSTR lszFilename, UINT line)
  1012. {
  1013. return (int)VirtualUnlock(hnd, size);
  1014. }
  1015. PUBLIC int EXPORT_API PASCAL FAR _VirtualFree(HANDLE hnd, DWORD size,
  1016. DWORD flag, LPSTR lszFilename, UINT line)
  1017. {
  1018. return (VirtualFree(hnd, 0L, (MEM_DECOMMIT | MEM_RELEASE)));
  1019. }
  1020. #endif // }_MAC
  1021. #endif // }
  1022. #endif // } _DEBUG