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.

657 lines
15 KiB

  1. /*++
  2. Copyright (c) 1988-1999 Microsoft Corporation
  3. Module Name:
  4. cmem.c
  5. Abstract:
  6. Memory allocation support
  7. --*/
  8. #include "cmd.h"
  9. extern DWORD DosErr ;
  10. /* Data Stack - a stack of pointers to memory that has been allocated *M005*/
  11. typedef struct _DSTACK {
  12. ULONG cb ; /* malloc's length value (M011) */
  13. struct _DSTACK *pdstkPrev; /* Pointer to the previous list element */
  14. CHAR data ; /* The data block */
  15. } DSTACK, *PDSTACK;
  16. #define PTRSIZE FIELD_OFFSET(DSTACK, data) /* Size of element header*/
  17. PDSTACK DHead = NULL ; /* Head of the data list */
  18. ULONG DCount = 0 ; /* Number of elements in the list */
  19. #define MAX_NUM_BIG_BUF 2
  20. PVOID BigBufHandle[MAX_NUM_BIG_BUF] = {0, 0}; /* Handle/segment of buffer used by type & copy */
  21. #if DBG
  22. /*** MemChk1 - Sanity check on one element of the data stack
  23. *
  24. * Purpose:
  25. * Verifies the integrity and length of a single data element
  26. *
  27. * int MemChk1(PDSTACK s)
  28. *
  29. * Args:
  30. * s - Pointer to the data stack element to check on
  31. *
  32. * Returns:
  33. * 0 - If element is intact and okay
  34. * 1 - If element size or integrity is off
  35. *
  36. */
  37. MemChk1(
  38. IN PDSTACK pdstk
  39. )
  40. {
  41. return 0;
  42. #if 0
  43. if (pdstk->cb != HeapSize(GetProcessHeap(), 0, pdstk)) {
  44. printf( "My Size is %x, heap says %x\n", pdstk->cb, HeapSize(GetProcessHeap(), 0, pdstk));
  45. cmd_printf (TEXT("len = %d"), pdstk->cb) ;
  46. return(1) ;
  47. } else {
  48. return(0) ;
  49. } ;
  50. #endif
  51. }
  52. /*** MemChkBk - Sanity check on data stack elements from here back
  53. *
  54. * Purpose:
  55. * Verifies the integrity of the CMD data stack from a single
  56. * point back to the beginning.
  57. *
  58. * int MemChkBk(PDSTACK s)
  59. *
  60. * Args:
  61. * s - Pointer to the data stack element to start with
  62. *
  63. * Returns:
  64. * 0 - If elements are intact and okay
  65. * 1 - If elements' size or integrity are off
  66. *
  67. */
  68. MemChkBk(
  69. IN PDSTACK pdstk
  70. )
  71. {
  72. #if 0
  73. ULONG cnt ; // Element counter
  74. PDSTACK pdstkCur; // Element pointer
  75. cnt = DCount ;
  76. for (pdstkCur = DHead, cnt = DCount ; pdstkCur ; pdstkCur = (PDSTACK)pdstkCur->pdstkPrev, cnt--) {
  77. if (pdstkCur == pdstk) {
  78. break ;
  79. } ;
  80. } ;
  81. while (pdstkCur) {
  82. if (MemChk1(pdstkCur)) {
  83. cmd_printf(TEXT("Memory Element %d @ %04x contaminated!"), cnt, pdstkCur) ;
  84. abort() ;
  85. } ;
  86. pdstkCur = (PDSTACK)pdstkCur->pdstkPrev ;
  87. --cnt ;
  88. } ;
  89. #endif
  90. return(0) ;
  91. }
  92. /*** MemChkAll - Sanity check on one element of the data stack
  93. *
  94. * Purpose:
  95. * Checks the entire data stack for integrity.
  96. *
  97. * int MemChkAll()
  98. *
  99. * Args:
  100. *
  101. * Returns:
  102. * 0 - If elements are intact and okay
  103. * 1 - If elements' size or integrity are off
  104. *
  105. */
  106. MemChkAll()
  107. {
  108. return(MemChkBk(DHead)) ;
  109. }
  110. #endif
  111. /*** FreeBigBuf - free the buffer used by the type and copy commands
  112. *
  113. * Purpose:
  114. * If BigBufHandle contains a handle, unlock it and free it.
  115. *
  116. * FreeBigBuf()
  117. *
  118. * *** NOTE: This routine manipulates Command's Buffer handle, and ***
  119. * *** should be called with signal processing postponed. ***
  120. */
  121. void FreeBigBuf(
  122. int BigBufID
  123. )
  124. {
  125. if (BigBufID >= MAX_NUM_BIG_BUF)
  126. return;
  127. if (BigBufHandle[BigBufID]) {
  128. DEBUG((MMGRP, LMLVL, " FREEBIGBUF: Freeing bigbufhandle = 0x%04x", BigBufHandle[BigBufID])) ;
  129. VirtualFree(BigBufHandle[BigBufID],0,MEM_RELEASE) ;
  130. BigBufHandle[BigBufID] = 0 ;
  131. } ;
  132. }
  133. /*** FreeStack - free the memory on the data stack
  134. *
  135. * Purpose:
  136. * Free the memory pointed to by all but the first n elements of the
  137. * data stack and free BigBufHandle if it is nonzero.
  138. *
  139. * FreeStack(int n)
  140. *
  141. * Args:
  142. * n - the number of elements to leave on the stack
  143. *
  144. * W A R N I N G
  145. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  146. */
  147. void FreeStack(
  148. IN ULONG n
  149. )
  150. {
  151. PDSTACK pdstkPtr ;
  152. int i;
  153. DEBUG((MMGRP, LMLVL, " FREESTACK: n = %d DCount = %d", n, DCount)) ;
  154. while (DCount > n && (pdstkPtr = DHead)) {
  155. /* Free the top item in the data stack and pop the stack */
  156. DHead = (PDSTACK)DHead->pdstkPrev ;
  157. -- DCount ;
  158. DEBUG((MMGRP, LMLVL, " FREESTACK: Freeing %x", pdstkPtr)) ;
  159. memset( pdstkPtr, 0, sizeof( *pdstkPtr ));
  160. HeapFree(GetProcessHeap(), 0, pdstkPtr) ;
  161. }
  162. #if DBG
  163. MemChkAll() ; /* CAUSES abort() IF CONTAMINATED */
  164. #endif
  165. for (i=0; i<MAX_NUM_BIG_BUF; i++) {
  166. FreeBigBuf(i) ;
  167. }
  168. DEBUG((MMGRP, LMLVL, " FREESTACK: n = %d, DCount = %d", n, DCount)) ;
  169. }
  170. /*** FreeStr - free a memory block
  171. *
  172. * Purpose:
  173. * Free a single memory block from the stack.
  174. *
  175. * Args:
  176. * pbFree - pointer to block being freed.
  177. *
  178. * W A R N I N G
  179. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  180. */
  181. void
  182. FreeStr(
  183. IN PTCHAR pbFree
  184. )
  185. {
  186. PDSTACK pdstkCur;
  187. PDSTACK pdstkPtr, pdstkLast ;
  188. ULONG cdstk;
  189. DEBUG(( MMGRP, LMLVL, " FreeStr: pbFree = %x DCount = %d", pbFree, DCount )) ;
  190. if ((pbFree == NULL) || (DHead == NULL)) {
  191. return;
  192. }
  193. pdstkPtr = (PDSTACK)((CHAR*)pbFree - PTRSIZE);
  194. //
  195. // Walk through current stack trying to find object
  196. //
  197. for (pdstkCur = DHead, cdstk = DCount; cdstk; cdstk--) {
  198. //
  199. // If we've found the object, remove it from the list
  200. //
  201. if (pdstkCur == pdstkPtr) {
  202. //
  203. // remove from chain
  204. //
  205. DEBUG(( MMGRP, LMLVL, " FreeStr: Prev %x, Cur %x, DCount %d",
  206. pdstkLast, pdstkCur, DCount )) ;
  207. if (pdstkCur == DHead) {
  208. DHead = (PDSTACK)pdstkCur->pdstkPrev;
  209. } else {
  210. pdstkLast->pdstkPrev = pdstkCur->pdstkPrev;
  211. }
  212. HeapFree( GetProcessHeap( ), 0, pdstkCur );
  213. DCount--;
  214. #if DBG
  215. MemChkAll( ) ;
  216. #endif
  217. return;
  218. }
  219. pdstkLast = pdstkCur;
  220. pdstkCur = (PDSTACK)pdstkCur->pdstkPrev;
  221. }
  222. //
  223. // The object wasn't in the stack at all!
  224. //
  225. #if DBG
  226. DEBUG((MMGRP, LMLVL, " FreeStr: object not in stack")) ;
  227. // cmd_printf( TEXT( "Object @ %04x not in memory stack!" ), pbFree ) ;
  228. MemChkAll( ) ;
  229. #endif
  230. }
  231. /*** GetBigBuf - allocate a large buffer
  232. *
  233. * Purpose:
  234. * To allocate a buffer for data transferrals.
  235. * The buffer will be as large as possible, up to MAXBUFSIZE bytes,
  236. * but no smaller than MINBUFSIZE bytes.
  237. *
  238. * TCHAR *GetBigBuf(unsigned *blen)
  239. *
  240. * Args:
  241. * blen = the variable pointed to by blen will be assigned the size of
  242. * the buffer
  243. *
  244. * Returns:
  245. * A TCHAR pointer containing segment:0.
  246. * Returns 0L if unable to allocate a reasonable length buffer
  247. *
  248. */
  249. PVOID
  250. GetBigBuf(
  251. IN ULONG CbMaxToAllocate,
  252. IN ULONG CbMinToAllocate,
  253. OUT unsigned int *CbAllocated,
  254. IN int BigBufID
  255. )
  256. /*++
  257. Routine Description:
  258. To allocate a buffer for data transferrals.
  259. Arguments:
  260. CbMinToAllocate - Fail if can't allocate this number
  261. CbMaxToAllocate - Initial try and allocation will use this number
  262. CbAllocated - Number of bytes allocated
  263. BigBufID - BigBuf index
  264. Return Value:
  265. Return: NULL - if failed to allocate anything
  266. pointer to allocated buffer if success
  267. --*/
  268. {
  269. ULONG cbToDecrease;
  270. PVOID handle ;
  271. DEBUG((MMGRP, MALVL, "GETBIGBUF: MinToAlloc %d, MaxToAlloc %d", CbMinToAllocate, CbMaxToAllocate)) ;
  272. cbToDecrease = CbMaxToAllocate;
  273. //bytesdecrease = CbMaxToAllocate ;
  274. while (!(handle = VirtualAlloc(NULL, CbMaxToAllocate,MEM_COMMIT,PAGE_READWRITE))) {
  275. //
  276. // Decrease the desired buffer size by CbToDecrease
  277. // If the decrease is too large, make it smaller
  278. //
  279. if ( cbToDecrease >= CbMaxToAllocate ) {
  280. cbToDecrease = ((CbMaxToAllocate >> 2) & 0xFE00) + 0x200;
  281. }
  282. if ( cbToDecrease < CbMinToAllocate ) {
  283. cbToDecrease = CbMinToAllocate ;
  284. }
  285. CbMaxToAllocate -= cbToDecrease ;
  286. if ( CbMaxToAllocate < CbMinToAllocate ) {
  287. //
  288. // Unable to allocate a reasonable buffer
  289. //
  290. *CbAllocated = 0 ;
  291. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  292. return ( NULL ) ;
  293. }
  294. }
  295. *CbAllocated = CbMaxToAllocate ;
  296. FreeBigBuf(BigBufID) ;
  297. BigBufHandle[BigBufID] = handle ;
  298. DEBUG((MMGRP, MALVL, " GETBIGBUF: Bytes Allocated = %d Handle = 0x%04x", *CbAllocated, BigBufHandle[BigBufID])) ;
  299. return(handle) ;
  300. }
  301. /*** mknode - allocata a parse tree node
  302. *
  303. * Purpose:
  304. * To allocate space for a new parse tree node. Grow the data segment
  305. * if necessary.
  306. *
  307. * struct node *mknode()
  308. *
  309. * Returns:
  310. * A pointer to the node that was just allocated.
  311. *
  312. * Notes:
  313. * This routine must always use calloc(). Many other parts of Command
  314. * depend on the fact that the fields in these nodes are initialized to 0.
  315. *
  316. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  317. */
  318. struct node *mknode()
  319. {
  320. struct node *Node = (struct node *) mkstr( sizeof( struct node ));
  321. DEBUG((MMGRP, MALVL, " MKNODE: Entered")) ;
  322. return Node;
  323. }
  324. /*** mkstr - allocate space for a string
  325. *
  326. * Purpose:
  327. * To allocate space for a new string. Grow the data segment if necessary.
  328. *
  329. * TCHAR *mkstr(size)
  330. *
  331. * Args:
  332. * size - size of the string to be allocated
  333. *
  334. * Returns:
  335. * A pointer to the string that was just allocated.
  336. *
  337. * Notes:
  338. * This routine must always use calloc(). Many other parts of Command
  339. * depend on the fact that memory that is allocated is initialized to 0.
  340. *
  341. * - M005 * The piece of memory allocated is large enough to include
  342. * a pointer at the beginning. This pointer is part of the list of
  343. * allocated memory. The routine calling mkstr() receives the address
  344. * of the first byte after that pointer. resize() knows about this,
  345. * and so must any other routines which directly modify memory
  346. * allocation.
  347. * - M011 * This function is the same as mentioned above except that the
  348. * pointer is now preceeded by a header consisting of two signature
  349. * bytes and the length of the memory allocated. This was added for
  350. * sanity checks.
  351. *
  352. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  353. *
  354. * W A R N I N G
  355. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  356. */
  357. void*
  358. mkstr(
  359. IN int cbNew
  360. )
  361. {
  362. PDSTACK pdstkCur ; // Ptr to the memory being allocated
  363. DEBUG((MMGRP, MALVL, " MKSTR: Entered.")) ;
  364. #if DBG
  365. MemChkAll() ; /* CAUSES abort() IF CONTAMINATED */
  366. #endif
  367. if ((pdstkCur = (PDSTACK)(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNew + PTRSIZE + 4))) == NULL) {
  368. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  369. return(0) ;
  370. } ;
  371. DEBUG((MMGRP, MALVL, " MKSTR: Adding to stack")) ;
  372. pdstkCur->cb = cbNew + PTRSIZE + 4 ;
  373. pdstkCur->pdstkPrev = (PDSTACK)DHead ;
  374. DHead = pdstkCur ;
  375. DCount++ ;
  376. DEBUG((MMGRP, MALVL, " MKSTR: ptr = %04x cbNew = %04x DCount = %d",
  377. pdstkCur, cbNew, DCount)) ;
  378. #if DBG
  379. MemChkBk(pdstkCur) ; /* CAUSES abort() IF CONTAMINATED */
  380. #endif
  381. return(&(pdstkCur->data)) ; /*M005*/
  382. }
  383. /*** dupstr - Duplicate a string
  384. *
  385. * Purpose:
  386. * Create a copy of a string in a new heap block
  387. *
  388. * TCHAR *dupstr( TCHAR *String )
  389. *
  390. * Args:
  391. * String to be duplicated
  392. *
  393. * Returns:
  394. * A pointer to the string that was just allocated and copied. The caller retains
  395. * ownership of the input string and the returned string.
  396. *
  397. * Notes:
  398. *
  399. * W A R N I N G
  400. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  401. */
  402. TCHAR *
  403. dupstr( TCHAR *String )
  404. {
  405. TCHAR *New = mkstr( (mystrlen( String ) + 1) * sizeof( TCHAR ));
  406. mystrcpy( New, String );
  407. return New;
  408. }
  409. /*** gmkstr - allocate a piece of memory, with no return on failure
  410. *
  411. * Purpose:
  412. * Same as "mkstr" except that if memory cannot be allocated, this
  413. * routine will jump out to code which will clean things up and
  414. * return to the top level of command.
  415. *
  416. */
  417. void*
  418. gmkstr(
  419. IN int cbNew
  420. )
  421. {
  422. PTCHAR pbNew ;
  423. if (!(pbNew = (PTCHAR)mkstr(cbNew)))
  424. Abort() ;
  425. return(pbNew) ;
  426. }
  427. /*** resize - resize a piece of memory
  428. *
  429. * Purpose:
  430. * Change the size of a previously allocated piece of memory. Grow the
  431. * data segment if necessary. If a new different pointer is returned by
  432. * realloc(0), search the dstk for the pointer to the old piece and
  433. * update that pointer to point to the new piece.
  434. *
  435. * TCHAR *resize(TCHAR *ptr, unsigned size)
  436. *
  437. * Args:
  438. * ptr - pointer to the memory to be resized
  439. * size - the new size for the block of memory
  440. *
  441. * Returns:
  442. * A pointer to the new piece of memory.
  443. *
  444. * - M005 * Modified for the new scheme for keeping a list of allocated
  445. * blocks
  446. * - M011 * Modified to use and check new header.
  447. *
  448. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  449. *
  450. * W A R N I N G
  451. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  452. */
  453. void*
  454. resize (
  455. IN void* pv,
  456. IN unsigned int cbNew
  457. )
  458. {
  459. PDSTACK pdstkCur ;
  460. PDSTACK pdstkNew, pdstkOld;
  461. CHAR* pbOld = pv;
  462. DEBUG((MMGRP, MALVL, " RESIZE: Entered %x.", pv)) ;
  463. pbOld -= PTRSIZE ;
  464. pdstkOld = (PDSTACK)pbOld ;
  465. #if DBG
  466. if (MemChk1(pdstkOld)) {
  467. cmd_printf(TEXT("Memory Element @ %04x contaminated!"), pdstkOld) ;
  468. abort() ;
  469. } ;
  470. #endif
  471. if (!(pdstkNew = (PDSTACK)HeapReAlloc(GetProcessHeap(), 0, pbOld, cbNew + PTRSIZE + 4))) {
  472. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  473. return(0) ;
  474. } ;
  475. pdstkNew->cb = cbNew + PTRSIZE + 4 ; // Update to new length
  476. if (HeapSize(GetProcessHeap(), 0, pdstkNew) != pdstkNew->cb) {
  477. DEBUG((MMGRP, LMLVL, " resize: My Size is %x, heap says %x", pdstkNew->cb, HeapSize(GetProcessHeap(), 0, pdstkNew)));
  478. }
  479. //
  480. // revise Data Stack information, updating chain of pdstk's with
  481. // new pointer
  482. //
  483. if (pdstkNew != pdstkOld) {
  484. if (DHead == pdstkOld) { // Is head of List
  485. DHead = pdstkNew ;
  486. } else { // Is in middle of list
  487. for (pdstkCur = DHead ; pdstkCur ; pdstkCur = (PDSTACK)(pdstkCur->pdstkPrev)) {
  488. if ((PDSTACK)(pdstkCur->pdstkPrev) == pdstkOld) {
  489. pdstkCur->pdstkPrev = (PDSTACK)pdstkNew ;
  490. break ;
  491. }
  492. }
  493. }
  494. }
  495. #if DBG
  496. MemChkBk(pdstkOld) ; // CAUSES abort() IF CONTAMINATED
  497. #endif
  498. DEBUG((MMGRP, MALVL, " RESIZE: pbOld = %04x cbNew = %04x",&(pdstkNew->data),cbNew)) ;
  499. return(&(pdstkNew->data)) ;
  500. }