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.

900 lines
21 KiB

  1. /***
  2. *dballoc.cpp
  3. *
  4. * Copyright (C) 1992-93, Microsoft Corporation. All Rights Reserved.
  5. *
  6. *Purpose:
  7. * This file contains a debug implementation of the IMalloc interface.
  8. *
  9. * This implementation is basically a simple wrapping of the C runtime,
  10. * with additional work to detect memory leakage, and memory overwrite.
  11. *
  12. * Leakage is detected by tracking each allocation in an address
  13. * instance table, and then checking to see if the table is empty
  14. * when the last reference to the allocator is released.
  15. *
  16. * Memory overwrite is detected by placing a signature at the end
  17. * of every allocated block, and checking to make sure the signature
  18. * is unchanged when the block is freed.
  19. *
  20. * This implementation also has additional param validation code, as
  21. * well as additional check make sure that instances that are passed
  22. * to Free() were actually allocated by the corresponding instance
  23. * of the allocator.
  24. *
  25. *
  26. * Creating an instance of this debug allocator that uses the default
  27. * output interface would look like the following,
  28. *
  29. *
  30. * BOOL init_application_instance()
  31. * {
  32. * HRESULT hresult;
  33. * IMalloc FAR* pmalloc;
  34. *
  35. * pmalloc = NULL;
  36. *
  37. * if((hresult = OleStdCreateDbAlloc(0,&pmalloc))!=NOERROR)
  38. * goto LReturn;
  39. *
  40. * hresult = OleInitialize(pmalloc);
  41. *
  42. * // release pmalloc to let OLE hold the only ref to the it. later
  43. * // when OleUnitialize is called, memory leaks will be reported.
  44. * if(pmalloc != NULL)
  45. * pmalloc->Release();
  46. *
  47. * LReturn:
  48. *
  49. * return (hresult == NOERROR) ? TRUE : FALSE;
  50. * }
  51. *
  52. *
  53. * CONSIDER: could add an option to force error generation, something
  54. * like DBALLOC_ERRORGEN
  55. *
  56. * CONSIDER: add support for heap-checking. say for example,
  57. * DBALLOC_HEAPCHECK would do a heapcheck every free? every 'n'
  58. * calls to free? ...
  59. *
  60. *
  61. *Implementation Notes:
  62. *
  63. * The method IMalloc::DidAlloc() is allowed to always return
  64. * "Dont Know" (-1). This method is called by Ole, and they take
  65. * some appropriate action when they get this answer.
  66. The debugging allocator has the option to catch bugs where code is writing off
  67. the end of allocated memory. This is implemented by using NT's virtual memory
  68. services. To switch on this option, use
  69. #define DBALLOC_POWERDEBUG
  70. Note it will ONLY WORK ON NT. This option consumes a very large amount of
  71. memory. Basically, for every allocation, it cooks the allocation so that the
  72. end of the allocation will fall on a page boundary. An extra page of memory
  73. is allocated after the requested memory. The protection bits for this page
  74. are altered so that it is an error to read or write to it. Any incident of
  75. writing past the end of allocated memory is trapped at the point of the error.
  76. This consumes a great deal of memory because at least two pages must be
  77. allocated for each allocation.
  78. *
  79. *****************************************************************************/
  80. // Note: this file is designed to be stand-alone; it includes a
  81. // carefully chosen, minimal set of headers.
  82. //
  83. // For conditional compilation we use the ole2 conventions,
  84. // _MAC = mac
  85. // WIN32 = Win32 (NT really)
  86. // <nothing> = defaults to Win16
  87. // REVIEW: the following needs to modified to handle _MAC
  88. #define STRICT
  89. #ifndef INC_OLE2
  90. #define INC_OLE2
  91. #endif
  92. #include <windows.h>
  93. #include "ole2.h"
  94. #if defined( __TURBOC__)
  95. #define __STDC__ (1)
  96. #endif
  97. #define WINDLL 1 // make far pointer version of stdargs.h
  98. #include <stdarg.h>
  99. #if defined( __TURBOC__)
  100. #undef __STDC__
  101. #endif
  102. #include <stdio.h>
  103. #include <stdlib.h>
  104. #include <malloc.h>
  105. #include <string.h>
  106. #include <limits.h>
  107. #include "dballoc.h"
  108. #define DIM(X) (sizeof(X)/sizeof((X)[0]))
  109. #define UNREACHED 0
  110. #if defined(WIN32)
  111. # define MEMCMP(PV1, PV2, CB) memcmp((PV1), (PV2), (CB))
  112. # define MEMCPY(PV1, PV2, CB) memcpy((PV1), (PV2), (CB))
  113. # define MEMSET(PV, VAL, CB) memset((PV), (VAL), (CB))
  114. # define MALLOC(CB) malloc(CB)
  115. # define REALLOC(PV, CB) realloc((PV), (CB))
  116. # define FREE(PV) free(PV)
  117. #ifndef WIN32
  118. # define HEAPMIN() _heapmin()
  119. #else
  120. # define HEAPMIN()
  121. #endif
  122. #elif defined(_MAC)
  123. # define MEMCMP(PV1, PV2) ERROR -- NYI
  124. # define MEMCPY(PV1, PV2, CB) ERROR -- NYI
  125. # define MEMSET(PV, VAL, CB) ERROR -- NYI
  126. # define MALLOC(CB) ERROR -- NYI
  127. # define REALLOC(PV, CB) ERROR -- NYI
  128. # define FREE(PV) ERROR -- NYI
  129. # define HEAPMIN() ERROR -- NYI
  130. #else
  131. # define MEMCMP(PV1, PV2, CB) _fmemcmp((PV1), (PV2), (CB))
  132. # define MEMCPY(PV1, PV2, CB) _fmemcpy((PV1), (PV2), (CB))
  133. # define MEMSET(PV, VAL, CB) _fmemset((PV), (VAL), (CB))
  134. # define MALLOC(CB) _fmalloc(CB)
  135. # define REALLOC(PV, CB) _frealloc(PV, CB)
  136. # define FREE(PV) _ffree(PV)
  137. # define HEAPMIN() _fheapmin()
  138. #endif
  139. #if defined( __TURBOC__ )
  140. #define classmodel _huge
  141. #else
  142. #define classmodel FAR
  143. #endif
  144. class classmodel CStdDbOutput : public IDbOutput {
  145. public:
  146. static IDbOutput FAR* Create();
  147. // IUnknown methods
  148. STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
  149. STDMETHOD_(ULONG, AddRef)(void);
  150. STDMETHOD_(ULONG, Release)(void);
  151. // IDbOutput methods
  152. STDMETHOD_(void, Printf)(TCHAR FAR* szFmt, ...);
  153. STDMETHOD_(void, Assertion)(
  154. BOOL cond,
  155. TCHAR FAR* szExpr,
  156. TCHAR FAR* szFile,
  157. UINT uLine,
  158. TCHAR FAR* szMsg);
  159. void FAR* operator new(size_t cb){
  160. return MALLOC(cb);
  161. }
  162. void operator delete(void FAR* pv){
  163. FREE(pv);
  164. }
  165. CStdDbOutput(){
  166. m_refs = 0;
  167. }
  168. private:
  169. ULONG m_refs;
  170. TCHAR m_rgch[128]; // buffer for output formatting
  171. };
  172. //---------------------------------------------------------------------
  173. // implementation of the debug allocator
  174. //---------------------------------------------------------------------
  175. class FAR CAddrNode
  176. {
  177. public:
  178. void FAR* m_pv; // instance
  179. SIZE_T m_cb; // size of allocation in BYTES
  180. SIZE_T m_nAlloc; // the allocation pass count
  181. CAddrNode FAR* m_next;
  182. void FAR* operator new(size_t cb){
  183. return MALLOC(cb);
  184. }
  185. void operator delete(void FAR* pv){
  186. FREE(pv);
  187. }
  188. };
  189. class classmodel CDbAlloc : public IMalloc
  190. {
  191. public:
  192. static HRESULT Create(
  193. ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc);
  194. // IUnknown methods
  195. STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
  196. STDMETHOD_(ULONG, AddRef)(void);
  197. STDMETHOD_(ULONG, Release)(void);
  198. // IMalloc methods
  199. STDMETHOD_(void FAR*, Alloc)(SIZE_T cb);
  200. STDMETHOD_(void FAR*, Realloc)(void FAR* pv, SIZE_T cb);
  201. STDMETHOD_(void, Free)(void FAR* pv);
  202. STDMETHOD_(SIZE_T, GetSize)(void FAR* pv);
  203. STDMETHOD_(int, DidAlloc)(void FAR* pv);
  204. STDMETHOD_(void, HeapMinimize)(void);
  205. void FAR* operator new(size_t cb){
  206. return MALLOC(cb);
  207. }
  208. void operator delete(void FAR* pv){
  209. FREE(pv);
  210. }
  211. CDbAlloc(){
  212. m_refs = 1;
  213. m_pdbout = NULL;
  214. m_cAllocCalls = 0;
  215. m_nBreakAtNthAlloc = 0;
  216. m_nBreakAtAllocSize = 0;
  217. MEMSET(m_rganode, 0, sizeof(m_rganode));
  218. #ifdef DBALLOC_POWERDEBUG
  219. {
  220. SYSTEM_INFO si;
  221. GetSystemInfo(&si);
  222. m_virtPgSz = si.dwPageSize;
  223. }
  224. #endif // DBALLOC_POWERDEBUG
  225. }
  226. private:
  227. ULONG m_refs;
  228. ULONG m_cAllocCalls; // total count of allocation calls
  229. ULONG m_nBreakAtNthAlloc; // allocation number to break to debugger
  230. // this value should be set typically in the
  231. // debugger.
  232. ULONG m_nBreakAtAllocSize; // allocation size to break to debugger
  233. // this value should be set typically in the
  234. // debugger.
  235. IDbOutput FAR* m_pdbout; // output interface
  236. CAddrNode FAR* m_rganode[64]; // address instance table
  237. // instance table methods
  238. BOOL IsEmpty(void);
  239. void AddInst(void FAR* pv, ULONG nAlloc, SIZE_T cb);
  240. void DelInst(void FAR* pv);
  241. CAddrNode FAR* GetInst(void FAR* pv);
  242. void DumpInst(CAddrNode FAR* pn);
  243. void DumpInstTable(void);
  244. inline UINT HashInst(void FAR* pv) const {
  245. return ((UINT)((ULONG)pv >> 4)) % DIM(m_rganode);
  246. }
  247. // output method(s)
  248. inline void Assertion(
  249. BOOL cond,
  250. TCHAR FAR* szExpr,
  251. TCHAR FAR* szFile,
  252. UINT uLine,
  253. TCHAR FAR* szMsg)
  254. {
  255. m_pdbout->Assertion(cond, szExpr, szFile, uLine, szMsg);
  256. }
  257. #define ASSERT(X) Assertion(X, TEXT(#X), TEXT(__FILE__), __LINE__, NULL)
  258. #define ASSERTSZ(X, SZ) Assertion(X, TEXT(#X), TEXT(__FILE__), __LINE__, SZ)
  259. static const BYTE m_rgchSig[];
  260. #ifdef DBALLOC_POWERDEBUG
  261. size_t m_virtPgSz;
  262. #endif // DBALLOC_POWERDEBUG
  263. };
  264. const BYTE CDbAlloc::m_rgchSig[] = { 0xDE, 0xAD, 0xBE, 0xEF };
  265. /***
  266. *HRESULT OleStdCreateDbAlloc(ULONG reserved, IMalloc** ppmalloc)
  267. * Purpose:
  268. * Create an instance of CDbAlloc -- a debug implementation
  269. * of IMalloc.
  270. *
  271. * Parameters:
  272. * ULONG reserved - reserved for future use. must be 0.
  273. * IMalloc FAR* FAR* ppmalloc - (OUT) pointer to an IMalloc interface
  274. * of new debug allocator object
  275. * Returns:
  276. * HRESULT
  277. * NOERROR - if no error.
  278. * E_OUTOFMEMORY - allocation failed.
  279. *
  280. ***********************************************************************/
  281. STDAPI OleStdCreateDbAlloc(ULONG reserved,IMalloc FAR* FAR* ppmalloc)
  282. {
  283. return CDbAlloc::Create(reserved, NULL, ppmalloc);
  284. }
  285. HRESULT
  286. CDbAlloc::Create(
  287. ULONG options,
  288. IDbOutput FAR* pdbout,
  289. IMalloc FAR* FAR* ppmalloc)
  290. {
  291. HRESULT hresult;
  292. CDbAlloc FAR* pmalloc;
  293. // default the instance of IDbOutput if the user didn't supply one
  294. if(pdbout == NULL && ((pdbout = CStdDbOutput::Create()) == NULL)){
  295. hresult = ResultFromScode(E_OUTOFMEMORY);
  296. goto LError0;
  297. }
  298. pdbout->AddRef();
  299. if((pmalloc = new FAR CDbAlloc()) == NULL){
  300. hresult = ResultFromScode(E_OUTOFMEMORY);
  301. goto LError1;
  302. }
  303. pmalloc->m_pdbout = pdbout;
  304. *ppmalloc = pmalloc;
  305. return NOERROR;
  306. LError1:;
  307. pdbout->Release();
  308. pmalloc->Release();
  309. LError0:;
  310. return hresult;
  311. }
  312. STDMETHODIMP
  313. CDbAlloc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  314. {
  315. if(IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IMalloc)){
  316. *ppv = this;
  317. AddRef();
  318. return NOERROR;
  319. }
  320. return ResultFromScode(E_NOINTERFACE);
  321. }
  322. STDMETHODIMP_(ULONG)
  323. CDbAlloc::AddRef()
  324. {
  325. return ++m_refs;
  326. }
  327. STDMETHODIMP_(ULONG)
  328. CDbAlloc::Release()
  329. {
  330. if(--m_refs == 0){
  331. // check for memory leakage
  332. if(IsEmpty()){
  333. m_pdbout->Printf(TEXT("No Memory Leaks.\n"));
  334. }else{
  335. m_pdbout->Printf(TEXT("Memory Leak Detected,\n"));
  336. DumpInstTable();
  337. }
  338. m_pdbout->Release();
  339. delete this;
  340. return 0;
  341. }
  342. return m_refs;
  343. }
  344. STDMETHODIMP_(void FAR*)
  345. CDbAlloc::Alloc(SIZE_T cb)
  346. {
  347. size_t size;
  348. void FAR* pv;
  349. ++m_cAllocCalls;
  350. if (m_nBreakAtNthAlloc && m_cAllocCalls == m_nBreakAtNthAlloc) {
  351. ASSERTSZ(FALSE, TEXT("DBALLOC: NthAlloc Break target reached\r\n"));
  352. } else if (m_nBreakAtAllocSize && cb == m_nBreakAtAllocSize) {
  353. ASSERTSZ(FALSE, TEXT("DBALLOC: AllocSize Break target reached\r\n"));
  354. }
  355. #ifndef DBALLOC_POWERDEBUG
  356. // REVIEW: need to add support for huge allocations (on win16)
  357. if((cb + sizeof(m_rgchSig)) > UINT_MAX)
  358. return NULL;
  359. size = (size_t)cb;
  360. if((pv = MALLOC(size + sizeof(m_rgchSig))) == NULL)
  361. return NULL;
  362. // set allocated block to some non-zero value
  363. MEMSET(pv, -1, size);
  364. // put signature at end of allocated block
  365. MEMCPY(((char FAR*)pv) + size, m_rgchSig, sizeof(m_rgchSig));
  366. AddInst(pv, m_cAllocCalls, size);
  367. #else
  368. // for each allocate, allocate the amount of memory required, and
  369. // one more page beyond that. We will change the protection bits of
  370. // the trailing page so that we get an access violation if someone
  371. // writes beyond the end of their allocated memory
  372. {
  373. size_t allocpgs; // number of pages to allocate
  374. DWORD dwOldProt; // previous protection of the last page
  375. void *plastpg; // points to the beginning of the last page
  376. // allocate at least one page for the allocation, and
  377. // one to go after it
  378. allocpgs = (cb + 2*m_virtPgSz) / m_virtPgSz;
  379. pv = VirtualAlloc(NULL, allocpgs*m_virtPgSz,
  380. MEM_COMMIT, PAGE_READWRITE);
  381. // change the protection of the last page
  382. plastpg = (void *)(((BYTE *)pv)+m_virtPgSz*(allocpgs-1));
  383. VirtualProtect(plastpg, m_virtPgSz, PAGE_NOACCESS, &dwOldProt);
  384. // figure out what pointer to return to the user
  385. pv = (void *)(((BYTE *)plastpg)-cb);
  386. // record the allocation
  387. AddInst(pv, m_cAllocCalls, cb);
  388. }
  389. #endif // DBALLOC_POWERDEBUG
  390. return pv;
  391. }
  392. STDMETHODIMP_(void FAR*)
  393. CDbAlloc::Realloc(void FAR* pv, SIZE_T cb)
  394. {
  395. size_t size;
  396. CAddrNode *pcan;
  397. #ifndef DBALLOC_POWERDEBUG
  398. // REVIEW: need to add support for huge realloc
  399. if((cb + sizeof(m_rgchSig)) > UINT_MAX)
  400. return NULL;
  401. #endif // DBALLOC_POWERDEBUG
  402. if(pv == NULL){
  403. return Alloc(cb);
  404. }
  405. ++m_cAllocCalls;
  406. ASSERT((pcan = GetInst(pv)) != NULL);
  407. #ifndef DBALLOC_POWERDEBUG
  408. DelInst(pv);
  409. if(cb == 0){
  410. Free(pv);
  411. return NULL;
  412. }
  413. size = (size_t)cb;
  414. if((pv = REALLOC(pv, size + sizeof(m_rgchSig))) == NULL)
  415. return NULL;
  416. // put signature at end of allocated block
  417. MEMCPY(((char FAR*)pv) + size, m_rgchSig, sizeof(m_rgchSig));
  418. AddInst(pv, m_cAllocCalls, size);
  419. #else
  420. {
  421. void *pnew;
  422. DWORD dwOldProt;
  423. // allocate new memory
  424. pnew = Alloc(cb);
  425. // copy in the previous material
  426. memcpy(pnew, pcan->m_pv, pcan->m_cb);
  427. // protect the old memory
  428. VirtualProtect(pcan->m_pv, pcan->m_cb, PAGE_NOACCESS,
  429. &dwOldProt);
  430. DelInst(pv);
  431. AddInst(pv, m_cAllocCalls, cb);
  432. pv = pnew;
  433. }
  434. #endif // DBALLOC_POWERDEBUG
  435. return pv;
  436. }
  437. STDMETHODIMP_(void)
  438. CDbAlloc::Free(void FAR* pv)
  439. {
  440. if (pv == NULL)
  441. {
  442. // Free of NULL is a NO-OP
  443. return;
  444. }
  445. CAddrNode FAR* pn;
  446. static TCHAR szSigMsg[] = TEXT("Signature Check Failed");
  447. pn = GetInst(pv);
  448. // check for attempt to free an instance we didnt allocate
  449. if(pn == NULL){
  450. ASSERTSZ(FALSE, TEXT("pointer freed by wrong allocator"));
  451. return;
  452. }
  453. #ifndef DBALLOC_POWERDEBUG
  454. // verify the signature
  455. if(MEMCMP(((char FAR*)pv) + pn->m_cb, m_rgchSig, sizeof(m_rgchSig)) != 0){
  456. m_pdbout->Printf(szSigMsg); m_pdbout->Printf(TEXT("\n"));
  457. DumpInst(GetInst(pv));
  458. ASSERTSZ(FALSE, szSigMsg);
  459. }
  460. // stomp on the contents of the block
  461. MEMSET(pv, 0xCC, ((size_t)pn->m_cb + sizeof(m_rgchSig)));
  462. DelInst(pv);
  463. FREE(pv);
  464. #else
  465. {
  466. DWORD dwOldProt;
  467. // make the block inaccessible
  468. VirtualProtect(pv, pn->m_cb, PAGE_NOACCESS, &dwOldProt);
  469. DelInst(pv);
  470. }
  471. #endif // DBALLOC_POWERDEBUG
  472. }
  473. STDMETHODIMP_(SIZE_T)
  474. CDbAlloc::GetSize(void FAR* pv)
  475. {
  476. CAddrNode FAR* pn;
  477. if (pv == NULL)
  478. {
  479. // GetSize is supposed to return a -1 when NULL is passed in.
  480. return (SIZE_T) -1;
  481. }
  482. pn = GetInst(pv);
  483. if (pn == NULL) {
  484. ASSERT(pn != NULL);
  485. return 0;
  486. }
  487. return pn->m_cb;
  488. }
  489. /***
  490. *PUBLIC HRESULT CDbAlloc::DidAlloc
  491. *Purpose:
  492. * Answer if the given address belongs to a block allocated by
  493. * this allocator.
  494. *
  495. *Entry:
  496. * pv = the instance to lookup
  497. *
  498. *Exit:
  499. * return value = int
  500. * 1 - did alloc
  501. * 0 - did *not* alloc
  502. * -1 - dont know (according to the ole2 spec it is always legal
  503. * for the allocator to answer "dont know")
  504. *
  505. ***********************************************************************/
  506. STDMETHODIMP_(int)
  507. CDbAlloc::DidAlloc(void FAR* pv)
  508. {
  509. return -1; // answer "I dont know"
  510. }
  511. STDMETHODIMP_(void)
  512. CDbAlloc::HeapMinimize()
  513. {
  514. HEAPMIN();
  515. }
  516. //---------------------------------------------------------------------
  517. // instance table methods
  518. //---------------------------------------------------------------------
  519. /***
  520. *PRIVATE CDbAlloc::AddInst
  521. *Purpose:
  522. * Add the given instance to the address instance table.
  523. *
  524. *Entry:
  525. * pv = the instance to add
  526. * nAlloc = the allocation passcount of this instance
  527. *
  528. *Exit:
  529. * None
  530. *
  531. ***********************************************************************/
  532. void
  533. CDbAlloc::AddInst(void FAR* pv, ULONG nAlloc, SIZE_T cb)
  534. {
  535. UINT hash;
  536. CAddrNode FAR* pn;
  537. ASSERT(pv != NULL);
  538. pn = (CAddrNode FAR*)new FAR CAddrNode();
  539. if (pn == NULL) {
  540. ASSERT(pn != NULL);
  541. return;
  542. }
  543. pn->m_pv = pv;
  544. pn->m_cb = cb;
  545. pn->m_nAlloc = nAlloc;
  546. hash = HashInst(pv);
  547. pn->m_next = m_rganode[hash];
  548. m_rganode[hash] = pn;
  549. }
  550. /***
  551. *UNDONE
  552. *Purpose:
  553. * Remove the given instance from the address instance table.
  554. *
  555. *Entry:
  556. * pv = the instance to remove
  557. *
  558. *Exit:
  559. * None
  560. *
  561. ***********************************************************************/
  562. void
  563. CDbAlloc::DelInst(void FAR* pv)
  564. {
  565. CAddrNode FAR* FAR* ppn, FAR* pnDead;
  566. for(ppn = &m_rganode[HashInst(pv)]; *ppn != NULL; ppn = &(*ppn)->m_next){
  567. if((*ppn)->m_pv == pv){
  568. pnDead = *ppn;
  569. *ppn = (*ppn)->m_next;
  570. delete pnDead;
  571. // make sure it doesnt somehow appear twice
  572. ASSERT(GetInst(pv) == NULL);
  573. return;
  574. }
  575. }
  576. // didnt find the instance
  577. ASSERT(UNREACHED);
  578. }
  579. CAddrNode FAR*
  580. CDbAlloc::GetInst(void FAR* pv)
  581. {
  582. CAddrNode FAR* pn;
  583. for(pn = m_rganode[HashInst(pv)]; pn != NULL; pn = pn->m_next){
  584. if(pn->m_pv == pv)
  585. return pn;
  586. }
  587. return NULL;
  588. }
  589. void
  590. CDbAlloc::DumpInst(CAddrNode FAR* pn)
  591. {
  592. if (pn == NULL)
  593. return;
  594. m_pdbout->Printf(TEXT("[0x%lx] nAlloc=%ld size=%ld\n"),
  595. pn->m_pv, pn->m_nAlloc, GetSize(pn->m_pv));
  596. }
  597. /***
  598. *PRIVATE BOOL IsEmpty
  599. *Purpose:
  600. * Answer if the address instance table is empty.
  601. *
  602. *Entry:
  603. * None
  604. *
  605. *Exit:
  606. * return value = BOOL, TRUE if empty, FALSE otherwise
  607. *
  608. ***********************************************************************/
  609. BOOL
  610. CDbAlloc::IsEmpty()
  611. {
  612. UINT u;
  613. for(u = 0; u < DIM(m_rganode); ++u){
  614. if(m_rganode[u] != NULL)
  615. return FALSE;
  616. }
  617. return TRUE;
  618. }
  619. /***
  620. *PRIVATE CDbAlloc::Dump
  621. *Purpose:
  622. * Print the current contents of the address instance table,
  623. *
  624. *Entry:
  625. * None
  626. *
  627. *Exit:
  628. * None
  629. *
  630. ***********************************************************************/
  631. void
  632. CDbAlloc::DumpInstTable()
  633. {
  634. UINT u;
  635. CAddrNode FAR* pn;
  636. for(u = 0; u < DIM(m_rganode); ++u){
  637. for(pn = m_rganode[u]; pn != NULL; pn = pn->m_next){
  638. DumpInst(pn);
  639. }
  640. }
  641. }
  642. //---------------------------------------------------------------------
  643. // implementation of CStdDbOutput
  644. //---------------------------------------------------------------------
  645. IDbOutput FAR*
  646. CStdDbOutput::Create()
  647. {
  648. return (IDbOutput FAR*)new FAR CStdDbOutput();
  649. }
  650. STDMETHODIMP
  651. CStdDbOutput::QueryInterface(REFIID riid, void FAR* FAR* ppv)
  652. {
  653. if(IsEqualIID(riid, IID_IUnknown))
  654. {
  655. *ppv = this;
  656. AddRef();
  657. return NOERROR;
  658. }
  659. return ResultFromScode(E_NOINTERFACE);
  660. }
  661. STDMETHODIMP_(ULONG)
  662. CStdDbOutput::AddRef()
  663. {
  664. return ++m_refs;
  665. }
  666. STDMETHODIMP_(ULONG)
  667. CStdDbOutput::Release()
  668. {
  669. if(--m_refs == 0){
  670. delete this;
  671. return 0;
  672. }
  673. return m_refs;
  674. }
  675. STDMETHODIMP_(void)
  676. CStdDbOutput::Printf(TCHAR FAR* lpszFmt, ...)
  677. {
  678. va_list args;
  679. TCHAR szBuf[256];
  680. #if defined( OBSOLETE )
  681. TCHAR *pn, FAR* pf;
  682. static TCHAR rgchFmtBuf[128];
  683. static TCHAR rgchOutputBuf[128];
  684. // copy the 'far' format string to a near buffer so we can use
  685. // a medium model vsprintf, which only supports near data pointers.
  686. //
  687. pn = rgchFmtBuf, pf=szFmt;
  688. while(*pf != TEXT('\0'))
  689. *pn++ = *pf++;
  690. *pn = TEXT('\0');
  691. #endif
  692. va_start(args, lpszFmt);
  693. // wvsprintf(rgchOutputBuf, rgchFmtBuf, args);
  694. wvsprintf(szBuf, lpszFmt, args);
  695. OutputDebugString(szBuf);
  696. }
  697. STDMETHODIMP_(void)
  698. CStdDbOutput::Assertion(
  699. BOOL cond,
  700. TCHAR FAR* szExpr,
  701. TCHAR FAR* szFile,
  702. UINT uLine,
  703. TCHAR FAR* szMsg)
  704. {
  705. if(cond)
  706. return;
  707. #ifdef _DEBUG
  708. // following is from compobj.dll (ole2)
  709. #ifdef UNICODE
  710. #ifndef NOASSERT
  711. FnAssert(szExpr, szMsg, szFile, uLine);
  712. #endif
  713. #else
  714. // we need to talk to comobj in UNICODE even though we are not defined
  715. // as UNICODE
  716. {
  717. WCHAR wszExpr[255], wszMsg[255], wszFile[255];
  718. mbstowcs(wszExpr, szExpr, 255);
  719. mbstowcs(wszMsg, szMsg, 255);
  720. mbstowcs(wszFile, szFile, 255);
  721. #ifndef NOASSERT
  722. FnAssert(wszExpr, wszMsg, wszFile, uLine);
  723. #endif
  724. }
  725. #endif
  726. #else
  727. // REVIEW: should be able to do something better that this...
  728. DebugBreak();
  729. #endif
  730. }