Leaked source code of windows server 2003
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.

658 lines
16 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. pdstkPtr->cb = 0;
  160. pdstkPtr->pdstkPrev = NULL;
  161. HeapFree(GetProcessHeap(), 0, pdstkPtr) ;
  162. }
  163. #if DBG
  164. MemChkAll() ; /* CAUSES abort() IF CONTAMINATED */
  165. #endif
  166. for (i=0; i<MAX_NUM_BIG_BUF; i++) {
  167. FreeBigBuf(i) ;
  168. }
  169. DEBUG((MMGRP, LMLVL, " FREESTACK: n = %d, DCount = %d", n, DCount)) ;
  170. }
  171. /*** FreeStr - free a memory block
  172. *
  173. * Purpose:
  174. * Free a single memory block from the stack.
  175. *
  176. * Args:
  177. * pbFree - pointer to block being freed.
  178. *
  179. * W A R N I N G
  180. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  181. */
  182. void
  183. FreeStr(
  184. IN PVOID pbFree
  185. )
  186. {
  187. PDSTACK pdstkCur;
  188. PDSTACK pdstkPtr, pdstkLast ;
  189. ULONG cdstk;
  190. DEBUG(( MMGRP, LMLVL, " FreeStr: pbFree = %x DCount = %d", pbFree, DCount )) ;
  191. if ((pbFree == NULL) || (DHead == NULL)) {
  192. return;
  193. }
  194. pdstkPtr = (PDSTACK)((CHAR*)pbFree - PTRSIZE);
  195. //
  196. // Walk through current stack trying to find object
  197. //
  198. for (pdstkCur = DHead, cdstk = DCount; cdstk; cdstk--) {
  199. //
  200. // If we've found the object, remove it from the list
  201. //
  202. if (pdstkCur == pdstkPtr) {
  203. //
  204. // remove from chain
  205. //
  206. DEBUG(( MMGRP, LMLVL, " FreeStr: Prev %x, Cur %x, DCount %d",
  207. pdstkLast, pdstkCur, DCount )) ;
  208. if (pdstkCur == DHead) {
  209. DHead = (PDSTACK)pdstkCur->pdstkPrev;
  210. } else {
  211. pdstkLast->pdstkPrev = pdstkCur->pdstkPrev;
  212. }
  213. HeapFree( GetProcessHeap( ), 0, pdstkCur );
  214. DCount--;
  215. #if DBG
  216. MemChkAll( ) ;
  217. #endif
  218. return;
  219. }
  220. pdstkLast = pdstkCur;
  221. pdstkCur = (PDSTACK)pdstkCur->pdstkPrev;
  222. }
  223. //
  224. // The object wasn't in the stack at all!
  225. //
  226. #if DBG
  227. DEBUG((MMGRP, LMLVL, " FreeStr: object not in stack")) ;
  228. // cmd_printf( TEXT( "Object @ %04x not in memory stack!" ), pbFree ) ;
  229. MemChkAll( ) ;
  230. #endif
  231. }
  232. /*** GetBigBuf - allocate a large buffer
  233. *
  234. * Purpose:
  235. * To allocate a buffer for data transferrals.
  236. * The buffer will be as large as possible, up to MAXBUFSIZE bytes,
  237. * but no smaller than MINBUFSIZE bytes.
  238. *
  239. * TCHAR *GetBigBuf(unsigned *blen)
  240. *
  241. * Args:
  242. * blen = the variable pointed to by blen will be assigned the size of
  243. * the buffer
  244. *
  245. * Returns:
  246. * A TCHAR pointer containing segment:0.
  247. * Returns 0L if unable to allocate a reasonable length buffer
  248. *
  249. */
  250. PVOID
  251. GetBigBuf(
  252. IN ULONG CbMaxToAllocate,
  253. IN ULONG CbMinToAllocate,
  254. OUT unsigned int *CbAllocated,
  255. IN int BigBufID
  256. )
  257. /*++
  258. Routine Description:
  259. To allocate a buffer for data transferrals.
  260. Arguments:
  261. CbMinToAllocate - Fail if can't allocate this number
  262. CbMaxToAllocate - Initial try and allocation will use this number
  263. CbAllocated - Number of bytes allocated
  264. BigBufID - BigBuf index
  265. Return Value:
  266. Return: NULL - if failed to allocate anything
  267. pointer to allocated buffer if success
  268. --*/
  269. {
  270. ULONG cbToDecrease;
  271. PVOID handle ;
  272. DEBUG((MMGRP, MALVL, "GETBIGBUF: MinToAlloc %d, MaxToAlloc %d", CbMinToAllocate, CbMaxToAllocate)) ;
  273. cbToDecrease = CbMaxToAllocate;
  274. //bytesdecrease = CbMaxToAllocate ;
  275. while (!(handle = VirtualAlloc(NULL, CbMaxToAllocate,MEM_COMMIT,PAGE_READWRITE))) {
  276. //
  277. // Decrease the desired buffer size by CbToDecrease
  278. // If the decrease is too large, make it smaller
  279. //
  280. if ( cbToDecrease >= CbMaxToAllocate ) {
  281. cbToDecrease = ((CbMaxToAllocate >> 2) & 0xFE00) + 0x200;
  282. }
  283. if ( cbToDecrease < CbMinToAllocate ) {
  284. cbToDecrease = CbMinToAllocate ;
  285. }
  286. CbMaxToAllocate -= cbToDecrease ;
  287. if ( CbMaxToAllocate < CbMinToAllocate ) {
  288. //
  289. // Unable to allocate a reasonable buffer
  290. //
  291. *CbAllocated = 0 ;
  292. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  293. return ( NULL ) ;
  294. }
  295. }
  296. *CbAllocated = CbMaxToAllocate ;
  297. FreeBigBuf(BigBufID) ;
  298. BigBufHandle[BigBufID] = handle ;
  299. DEBUG((MMGRP, MALVL, " GETBIGBUF: Bytes Allocated = %d Handle = 0x%04x", *CbAllocated, BigBufHandle[BigBufID])) ;
  300. return(handle) ;
  301. }
  302. /*** mknode - allocata a parse tree node
  303. *
  304. * Purpose:
  305. * To allocate space for a new parse tree node. Grow the data segment
  306. * if necessary.
  307. *
  308. * struct node *mknode()
  309. *
  310. * Returns:
  311. * A pointer to the node that was just allocated.
  312. *
  313. * Notes:
  314. * This routine must always use calloc(). Many other parts of Command
  315. * depend on the fact that the fields in these nodes are initialized to 0.
  316. *
  317. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  318. */
  319. struct node *mknode()
  320. {
  321. struct node *Node = (struct node *) mkstr( sizeof( struct node ));
  322. DEBUG((MMGRP, MALVL, " MKNODE: Entered")) ;
  323. return Node;
  324. }
  325. /*** mkstr - allocate space for a string
  326. *
  327. * Purpose:
  328. * To allocate space for a new string. Grow the data segment if necessary.
  329. *
  330. * TCHAR *mkstr(size)
  331. *
  332. * Args:
  333. * size - size of the string to be allocated
  334. *
  335. * Returns:
  336. * A pointer to the string that was just allocated.
  337. *
  338. * Notes:
  339. * This routine must always use calloc(). Many other parts of Command
  340. * depend on the fact that memory that is allocated is initialized to 0.
  341. *
  342. * - M005 * The piece of memory allocated is large enough to include
  343. * a pointer at the beginning. This pointer is part of the list of
  344. * allocated memory. The routine calling mkstr() receives the address
  345. * of the first byte after that pointer. resize() knows about this,
  346. * and so must any other routines which directly modify memory
  347. * allocation.
  348. * - M011 * This function is the same as mentioned above except that the
  349. * pointer is now preceeded by a header consisting of two signature
  350. * bytes and the length of the memory allocated. This was added for
  351. * sanity checks.
  352. *
  353. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  354. *
  355. * W A R N I N G
  356. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  357. */
  358. void*
  359. mkstr(
  360. IN int cbNew
  361. )
  362. {
  363. PDSTACK pdstkCur ; // Ptr to the memory being allocated
  364. DEBUG((MMGRP, MALVL, " MKSTR: Entered.")) ;
  365. #if DBG
  366. MemChkAll() ; /* CAUSES abort() IF CONTAMINATED */
  367. #endif
  368. if ((pdstkCur = (PDSTACK)(HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbNew + PTRSIZE + 4))) == NULL) {
  369. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  370. return(0) ;
  371. } ;
  372. DEBUG((MMGRP, MALVL, " MKSTR: Adding to stack")) ;
  373. pdstkCur->cb = cbNew + PTRSIZE + 4;
  374. pdstkCur->pdstkPrev = (PDSTACK)DHead ;
  375. DHead = pdstkCur ;
  376. DCount++ ;
  377. DEBUG((MMGRP, MALVL, " MKSTR: ptr = %04x cbNew = %04x DCount = %d",
  378. pdstkCur, cbNew, DCount)) ;
  379. #if DBG
  380. MemChkBk(pdstkCur) ; /* CAUSES abort() IF CONTAMINATED */
  381. #endif
  382. return(&(pdstkCur->data)) ; /*M005*/
  383. }
  384. /*** dupstr - Duplicate a string
  385. *
  386. * Purpose:
  387. * Create a copy of a string in a new heap block
  388. *
  389. * TCHAR *dupstr( TCHAR *String )
  390. *
  391. * Args:
  392. * String to be duplicated
  393. *
  394. * Returns:
  395. * A pointer to the string that was just allocated and copied. The caller retains
  396. * ownership of the input string and the returned string.
  397. *
  398. * Notes:
  399. *
  400. * W A R N I N G
  401. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  402. */
  403. TCHAR *
  404. dupstr( TCHAR *String )
  405. {
  406. TCHAR *New = mkstr( (mystrlen( String ) + 1) * sizeof( TCHAR ));
  407. mystrcpy( New, String );
  408. return New;
  409. }
  410. /*** gmkstr - allocate a piece of memory, with no return on failure
  411. *
  412. * Purpose:
  413. * Same as "mkstr" except that if memory cannot be allocated, this
  414. * routine will jump out to code which will clean things up and
  415. * return to the top level of command.
  416. *
  417. */
  418. void*
  419. gmkstr(
  420. IN int cbNew
  421. )
  422. {
  423. PTCHAR pbNew ;
  424. if (!(pbNew = (PTCHAR)mkstr(cbNew)))
  425. Abort() ;
  426. return(pbNew) ;
  427. }
  428. /*** resize - resize a piece of memory
  429. *
  430. * Purpose:
  431. * Change the size of a previously allocated piece of memory. Grow the
  432. * data segment if necessary. If a new different pointer is returned by
  433. * realloc(0), search the dstk for the pointer to the old piece and
  434. * update that pointer to point to the new piece.
  435. *
  436. * TCHAR *resize(TCHAR *ptr, unsigned size)
  437. *
  438. * Args:
  439. * ptr - pointer to the memory to be resized
  440. * size - the new size for the block of memory
  441. *
  442. * Returns:
  443. * A pointer to the new piece of memory.
  444. *
  445. * - M005 * Modified for the new scheme for keeping a list of allocated
  446. * blocks
  447. * - M011 * Modified to use and check new header.
  448. *
  449. * THIS ROUTINE RETURNS `NULL' IF THE C RUN-TIME CANNOT ALLOCATE MEMORY
  450. *
  451. * W A R N I N G
  452. * !!! THIS ROUTINE CAUSES AN ABORT IF DATA STACK CONTAMINATED !!!
  453. */
  454. void*
  455. resize (
  456. IN void* pv,
  457. IN unsigned int cbNew
  458. )
  459. {
  460. PDSTACK pdstkCur ;
  461. PDSTACK pdstkNew, pdstkOld;
  462. CHAR* pbOld = pv;
  463. DEBUG((MMGRP, MALVL, " RESIZE: Entered %x.", pv)) ;
  464. pbOld -= PTRSIZE ;
  465. pdstkOld = (PDSTACK)pbOld ;
  466. #if DBG
  467. if (MemChk1(pdstkOld)) {
  468. cmd_printf(TEXT("Memory Element @ %04x contaminated!"), pdstkOld) ;
  469. abort() ;
  470. } ;
  471. #endif
  472. if (!(pdstkNew = (PDSTACK)HeapReAlloc(GetProcessHeap(), 0, pbOld, cbNew + PTRSIZE + 4))) {
  473. PutStdErr(ERROR_NOT_ENOUGH_MEMORY, NOARGS);
  474. return(0) ;
  475. } ;
  476. pdstkNew->cb = cbNew + PTRSIZE + 4 ; // Update to new length
  477. if (HeapSize(GetProcessHeap(), 0, pdstkNew) != pdstkNew->cb) {
  478. DEBUG((MMGRP, LMLVL, " resize: My Size is %x, heap says %x", pdstkNew->cb, HeapSize(GetProcessHeap(), 0, pdstkNew)));
  479. }
  480. //
  481. // revise Data Stack information, updating chain of pdstk's with
  482. // new pointer
  483. //
  484. if (pdstkNew != pdstkOld) {
  485. if (DHead == pdstkOld) { // Is head of List
  486. DHead = pdstkNew ;
  487. } else { // Is in middle of list
  488. for (pdstkCur = DHead ; pdstkCur ; pdstkCur = (PDSTACK)(pdstkCur->pdstkPrev)) {
  489. if ((PDSTACK)(pdstkCur->pdstkPrev) == pdstkOld) {
  490. pdstkCur->pdstkPrev = (PDSTACK)pdstkNew ;
  491. break ;
  492. }
  493. }
  494. }
  495. }
  496. #if DBG
  497. MemChkBk(pdstkOld) ; // CAUSES abort() IF CONTAMINATED
  498. #endif
  499. DEBUG((MMGRP, MALVL, " RESIZE: pbOld = %04x cbNew = %04x",&(pdstkNew->data),cbNew)) ;
  500. return(&(pdstkNew->data)) ;
  501. }