1611 lines
41 KiB
C++
1611 lines
41 KiB
C++
/*
|
|
*dimalloc.cxx
|
|
|
|
* Copyright (C) 1992-93, Microsoft Corporation. All Rights Reserved.
|
|
* Information Contained Herein Is Proprietary and Confidential.
|
|
|
|
*Purpose:
|
|
* This file contains a debug implementation of the IMalloc interface.
|
|
|
|
* This implementation is basically a simple wrapping of the C runtime,
|
|
* with additional work to detect memory leakage, and memory overwrite.
|
|
|
|
* Leakage is detected by tracking each allocation in an address
|
|
* instance table, and then checking to see if the table is empty
|
|
* when the last reference to the allocator is released.
|
|
|
|
* Memory overwrite is detected by placing a signature at the end
|
|
* of every allocated block, and checking to make sure the signature
|
|
* is unchanged when the block is freed.
|
|
|
|
* This implementation also has additional param validation code, as
|
|
* well as additional check make sure that instances that are passed
|
|
* to Free() were actually allocated by the corresponding instance of the allocator.
|
|
|
|
* Creating an instance of this debug allocator that uses the default
|
|
* output interface would look like the following,
|
|
|
|
|
|
* BOOL init_application_instance()
|
|
* {
|
|
* HRESULT hresult;
|
|
* IMalloc FAR* pmalloc;
|
|
|
|
* pmalloc = NULL;
|
|
|
|
* if((hresult = CreateDbAlloc(DBALLOC_NONE, NULL, &pmalloc)) != NOERROR)
|
|
* goto LReturn;
|
|
|
|
* hresult = OleInitialize(pmalloc);
|
|
|
|
* LReturn:;
|
|
* if(pmalloc != NULL)
|
|
* pmalloc->Release();
|
|
|
|
* return (hresult == NOERROR) ? TRUE : FALSE;
|
|
* }
|
|
|
|
|
|
* CONSIDER: could add an option to force error generation, something
|
|
* like DBALLOC_ERRORGEN, that works along the lines of OB's
|
|
* DebErrorNow.
|
|
|
|
* CONSIDER: add support for heap-checking. say for example,
|
|
* DBALLOC_HEAPCHECK would do a heapcheck every free? every 'n'
|
|
* calls to free? ...
|
|
|
|
|
|
*Revision History:
|
|
|
|
* [00] 25-Feb-92 bradlo: Created.
|
|
* [01] 03-Mar-93 rajivk: Added to ebapp.
|
|
|
|
*Implementation Notes:
|
|
|
|
* The method IMalloc::DidAlloc() is allowed to always return
|
|
* "Dont Know" (-1). This method is called by Ole, and they take
|
|
* some appropriate action when they get this answer. UNDONE -- elaborate.
|
|
|
|
*/
|
|
|
|
#ifdef DEBUG // entire file
|
|
#if 0
|
|
#include "pch.c"
|
|
#pragma hdrstop(PCHNAME)
|
|
#else //0
|
|
#include "mktyplib.h"
|
|
#ifdef MAC
|
|
#define OE_MAC TRUE
|
|
#endif
|
|
#ifdef WIN32
|
|
#define OE_WIN32 TRUE
|
|
#if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
|
|
#define OE_RISC TRUE
|
|
#endif
|
|
#endif
|
|
#ifdef WIN16
|
|
#define OE_WIN16 TRUE
|
|
#endif
|
|
#endif //0
|
|
|
|
#if OE_MAC
|
|
#include <macos\osutils.h>
|
|
#include <macos\sysequ.h>
|
|
#endif // OE_MAC
|
|
|
|
// Note: this file is designed to be stand-alone; it includes a
|
|
// carefully chosen, minimal set of headers.
|
|
|
|
// For conditional compilation we use the ole2 conventions,
|
|
// _MAC = mac
|
|
// WIN32 = Win32 (NT really)
|
|
// <nothing> = defaults to Win16
|
|
#ifdef _DEBUG
|
|
#undef _DEBUG
|
|
#endif
|
|
#define _DEBUG 1
|
|
|
|
#if !OE_WIN32
|
|
#include "ole2.h"
|
|
#if !OE_MAC
|
|
#include "compobj.h"
|
|
#endif
|
|
#endif //!OE_WIN32
|
|
|
|
#if OE_MAC
|
|
// include Mac stuff
|
|
#include "macos\memory.h"
|
|
#include "macos\errors.h"
|
|
|
|
typedef VOID* HSYS;
|
|
#define HSYS_Nil ((HSYS)NULL)
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <limits.h>
|
|
|
|
#if 0
|
|
#include "ebapp.h"
|
|
#include "dimalloc.hxx"
|
|
|
|
// This global is defined in bind.c and contains the name of the
|
|
// log file specified by -o, if there is one.
|
|
|
|
extern "C" {
|
|
CHAR g_szLogFile[];
|
|
}
|
|
#else //0
|
|
|
|
#if OE_RISC
|
|
// UNDONE: RISC [jeffrob] Currently use same alignment for ALL risc
|
|
// UNDONE: platforms.
|
|
#define cbAlign 8
|
|
#endif // OE_RISC
|
|
|
|
#if OE_MAC
|
|
#include "macos\menus.h"
|
|
#include "macos\dialogs.h"
|
|
#include "stdio.h"
|
|
#include "macos\files.h"
|
|
#include "macos\lists.h"
|
|
#endif // OE_MAC
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
// Assertion macro.
|
|
#define DebAssert(fExpr, szComment) \
|
|
if (!(fExpr)) \
|
|
DebAssertShow(__FILE__, __LINE__, szComment); \
|
|
else 0 /* useless statement */
|
|
|
|
void DebAssertShow(LPSTR szFileName, UINT uLine, LPSTR szComment);
|
|
|
|
#define DebAssertNum(fExpr, szComment, nErr) \
|
|
if (!(fExpr)) \
|
|
DebAssertShow(__FILE__, __LINE__, szComment); \
|
|
else 0 /* useless statement */
|
|
|
|
#if 0
|
|
// Macros for error checking:
|
|
#define IfErrExit(s) { if (eberr = (s)) goto Exit; }
|
|
#define IfNullExit(s) { if ( !(s) ) { eberr = EBERR_OutOfMemory; goto Exit;} }
|
|
#define IfErrGo(s) { if (eberr = (s)) goto Error; }
|
|
#define IfErrGoTo(s, label) { if (eberr = (s)) goto label; }
|
|
#endif //0
|
|
|
|
#ifndef WIN32
|
|
#ifndef _INC_WINDOWS
|
|
#define LOWORD(l) ((WORD)(DWORD)(l))
|
|
#define HIWORD(l) ((WORD)((((DWORD)(l)) >> 16) & 0xFFFF))
|
|
#endif //_INC_WINDOWS
|
|
#endif //!WIN32
|
|
|
|
#if 0
|
|
// Maintains the hproj/docfile/project substorage relationship.
|
|
typedef struct STGREC {
|
|
IStorage FAR* pstgFile;
|
|
IStorage FAR* pstgProj;
|
|
HPROJECT hproj; // The hproject associated with this storage if known.
|
|
LPSTR bstrName; // The name of the file.
|
|
BOOL isTemp; // TRUE if this is a temp file that should be deleted
|
|
// when closed.
|
|
} STGREC;
|
|
|
|
STGREC FAR* CreateTmpStorage(void);
|
|
EBERR CopyTmpFileToDest(HPROJECT hproj, LPSTR lpstrFileName);
|
|
void PASCAL FreeStorage(void);
|
|
STGREC FAR* FindStgRecByName(LPSTR szName);
|
|
void CloseProjectStorage(HPROJECT hproj);
|
|
|
|
#if OE_WIN
|
|
extern HINSTANCE g_hInst; // host-app instance handle
|
|
extern HWND g_hwndSrchDlg; // modeless search dialog
|
|
extern HWND g_hwndMDISpace; // window handle of host app's MDI space
|
|
extern HWND g_hwndParent; // this instance's top-level window.
|
|
extern char g_szProject[]; // project window class name
|
|
extern char g_szDebugWnd[]; // debug window class name
|
|
extern char g_szPolyWnd[]; // polygon window class name
|
|
#endif //OE_WIN
|
|
|
|
#if OE_MAC
|
|
extern BOOL fMacHelpLoaded; //TRUE if the mac help file is laoded
|
|
extern FSSpec fsHelpFile; //FSSpec for the help file
|
|
#endif
|
|
|
|
extern char* g_szTitleText; // default title bar text
|
|
extern HWND g_hwndEbActive; // Active O.B. window.
|
|
extern BOOL g_fAppActive; // is this application active?
|
|
extern BOOL g_fParentActive; // is the parent (frame) window active?
|
|
extern LPSTR g_lpszHelpFile; // help file if F1 pressed
|
|
extern DWORD g_dwHelpContext; // help context if F1 pressed
|
|
extern UINT g_cMsgLoop; // How many nested message loops?
|
|
extern INT g_fNoAllocs; // Are allocations allowed?
|
|
|
|
extern int g_cxScroll; // width of scrollbar
|
|
extern int g_cyScroll; // heigth of scrollbar
|
|
// Errros Used by Ebapp only.
|
|
#define EBERR_IdNotFound 0xffff
|
|
extern int g_fDbcs; // is DBCS support enabled?
|
|
|
|
LPDISPATCH EBCALL Bind(LPVARIANT lpvarRngName);
|
|
LPDISPATCH EBCALL NewPoint(void);
|
|
LPDISPATCH EBCALL NewPoly(void);
|
|
LPDISPATCH EBCALL GetProjCollection(void);
|
|
LPDISPATCH EBCALL NewList(void);
|
|
LPDISPATCH EBCALL GetAppObj(void);
|
|
void AppObjTerm();
|
|
|
|
void CallEbNotifyWindow(HWND hwnd, EBMSG ebmsg, LONG lparam);
|
|
void QuitEbApp();
|
|
void DebAssertWrite(char* szFileName, char* szMsg);
|
|
|
|
LPVOID EBCALL CreateNewObject(LPSTR szProjName, LPSTR szClassName);
|
|
BOOL GetDebIMalloc(IMalloc FAR* FAR* ppmalloc);
|
|
|
|
VOID FAR* EBCALL CreateInstance(BSTR szTlibName, UINT uIndex);
|
|
VOID FAR* CreateInst(BSTR szTlibName, UINT uIndex);
|
|
|
|
BOOL GetStringDlg(char** pszString);
|
|
BOOL RenameDlg(char** pszNewName);
|
|
|
|
#if OE_MAC
|
|
Boolean CheckMacHelpEvent(EventRecord* evtPtr);
|
|
OSErr GetWDInfoTemp(short wdRefNum, short* pvRefNum, long* pdirid);
|
|
BOOL MacGetFullPath(long dirid, short vRefNum, LPSTR szPath);
|
|
void InitializeGrafport();
|
|
BOOL FCalcTextHeight(CHAR* szText, SHORT cx, SHORT* cy);
|
|
void RectToRECT(const Rect* prcm, RECT* prc);
|
|
void RECTToRect(const RECT* prc, Rect* prcm);
|
|
BOOL PaintWindow(EventRecord* pevt);
|
|
#endif // OE_MAC
|
|
|
|
DEFINE_GUID(IID_CVARCOLLECT, 0x2d736941, 0xc370, 0x1068, 0xb3, 0x69, 0x08, 0x00, 0x2b, 0x2b, 0x37, 0x87);
|
|
#endif //0
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#if OE_MAC
|
|
#ifdef _fstrcpy
|
|
#undef _fstrcpy
|
|
#endif
|
|
#ifdef _fstrncpy
|
|
#undef _fstrncpy
|
|
#endif
|
|
#ifdef _fstrncat
|
|
#undef _fstrncat
|
|
#endif
|
|
#ifdef _fstrcat
|
|
#undef _fstrcat
|
|
#endif
|
|
#ifdef _fstrchr
|
|
#undef _fstrchr
|
|
#endif
|
|
|
|
#define _fstrcpy strcpy
|
|
#define _fstrncpy strncpy
|
|
#define _fstrncat strncat
|
|
#define _fstrcat strcat
|
|
#define _fstrchr strchr
|
|
#endif //OE_MAC
|
|
|
|
#if OE_MAC
|
|
#define STDOLE_FILE "mstdole.tlb"
|
|
#define APPOBJ_FILE "mappobj"
|
|
#else //!OE_MAC
|
|
|
|
#if OE_WIN32
|
|
#define STDOLE_FILE "stdole32.tlb"
|
|
#define APPOBJ_FILE "apo"
|
|
#else //OE_WIN16
|
|
#define STDOLE_FILE "stdole.tlb"
|
|
#define APPOBJ_FILE "apobj"
|
|
#endif //OE_WIN16
|
|
|
|
#endif //!OE_MAC
|
|
|
|
#define VBAOLB_FILE "vba"
|
|
|
|
#endif
|
|
|
|
#ifndef DBALLOC_H_INCLUDED /* { */
|
|
#define DBALLOC_H_INCLUDED
|
|
|
|
|
|
interface IDbOutput : public IUnknown
|
|
{
|
|
STDMETHOD(QueryInterface)(THIS_ REFIID riid, void FAR* FAR* ppv) PURE;
|
|
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
|
|
STDMETHOD_(ULONG, Release)(THIS) PURE;
|
|
|
|
STDMETHOD_(void, Printf)(THIS_ char FAR* szFmt, ...) PURE;
|
|
|
|
STDMETHOD_(void, Assertion)(THIS_
|
|
BOOL cond,
|
|
char FAR* szExpr,
|
|
char FAR* szFile,
|
|
UINT uLine,
|
|
char FAR* szMsg) PURE;
|
|
};
|
|
|
|
STDAPI CreateDbAlloc(ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc);
|
|
|
|
// dballoc option flags - these are set at create time.
|
|
|
|
#define DBALLOC_NONE 0
|
|
|
|
#endif /* } DBALLOC_H_INCLUDED */
|
|
|
|
#define OOB_SELECTOROF(p) ((USHORT) ((ULONG) (p) >> 16))
|
|
#define DIM(X) (sizeof(X)/sizeof((X)[0]))
|
|
#define UNREACHED 0
|
|
static char szSigMsg[] = "Signature Check Failed";
|
|
|
|
|
|
// This defn switches in array handling code that knows how to
|
|
// handle non-aligned & non-power-of-2 arrays.
|
|
// Defined & used in hugearry.asm, dimalloc.cxx & exvarg.cxx
|
|
// In dimalloc.cxx it enables signature prefixing for huge
|
|
// arrays thus allowing testing of the array-adjust code in VBA.
|
|
#define ADJUST_ARRAYS 1
|
|
|
|
#if OE_WIN16
|
|
#define MAX_SIZE 64000
|
|
#else
|
|
#define MAX_SIZE UINT_MAX
|
|
#endif
|
|
|
|
#define Max
|
|
VOID FAR* HugeAlloc(DWORD bch);
|
|
VOID FAR* HugeRealloc(VOID FAR* pv, DWORD bchNew);
|
|
VOID FAR* HugeFree(VOID FAR* pv);
|
|
|
|
#if defined(WIN32)
|
|
|
|
# define MEMCMP(PV1, PV2, CB) memcmp((PV1), (PV2), (CB))
|
|
# define MEMCPY(PV1, PV2, CB) memcpy((PV1), (PV2), (CB))
|
|
# define MEMSET(PV, VAL, CB) memset((PV), (VAL), (CB))
|
|
# define MALLOC(CB) malloc(CB)
|
|
# define REALLOC(PV, CB) realloc((PV), (CB))
|
|
# define FREE(PV) free(PV)
|
|
# define MSIZE(PV) _msize(PV)
|
|
//UNDONE: NT has no heapmin() function?
|
|
//# define HEAPMIN() _heapmin()
|
|
|
|
#elif OE_MAC
|
|
|
|
#define MEMCPY memcpy
|
|
// #define REALLOC(PV, CB) SetPtrSize((char _near *)(PV), (CB))
|
|
// #define MALLOC(CB) NewPtr(CB)
|
|
// #define FREE(PV) DisposPtr((char _near *)(PV))
|
|
#define REALLOC(PV, CB) realloc((PV), (CB))
|
|
#define MALLOC(CB) malloc(CB)
|
|
#define FREE(PV) free(PV)
|
|
#define MEMCMP(PV1, PV2, CB) memcmp((PV1), (PV2), (CB))
|
|
#define MEMSET(PV, VAL, CB) memset((PV), (VAL), (CB))
|
|
// #define MSIZE(PV) GetPtrSize((char _near *)(PV))
|
|
#define MSIZE(PV) _msize(PV)
|
|
#define HEAPMIN() _heapmin()
|
|
|
|
#else
|
|
|
|
# define MEMCMP(PV1, PV2, CB) _fmemcmp((PV1), (PV2), (CB))
|
|
# define MEMCPY(PV1, PV2, CB) _fmemcpy((PV1), (PV2), (CB))
|
|
# define MEMSET(PV, VAL, CB) _fmemset((PV), (VAL), (CB))
|
|
# define MALLOC(CB) _fmalloc(CB)
|
|
# define REALLOC(PV, CB) _frealloc(PV, CB)
|
|
# define FREE(PV) _ffree(PV)
|
|
# define MSIZE(PV) _fmsize(PV)
|
|
# define HEAPMIN() _fheapmin()
|
|
|
|
#endif
|
|
|
|
class FAR CStdDbOutput : public IDbOutput {
|
|
public:
|
|
static IDbOutput FAR* Create();
|
|
|
|
// IUnknown methods
|
|
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
|
|
STDMETHOD_(ULONG, AddRef)(void);
|
|
STDMETHOD_(ULONG, Release)(void);
|
|
|
|
// IDbOutput methods
|
|
STDMETHOD_(void, Printf)(char FAR* szFmt, ...);
|
|
STDMETHOD_(void, Assertion)(BOOL cond, char FAR* szExpr, char FAR* szFile, UINT uLine, char FAR* szMsg);
|
|
|
|
void FAR* operator new(size_t cb) {
|
|
return MALLOC(cb);
|
|
}
|
|
void operator delete(void FAR* pv) {
|
|
FREE(pv);
|
|
}
|
|
|
|
CStdDbOutput() {
|
|
m_refs = 0;
|
|
}
|
|
|
|
private:
|
|
ULONG m_refs;
|
|
|
|
char m_rgch[128]; // buffer for output formatting
|
|
};
|
|
|
|
|
|
//implementation of the debug allocator
|
|
|
|
|
|
class FAR CAddrNode
|
|
{
|
|
public:
|
|
void FAR* m_pv; // instance
|
|
ULONG m_cb; // size of allocation in BYTES
|
|
ULONG m_nAlloc; // the allocation pass count
|
|
CAddrNode FAR* m_next;
|
|
|
|
void FAR* operator new(size_t cb) {
|
|
return MALLOC(cb);
|
|
}
|
|
void operator delete(void FAR* pv) {
|
|
FREE(pv);
|
|
}
|
|
};
|
|
|
|
|
|
class FAR CDbAlloc : public IMalloc
|
|
{
|
|
public:
|
|
static HRESULT Create(ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc);
|
|
|
|
// IUnknown methods
|
|
STDMETHOD(QueryInterface)(REFIID riid, void FAR* FAR* ppv);
|
|
STDMETHOD_(ULONG, AddRef)(void);
|
|
STDMETHOD_(ULONG, Release)(void);
|
|
|
|
// IMalloc methods
|
|
STDMETHOD_(void FAR*, Alloc)(ULONG cb);
|
|
STDMETHOD_(void FAR*, Realloc)(void FAR* pv, ULONG cb);
|
|
STDMETHOD_(void, Free)(void FAR* pv);
|
|
STDMETHOD_(ULONG, GetSize)(void FAR* pv);
|
|
STDMETHOD_(int, DidAlloc)(void FAR* pv);
|
|
STDMETHOD_(void, HeapMinimize)(void);
|
|
|
|
VOID IMallocHeapChecker();
|
|
VOID MemInstance();
|
|
|
|
void FAR* operator new(size_t cb) {
|
|
return MALLOC(cb);
|
|
}
|
|
void operator delete(void FAR* pv) {
|
|
FREE(pv);
|
|
}
|
|
|
|
private:
|
|
ULONG m_refs;
|
|
ULONG m_cAllocCalls; // total count of allocation calls
|
|
IDbOutput FAR* m_pdbout; // output interface
|
|
CAddrNode FAR* m_rganode[64]; // address instance table
|
|
|
|
// instance table methods
|
|
|
|
void AddInst(void FAR* pv, ULONG nAlloc, ULONG cb);
|
|
void DelInst(void FAR* pv);
|
|
CAddrNode FAR* GetInst(void FAR* pv);
|
|
|
|
BOOL IsEmpty(void);
|
|
void DumpInstTable(void);
|
|
|
|
void DumpInst(CAddrNode FAR* pn);
|
|
|
|
inline UINT HashInst(void FAR* pv) const {
|
|
return ((UINT)((ULONG)pv >> 4)) % DIM(m_rganode);
|
|
}
|
|
|
|
// output method(s)
|
|
|
|
inline void Assertion(BOOL cond, char FAR* szExpr, char FAR* szFile, UINT uLine, char FAR* szMsg)
|
|
{
|
|
m_pdbout->Assertion(cond, szExpr, szFile, uLine, szMsg);
|
|
}
|
|
|
|
#define ASSERT(X) Assertion(X, #X, __FILE__, __LINE__, NULL)
|
|
#define ASSERTSZ(X, SZ) Assertion(X, #X, __FILE__, __LINE__, SZ)
|
|
|
|
#if OE_RISC
|
|
char m_rgchSig[cbAlign];
|
|
#else
|
|
char m_rgchSig[4];
|
|
#endif // !(OE_RISC)
|
|
|
|
public:
|
|
CDbAlloc() {
|
|
m_refs = 1;
|
|
m_pdbout = NULL;
|
|
m_cAllocCalls = 0;
|
|
MEMSET(m_rganode, 0, sizeof(m_rganode));
|
|
m_rgchSig[0] = m_rgchSig[2] = (char)0xBA;
|
|
m_rgchSig[1] = m_rgchSig[3] = (char)0xBE;
|
|
#if OE_RISC
|
|
#if (cbAlign == 8)
|
|
m_rgchSig[4] = m_rgchSig[6] = (char)0xBA;
|
|
m_rgchSig[5] = m_rgchSig[7] = (char)0xBE;
|
|
#else
|
|
#error Invalid cbAlign value.
|
|
#endif // cbAlign
|
|
#endif // OE_RISC
|
|
}
|
|
};
|
|
|
|
|
|
/*
|
|
*HRESULT CreateDbAlloc(ULONG, IDbOutput*, IMalloc**)
|
|
*Purpose:
|
|
* Create an instance of CDbAlloc -- a debug implementation
|
|
* of IMalloc.
|
|
|
|
*Entry:
|
|
* pdbout = optional IDbOutput interface to use for ouput
|
|
* (if NULL, then the default debug output interface will be used)
|
|
* options =
|
|
|
|
*Exit:
|
|
* return value = HRESULT
|
|
* *ppmalloc = pointer to an IMalloc interface
|
|
*/
|
|
STDAPI CreateDbAlloc(ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc)
|
|
{
|
|
return CDbAlloc::Create(options, pdbout, ppmalloc);
|
|
}
|
|
|
|
HRESULT CDbAlloc::Create(ULONG options, IDbOutput FAR* pdbout, IMalloc FAR* FAR* ppmalloc)
|
|
{
|
|
HRESULT hresult;
|
|
CDbAlloc FAR* pmalloc;
|
|
|
|
// default the instance of IDbOutput if the user didn't supply one
|
|
if (pdbout == NULL && ((pdbout = CStdDbOutput::Create()) == NULL)) {
|
|
hresult = ResultFromScode(E_OUTOFMEMORY);
|
|
goto LError0;
|
|
}
|
|
|
|
pdbout->AddRef();
|
|
|
|
if ((pmalloc = new FAR CDbAlloc()) == NULL) {
|
|
hresult = ResultFromScode(E_OUTOFMEMORY);
|
|
goto LError1;
|
|
}
|
|
|
|
pmalloc->m_pdbout = pdbout;
|
|
*ppmalloc = pmalloc;
|
|
return NOERROR;
|
|
|
|
LError1:;
|
|
pdbout->Release();
|
|
pmalloc->Release();
|
|
|
|
LError0:;
|
|
return hresult;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CDbAlloc::QueryInterface(REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
HRESULT hresult;
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif // OE_MAC
|
|
|
|
if (riid == IID_IUnknown) {
|
|
*ppv = this;
|
|
AddRef();
|
|
hresult = NOERROR;
|
|
} else
|
|
hresult = ResultFromScode(E_NOINTERFACE);
|
|
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif // OE_MAC
|
|
|
|
return hresult;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CDbAlloc::AddRef()
|
|
{
|
|
return ++m_refs;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CDbAlloc::Release()
|
|
{
|
|
// FILE *pfileLog; // UNDONE stevenl -- not used right now
|
|
|
|
if (--m_refs == 0) {
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif // OE_MAC
|
|
|
|
// check for memory leakage
|
|
if (!IsEmpty()) {
|
|
m_pdbout->Printf("Memory Leak Detected,\n");
|
|
DumpInstTable();
|
|
ASSERTSZ(FALSE, "Memory leaked");
|
|
} else {
|
|
// No memory has leaked. If we're running a test script,
|
|
// we want the line "No Memory Leaks." at the end of the
|
|
// script, so that there will be a baseline failure if
|
|
// memory has leaked. The global g_szLogFile has the name
|
|
// of the file, if there is one.
|
|
|
|
#if 0
|
|
if (strlen(g_szLogFile)) {
|
|
#if 0
|
|
// UNDONE 20-May-93 stevenl:
|
|
// This is #ifdef'ed out until we feel like
|
|
// messing with all the baselines again.
|
|
|
|
pfileLog = fopen(g_szLogFile, "at");
|
|
if (pfileLog) {
|
|
fprintf(pfileLog, "No Memory Leaks.");
|
|
fclose(pfileLog);
|
|
}
|
|
#endif
|
|
} // if
|
|
#endif //0
|
|
} // else
|
|
|
|
m_pdbout->Release();
|
|
delete this;
|
|
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif // OE_MAC
|
|
|
|
return 0;
|
|
}
|
|
|
|
return m_refs;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(void FAR*)
|
|
CDbAlloc::Alloc(ULONG cb)
|
|
{
|
|
ULONG size;
|
|
VOID FAR* pv;
|
|
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif // OE_MAC
|
|
|
|
#if 0
|
|
// If allocations have been disabled (probably because we're in
|
|
// the middle of a save), just return NULL.
|
|
if (g_fNoAllocs)
|
|
return NULL;
|
|
#endif //0
|
|
|
|
IMallocHeapChecker();
|
|
MemInstance();// ++m_cAllocCalls;
|
|
size = (ULONG)cb;
|
|
|
|
// Support for Huge Arrays
|
|
if ((cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
if ((pv = MALLOC((size_t)(size + 2 * sizeof(m_rgchSig)))) == NULL)
|
|
goto Error;
|
|
} else {
|
|
if ((pv = (VOID FAR*)HugeAlloc(size + 2 * sizeof(m_rgchSig))) == NULL)
|
|
goto Error;
|
|
}
|
|
|
|
// set allocated block to some non-zero value
|
|
MEMSET(pv, -1, (size_t)(size + 2 * sizeof(m_rgchSig)));
|
|
|
|
#if ADJUST_ARRAYS
|
|
if ((cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// put signature at end of allocated block
|
|
MEMCPY((char FAR*)pv + size + sizeof(m_rgchSig), m_rgchSig, (size_t)sizeof(m_rgchSig));
|
|
}
|
|
|
|
// put signature at the head of the allocated block
|
|
MEMCPY((char FAR*)pv, m_rgchSig, sizeof(m_rgchSig));
|
|
pv = (char FAR*)pv + sizeof(m_rgchSig);
|
|
|
|
#else
|
|
// We do not put the signature for huge memory allocation
|
|
if ((cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// put signature at end of allocated block
|
|
MEMCPY((char FAR*)pv + size + sizeof(m_rgchSig), m_rgchSig, (size_t)sizeof(m_rgchSig));
|
|
|
|
// put signature at the head of the allocated block
|
|
MEMCPY((char FAR*)pv, m_rgchSig, sizeof(m_rgchSig));
|
|
}
|
|
|
|
// For Huge allocation return the pointer to the beginnig of the seg.
|
|
if ((cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// return the pointer to the beginning of the block to be returned
|
|
pv = (char FAR*)pv + sizeof(m_rgchSig);
|
|
}
|
|
#endif
|
|
|
|
// save the address returned and it's size also.
|
|
AddInst(pv, m_cAllocCalls, size);
|
|
|
|
// FALL THROUGH!!!
|
|
|
|
Error:
|
|
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif // OE_MAC
|
|
|
|
return pv;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(void FAR*)
|
|
CDbAlloc::Realloc(void FAR* pv, ULONG cb)
|
|
{
|
|
ULONG size;
|
|
ULONG sizeToFree;
|
|
CAddrNode FAR* pn;
|
|
|
|
if (pv == NULL) {
|
|
return Alloc(cb);
|
|
}
|
|
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif // OE_MAC
|
|
|
|
// ++m_cAllocCalls;
|
|
MemInstance();
|
|
|
|
pn = GetInst(pv);
|
|
|
|
sizeToFree = pn->m_cb;
|
|
ASSERT(pn != NULL);
|
|
|
|
if (cb == 0) {
|
|
Free(pv);
|
|
pv = NULL;
|
|
goto Done;
|
|
}
|
|
|
|
#if 0
|
|
// If allocations have been disabled (probably because we're in
|
|
// the middle of a save) and we're trying to increase the size of
|
|
// the allocated block, just return NULL. We allow decreases, since
|
|
// that can't cause an out of memory error in a real allocator.
|
|
if (cb > sizeToFree&& g_fNoAllocs)
|
|
return NULL;
|
|
#endif //0
|
|
|
|
size = cb;
|
|
|
|
// UNDONE : This does not handle the case when we mix the huge alloc and
|
|
// and realloc.
|
|
if (((sizeToFree + 2 * sizeof(m_rgchSig)) < MAX_SIZE) && ((size + 2 * sizeof(m_rgchSig)) < MAX_SIZE)) {
|
|
// we delete the instance from the table using the address passed in.
|
|
DelInst(pv);
|
|
|
|
// get the address of the original memory allocated
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
|
|
// allocte enough memory to put the signature also.
|
|
if ((pv = REALLOC(pv, (size_t)(size + 2 * sizeof(m_rgchSig)))) == NULL)
|
|
goto Done;
|
|
} else {
|
|
if (((sizeToFree + 2 * sizeof(m_rgchSig)) >= MAX_SIZE) &&
|
|
((size + 2 * sizeof(m_rgchSig)) >= MAX_SIZE)) {
|
|
|
|
// we delete the instance from the table using the address passed in.
|
|
DelInst(pv);
|
|
|
|
#if ADJUST_ARRAYS
|
|
// get the address of the original memory allocated
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
#endif
|
|
// allocte enough memory to put the signature also.
|
|
if ((pv = HugeRealloc(pv, size + 2 * sizeof(m_rgchSig))) == NULL)
|
|
goto Done;
|
|
} else {
|
|
VOID FAR* pvNew;
|
|
ULONG cbCopy;
|
|
|
|
if ((pvNew = Alloc(size)) == NULL) {
|
|
// if the memory to be free is < MAX_SIZE then adjust the pointer
|
|
if ((sizeToFree + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// get the address of the original memory allocated
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
}
|
|
|
|
Free(pv);
|
|
pv = NULL;
|
|
goto Done;
|
|
}
|
|
|
|
cbCopy = (sizeToFree < size) ? sizeToFree : size;
|
|
|
|
// copy the original contents
|
|
MEMCPY((char FAR*)pvNew, (char FAR*)pv, (size_t)cbCopy);
|
|
|
|
#if ADJUST_ARRAYS
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
#else
|
|
// if the memory to be free is < MAX_SIZE then adjust the pointer
|
|
if ((sizeToFree + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// get the address of the original memory allocated
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
}
|
|
|
|
#endif
|
|
|
|
Free((char FAR*)pv + sizeof(m_rgchSig));
|
|
pv = pvNew;
|
|
goto Done;
|
|
}
|
|
}
|
|
|
|
// We do not put the signature at the tail for huge memory allocation
|
|
if ((size + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// put signature at end of allocated block
|
|
// NOTE:- the signature for the header is already there.
|
|
MEMCPY((char FAR*)pv + size + sizeof(m_rgchSig), m_rgchSig, sizeof(m_rgchSig));
|
|
}
|
|
|
|
#if ADJUST_ARRAYS
|
|
pv = (char FAR*)pv + sizeof(m_rgchSig);
|
|
#else
|
|
// For Huge allocation return the pointer to the beginnig of the seg.
|
|
if ((cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// return the pointer to the beginning of the block (to be used
|
|
// by the caller).
|
|
pv = (char FAR*)pv + sizeof(m_rgchSig);
|
|
}
|
|
#endif
|
|
|
|
// save the address returned and it's size also.
|
|
AddInst(pv, m_cAllocCalls, size);
|
|
|
|
Done:
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif // OE_MAC
|
|
return pv;
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(void) CDbAlloc::Free(void FAR* pv)
|
|
{
|
|
CAddrNode FAR* pn;
|
|
ULONG sizeToFree;
|
|
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif // OE_MAC
|
|
|
|
// STORAGE.DLL Calls Free(NULL) alot
|
|
if (pv == NULL)
|
|
goto Done;
|
|
|
|
pn = GetInst(pv);
|
|
|
|
// check for attempt to free an instance we didnt allocate
|
|
if (pn == NULL) {
|
|
ASSERTSZ(FALSE, "pointer freed by wrong allocator");
|
|
goto Done;
|
|
}
|
|
|
|
// We do not put the signature at the tail for huge memory allocation
|
|
if ((pn->m_cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// verify the signature at the tail
|
|
if (MEMCMP((char FAR*)pv + pn->m_cb, m_rgchSig, sizeof(m_rgchSig)) != 0) {
|
|
m_pdbout->Printf(szSigMsg); m_pdbout->Printf("\n");
|
|
DumpInst(GetInst(pv));
|
|
ASSERTSZ(FALSE, szSigMsg);
|
|
}
|
|
|
|
#if ADJUST_ARRAYS
|
|
}
|
|
|
|
{
|
|
#endif
|
|
// verify the signature at the head
|
|
if (MEMCMP((char FAR*)pv - sizeof(m_rgchSig), m_rgchSig, sizeof(m_rgchSig)) != 0) {
|
|
m_pdbout->Printf(szSigMsg); m_pdbout->Printf("\n");
|
|
DumpInst(GetInst(pv));
|
|
ASSERTSZ(FALSE, szSigMsg);
|
|
}
|
|
}
|
|
|
|
sizeToFree = pn->m_cb;
|
|
|
|
DelInst(pv);
|
|
|
|
#if ADJUST_ARRAYS
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
#else
|
|
if ((sizeToFree + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// get the address of the original memory allocated
|
|
pv = (char FAR*)pv - sizeof(m_rgchSig);
|
|
}
|
|
#endif
|
|
|
|
// stomp on the contents of the block
|
|
MEMSET(pv, 0xCC, (size_t)(sizeToFree + 2 * sizeof(m_rgchSig)));
|
|
|
|
if ((sizeToFree + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
|
|
FREE(pv);
|
|
} else {
|
|
HugeFree(pv);
|
|
}
|
|
|
|
Done:;
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif // OE_MAC
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CDbAlloc::GetSize(void FAR* pv)
|
|
{
|
|
CAddrNode FAR* pn;
|
|
ASSERT((pn = GetInst(pv)) != NULL);
|
|
|
|
// dont count extra signature bytes in size
|
|
return pn->m_cb;
|
|
}
|
|
|
|
VOID CDbAlloc::MemInstance()
|
|
{
|
|
++m_cAllocCalls;
|
|
}
|
|
|
|
|
|
/*
|
|
*PUBLIC HRESULT CDbAlloc::DidAlloc
|
|
*Purpose:
|
|
* Answer if the given address belongs to a block allocated by
|
|
* this allocator.
|
|
|
|
*Entry:
|
|
* pv = the instance to lookup
|
|
|
|
*Exit:
|
|
* return value = int
|
|
* 1 - did alloc
|
|
* 0 - did *not* alloc
|
|
* -1 - dont know (according to the ole2 spec it is always legal
|
|
* for the allocator to answer "dont know")
|
|
*/
|
|
STDMETHODIMP_(int)
|
|
CDbAlloc::DidAlloc(void FAR* pv)
|
|
{
|
|
return -1; // answer "I dont know"
|
|
}
|
|
|
|
|
|
STDMETHODIMP_(void)
|
|
CDbAlloc::HeapMinimize()
|
|
{
|
|
#if !OE_WIN32 //UNDONE: what does HeapMinimize mean for WIN32?
|
|
#if OE_MAC
|
|
long a5Save = SetA5(*((long*)(long)CurrentA5));
|
|
#endif
|
|
HEAPMIN();
|
|
#if OE_MAC
|
|
SetA5(a5Save);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
// instance table methods
|
|
|
|
|
|
void CDbAlloc::AddInst(void FAR* pv, ULONG nAlloc, ULONG cb)
|
|
/*
|
|
*PRIVATE CDbAlloc::AddInst
|
|
*Purpose:
|
|
* Add the given instance to the address instance table.
|
|
*Entry:
|
|
* pv = the instance to add
|
|
* nAlloc = the allocation passcount of this instance
|
|
*/
|
|
{
|
|
UINT hash;
|
|
CAddrNode FAR* pn;
|
|
|
|
ASSERT(pv != NULL);
|
|
|
|
pn = (CAddrNode FAR*)new FAR CAddrNode();
|
|
ASSERT(pn != NULL);
|
|
|
|
pn->m_pv = pv;
|
|
pn->m_cb = cb;
|
|
pn->m_nAlloc = nAlloc;
|
|
|
|
hash = HashInst(pv);
|
|
pn->m_next = m_rganode[hash];
|
|
m_rganode[hash] = pn;
|
|
}
|
|
|
|
|
|
void CDbAlloc::DelInst(void FAR* pv)
|
|
/*
|
|
*UNDONE
|
|
*Purpose:
|
|
* Remove the given instance from the address instance table.
|
|
*Entry:
|
|
* pv = the instance to remove
|
|
*/
|
|
{
|
|
CAddrNode FAR* FAR* ppn, FAR* pnDead;
|
|
|
|
for (ppn = &m_rganode[HashInst(pv)]; *ppn != NULL; ppn = &(*ppn)->m_next) {
|
|
if ((*ppn)->m_pv == pv) {
|
|
pnDead = *ppn;
|
|
*ppn = (*ppn)->m_next;
|
|
delete pnDead;
|
|
// make sure it doesnt somehow appear twice
|
|
ASSERT(GetInst(pv) == NULL);
|
|
return;
|
|
}
|
|
}
|
|
|
|
ASSERT(UNREACHED);// didnt find the instance
|
|
}
|
|
|
|
|
|
CAddrNode FAR* CDbAlloc::GetInst(void FAR* pv)
|
|
{
|
|
CAddrNode FAR* pn;
|
|
|
|
for (pn = m_rganode[HashInst(pv)]; pn != NULL; pn = pn->m_next) {
|
|
if (pn->m_pv == pv)
|
|
return pn;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
void CDbAlloc::DumpInst(CAddrNode FAR* pn)
|
|
{
|
|
m_pdbout->Printf("[%lp] nAlloc=%ld size=%ld\n", pn->m_pv, pn->m_nAlloc, GetSize(pn->m_pv));
|
|
}
|
|
|
|
|
|
BOOL CDbAlloc::IsEmpty()
|
|
/*
|
|
*PRIVATE BOOL IsEmpty
|
|
*Purpose:
|
|
* Answer if the address instance table is empty.
|
|
*Exit:
|
|
* return value = BOOL, TRUE if empty, FALSE otherwise
|
|
*/
|
|
{
|
|
UINT u;
|
|
|
|
for (u = 0; u < DIM(m_rganode); ++u) {
|
|
if (m_rganode[u] != NULL) {
|
|
#if OE_MAC
|
|
// UNDONE: (dougf) temporary code to work around bug in OleInitialize.
|
|
// UNDONE: OleInitialize in the OLE2 Beta 1 build allocs 42 bytes of
|
|
// UNDONE: memory in it's first alloc, and never frees it. It
|
|
// UNDONE: also randomly fails to dealloc 39 bytes in WriteClassStg.
|
|
// UNDONE: Rip this code when we upgrade to a newer Mac OLE that has
|
|
// UNDONE: these bugs fixed.
|
|
CAddrNode FAR* pn;
|
|
ULONG cb;
|
|
|
|
pn = m_rganode[u];
|
|
cb = GetSize(pn->m_pv);
|
|
|
|
if (pn->m_nAlloc == 1 && cb == 42)
|
|
continue; // ignore OleInitialize's memory leak
|
|
if (cb == 39)
|
|
continue; // ignore the random OLE memory leak in WriteClassStg
|
|
// (happens when running cl\tbmacole.scr)
|
|
#endif //OE_MAC
|
|
|
|
#if OE_WIN32 && 0
|
|
// UNDONE: (dougf) temporary code to work around bug in OleInitialize.
|
|
// UNDONE: OleInitialize allocs 320 bytes of memory in it's first
|
|
// UNDONE: alloc, and 60 bytes in it's 3rd alloc, and never frees them.
|
|
// UNDONE: OleUnitialize allocs 68 & 172 bytes and never frees them.
|
|
// UNDONE: Rip this code when we upgrade
|
|
// UNDONE: to a newer NT OLE that has these bugs fixed.
|
|
CAddrNode FAR* pn;
|
|
ULONG cb;
|
|
|
|
pn = m_rganode[u];
|
|
cb = GetSize(pn->m_pv);
|
|
|
|
if (pn->m_nAlloc == 1 && cb == 320)
|
|
continue;// ignore OleInitialize's first memory leak
|
|
if (pn->m_nAlloc == 3 && cb == 60)
|
|
continue;// ignore OleInitialize's second memory leak
|
|
if (cb == 68)
|
|
continue;// ignore OleUninitialize's first memory leak
|
|
if (cb == 172)
|
|
continue;// ignore OleUninitialize's second memory leak
|
|
#endif //OE_WIN32
|
|
|
|
#if !FV_UNICODE_OLE // UNDONE: temporary (ignore the dstrmgr leaks)
|
|
return FALSE;// some other leak
|
|
#endif //!FV_UNICODE_OLE
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void CDbAlloc::DumpInstTable()
|
|
/*
|
|
*PRIVATE CDbAlloc::Dump
|
|
*Purpose:
|
|
* Print the current contents of the address instance table,
|
|
*/
|
|
{
|
|
UINT u;
|
|
CAddrNode FAR* pn;
|
|
|
|
for (u = 0; u < DIM(m_rganode); ++u) {
|
|
for (pn = m_rganode[u]; pn != NULL; pn = pn->m_next) {
|
|
DumpInst(pn);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* GetDebIMalloc()
|
|
* Purpose : Walks the Heap and verifies that the heap is not corrupted
|
|
*/
|
|
VOID CDbAlloc::IMallocHeapChecker()
|
|
{
|
|
UINT u;
|
|
CAddrNode FAR* pn;
|
|
|
|
return;
|
|
|
|
for (u = 0; u < DIM(m_rganode); ++u) {
|
|
for (pn = m_rganode[u]; pn != NULL; pn = pn->m_next) {
|
|
// Verify that the signature are the foot and the head of this
|
|
// instance is correct.
|
|
|
|
// We do not put the signature at the tail for huge memory allocation
|
|
if ((pn->m_cb + 2 * sizeof(m_rgchSig)) < MAX_SIZE) {
|
|
// verify the signature at the tail
|
|
if (MEMCMP((char FAR*)pn->m_pv + pn->m_cb, m_rgchSig, sizeof(m_rgchSig)) != 0) {
|
|
m_pdbout->Printf(szSigMsg); m_pdbout->Printf("\n");
|
|
DumpInst(GetInst(pn->m_pv));
|
|
ASSERTSZ(FALSE, szSigMsg);
|
|
}
|
|
|
|
// verify the signature at the head
|
|
if (MEMCMP((char FAR*)pn->m_pv - sizeof(m_rgchSig), m_rgchSig, sizeof(m_rgchSig)) != 0) {
|
|
m_pdbout->Printf(szSigMsg); m_pdbout->Printf("\n");
|
|
DumpInst(GetInst(pn->m_pv));
|
|
ASSERTSZ(FALSE, szSigMsg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//implementation of CStdDbOutput
|
|
|
|
|
|
IDbOutput FAR* CStdDbOutput::Create()
|
|
{
|
|
return (IDbOutput FAR*)new FAR CStdDbOutput();
|
|
}
|
|
|
|
STDMETHODIMP
|
|
CStdDbOutput::QueryInterface(REFIID riid, void FAR* FAR* ppv)
|
|
{
|
|
if (riid == IID_IUnknown) {
|
|
*ppv = this;
|
|
AddRef();
|
|
return NOERROR;
|
|
}
|
|
return ResultFromScode(E_NOINTERFACE);
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CStdDbOutput::AddRef()
|
|
{
|
|
return ++m_refs;
|
|
}
|
|
|
|
STDMETHODIMP_(ULONG)
|
|
CStdDbOutput::Release()
|
|
{
|
|
if (--m_refs == 0) {
|
|
delete this;
|
|
return 0;
|
|
}
|
|
return m_refs;
|
|
}
|
|
|
|
STDMETHODIMP_(void)
|
|
CStdDbOutput::Printf(char FAR* szFmt, ...)
|
|
{
|
|
va_list args;
|
|
char* pn, FAR* pf;
|
|
char rgchFmtBuf[128];
|
|
char rgchOutputBuf[128];
|
|
|
|
// copy the 'far' format string to a near buffer so we can use
|
|
// a medium model vsprintf, which only supports near data pointers.
|
|
|
|
pn = rgchFmtBuf, pf = szFmt;
|
|
while (*pf != '\0')
|
|
*pn++ = *pf++;
|
|
*pn = '\0';
|
|
|
|
va_start(args, szFmt);
|
|
|
|
vsprintf(rgchOutputBuf, rgchFmtBuf, args);
|
|
|
|
#if !OE_MAC
|
|
OutputDebugString(rgchOutputBuf);
|
|
#else
|
|
strcat(rgchOutputBuf, ";g");
|
|
DebugStr((const unsigned char*)c2pstr(rgchOutputBuf));
|
|
#endif
|
|
}
|
|
|
|
STDMETHODIMP_(void)
|
|
CStdDbOutput::Assertion(BOOL cond, char FAR* szExpr, char FAR* szFile, UINT uLine, char FAR* szMsg)
|
|
{
|
|
if (cond)
|
|
return;
|
|
|
|
// following is from compobj.dll (ole2)
|
|
// FnAssert(szExpr, szMsg, szFile, uLine);
|
|
DebAssert(0, szMsg);
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/*
|
|
* GetDebIMalloc()
|
|
|
|
* Purpose : Creates a debug version of IMalloc
|
|
*/
|
|
BOOL GetDebIMalloc(IMalloc FAR* FAR* ppmalloc)
|
|
{
|
|
// For Debug version we want to provide our own implementation of
|
|
// IMalloc. But for release version we use the default.
|
|
HRESULT hresult;
|
|
IMalloc FAR* pmalloc;
|
|
|
|
pmalloc = NULL;
|
|
hresult = CreateDbAlloc(DBALLOC_NONE, NULL, &pmalloc);
|
|
|
|
if (hresult != NOERROR)
|
|
return FALSE;
|
|
|
|
*ppmalloc = pmalloc;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
VOID FAR* HugeAlloc(DWORD bch)
|
|
/*
|
|
Purpose:
|
|
Allocate a system memblock of given size and return its handle.
|
|
Note: on Win16 dereferences handle and produce 32-bit
|
|
address = selector:offset=0.
|
|
Inputs:
|
|
bch Allocation request. Can be >64K.
|
|
Outputs:
|
|
Returns an HSYS. NULL if unsuccessful.
|
|
*/
|
|
{
|
|
#if OE_WIN16
|
|
VOID FAR* pv;
|
|
HANDLE hMem;
|
|
|
|
if (((hMem = GlobalAlloc(GMEM_MOVEABLE, bch)) == NULL)) {
|
|
return NULL;
|
|
} else if ((pv = (VOID FAR*) GlobalLock(hMem)) == NULL) {
|
|
return NULL;
|
|
} else {
|
|
return (VOID FAR*)pv;
|
|
}
|
|
#elif OE_MACNATIVE
|
|
|
|
Handle hMemBlock;
|
|
THz pCurrZone;
|
|
OSErr oserr;
|
|
|
|
// The following is a work-around to our bogus code that
|
|
// caches pointers to moveable memory. The basic idea
|
|
// is that we allocate all such memory out of a sub-heap
|
|
// inside the host application (or inside our own heap when
|
|
// a .DLL). The zone is switched in briefly to allocate,
|
|
// then switched back to avoid the OS or CODE seg loads
|
|
// from allocating there-in.
|
|
|
|
// The practice of caching pointers to moveable memory on
|
|
// the mac should be fixed to gain optimal use of available
|
|
// memory. The sub-heap scheme pools available memory
|
|
// and keeps it from being used for loading code when data
|
|
// is small. Visa-versa, we cannot flush more code out
|
|
// when the data expands to the heap limit. (jwc)
|
|
|
|
|
|
DebAssert(g_pOBZone != NULL, "OB Zone used before being allocated.");
|
|
pCurrZone = GetZone(); // save current heap zone.
|
|
SetZone(g_pOBZone); // set to OB's zone.
|
|
|
|
// Allocate moveable mac memblock.
|
|
hMemBlock = NewHandle(bch);
|
|
// get the error before calling SetZone. 'Cos SetZone can
|
|
// change the memory error.
|
|
oserr = MemError();
|
|
|
|
SetZone(pCurrZone); // always restore zone.
|
|
|
|
if (oserr) {
|
|
return NULL;
|
|
} else {
|
|
return (HSYS)hMemBlock;
|
|
}
|
|
|
|
#elif OE_MAC
|
|
|
|
Handle hMemBlock;
|
|
OSErr oserr;
|
|
|
|
// Allocate moveable mac memblock.
|
|
hMemBlock = NewHandle(bch);
|
|
oserr = MemError();
|
|
if (oserr) {
|
|
return NULL;
|
|
} else {
|
|
return (VOID FAR*)hMemBlock;
|
|
}
|
|
|
|
#elif OE_WIN32
|
|
|
|
VOID FAR* pv = NULL;
|
|
|
|
return (VOID FAR*)VirtualAlloc(pv, bch, MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
#else
|
|
#error Bad OE
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
VOID FAR* HugeRealloc(VOID FAR* pv, DWORD bchNew)
|
|
/*
|
|
HsysReallocHsys
|
|
Purpose:
|
|
Reallocate a system memblock given handle to new size.
|
|
Shrinking won't move block.
|
|
Inputs:
|
|
hsys Handle to sys memblock they want to realloc.
|
|
bchNew New size they want. Can be >64K.
|
|
Outputs:
|
|
Returns an HSYS. NULL if unsuccessful.
|
|
*/
|
|
{
|
|
#if OE_WIN16 // TEMPORARY
|
|
#if OE_WIN16
|
|
|
|
HANDLE hMem, hMemNew;
|
|
VOID FAR* pvNew;
|
|
USHORT usSel;
|
|
DWORD dwMem;
|
|
DWORD dwNewSize = bchNew;
|
|
#if ID_DEBUG
|
|
ULONG cbOld;
|
|
#endif
|
|
|
|
usSel = OOB_SELECTOROF((void FAR*)pv);// Get selector
|
|
|
|
if ((dwMem = GlobalHandle((WORD)usSel)) == NULL) {
|
|
return NULL;
|
|
} else {
|
|
hMem = (HANDLE)LOWORD(dwMem);// Extract the handle.
|
|
|
|
#if ID_DEBUG
|
|
cbOld = GlobalSize(hMem);// get the size of the old block
|
|
#endif
|
|
|
|
if (((hMemNew = GlobalReAlloc(hMem, bchNew, GMEM_MOVEABLE)) == NULL)) {
|
|
return NULL;
|
|
} else if ((pvNew = GlobalLock(hMemNew)) == NULL) {
|
|
return NULL;
|
|
} else {
|
|
return (VOID FAR*)pvNew;
|
|
}
|
|
}
|
|
|
|
#elif OE_MACNATIVE
|
|
|
|
Handle hMemBlock;
|
|
THz pCurrZone;
|
|
OSErr oserr;
|
|
#if ID_DEBUG
|
|
ULONG cbOld;
|
|
#endif
|
|
|
|
hMemBlock = (Handle)hsys;
|
|
|
|
#if ID_DEBUG
|
|
cbOld = GetHandleSize(hMemBlock);// get the size of the old block
|
|
#endif
|
|
|
|
pCurrZone = GetZone(); // save current zone
|
|
SetZone(HandleZone((Handle)hsys)); // must set proper zone or
|
|
SetHandleSize(hMemBlock, bchNew); // handle will likely
|
|
// jump to curr zone if it moves.
|
|
oserr = MemError();
|
|
SetZone(pCurrZone); // restore current zone.
|
|
if (oserr == memFullErr) {
|
|
return NULL;// Out of memory
|
|
}
|
|
|
|
DebAssert((MemError() != nilHandleErr), "HsysReallocHsys: NIL master pointer ");
|
|
DebAssert((MemError() != memWZErr), "HsysReallocHsys: Attempt to operate on free Block");
|
|
|
|
// anything else would be an undocumented error
|
|
DebAssert(MemError() == noErr, "HsysReallocHsys: undocumented Mac error");
|
|
|
|
return (VOID FAR*)hMemBlock;
|
|
|
|
#elif OE_MAC
|
|
|
|
Handle hMemBlock;
|
|
OSErr oserr;
|
|
#if ID_DEBUG
|
|
ULONG cbOld;
|
|
#endif
|
|
|
|
hMemBlock = (Handle)hsys;
|
|
|
|
#if ID_DEBUG
|
|
cbOld = GetHandleSize(hMemBlock);// get the size of the old block
|
|
#endif
|
|
|
|
SetHandleSize(hMemBlock, bchNew); // realloc
|
|
oserr = MemError();
|
|
if (oserr == memFullErr) {
|
|
return NULL;// Out of memory
|
|
}
|
|
|
|
DebAssert((MemError() != nilHandleErr), "HsysReallocHsys: NIL master pointer ");
|
|
DebAssert((MemError() != memWZErr), "HsysReallocHsys: Attempt to operate on free Block");
|
|
|
|
// anything else would be an undocumented error
|
|
DebAssert(MemError() == noErr, "HsysReallocHsys: undocumented Mac error");
|
|
|
|
return (HSYS)hMemBlock;
|
|
|
|
#elif OE_WIN32
|
|
// UNDONE...
|
|
DebHalt("HsysReallocHsys: UNDONE for OE_WIN32");
|
|
return NULL;
|
|
#else
|
|
#error Bad OE
|
|
#endif
|
|
#endif // TEMPORARY
|
|
return NULL;
|
|
}
|
|
|
|
|
|
VOID FAR* HugeFree(VOID FAR* pv)
|
|
/*
|
|
FreeHsys
|
|
|
|
Purpose:
|
|
Free the sys memblock given a handle.
|
|
Implementation:
|
|
On Win16, get selector part of hsys,
|
|
get its handle, unlock and finally free.
|
|
On Mac: Just use DisposHandle
|
|
|
|
Inputs:
|
|
hsys Handle to memblock they want to free.
|
|
|
|
Outputs:
|
|
Returns NULL if successful, otherwise on failure
|
|
returns the input param.
|
|
*/
|
|
{
|
|
#if OE_WIN16
|
|
|
|
HANDLE hMem;
|
|
DWORD dwMem;
|
|
USHORT usSel = OOB_SELECTOROF((VOID FAR*)pv);
|
|
|
|
dwMem = GlobalHandle((WORD)usSel);
|
|
if (dwMem == NULL) {
|
|
// error
|
|
return pv;
|
|
} else {
|
|
hMem = (HANDLE)LOWORD(dwMem);
|
|
GlobalUnlock(hMem); // Can't fail cos nondiscardable.
|
|
if (GlobalFree(hMem) != NULL) {
|
|
return pv;// error
|
|
} else {
|
|
return NULL;// ok
|
|
}
|
|
}
|
|
|
|
#elif OE_MACNATIVE
|
|
THz pCurrZone;
|
|
#if ID_DEBUG
|
|
OSErr oserr;
|
|
#endif
|
|
|
|
pCurrZone = GetZone(); // save current zone
|
|
SetZone(HandleZone((Handle)hsys)); // must set to proper zone to correctly update free list.
|
|
|
|
DisposHandle((Handle)hsys);
|
|
|
|
#if ID_DEBUG
|
|
oserr = MemError(); // SetZone() will destroy MemError() result.
|
|
#endif
|
|
|
|
SetZone(pCurrZone); // restore zone.
|
|
|
|
DebAssert(oserr != memWZErr, "FreeHsys: attempt to operate on already free block.");
|
|
DebAssert(oserr == noErr, "FreeHsys: unexpected error.");
|
|
return NULL;
|
|
|
|
#elif OE_MAC
|
|
HSYS hsys = (HSYS)pv;
|
|
#if ID_DEBUG
|
|
OSErr oserr;
|
|
#endif
|
|
|
|
DisposHandle((Handle)hsys);
|
|
|
|
#if ID_DEBUG
|
|
oserr = MemError(); // SetZone() will destroy MemError() result.
|
|
|
|
DebAssert(oserr != memWZErr, "FreeHsys: attempt to operate on already free block.");
|
|
DebAssert(oserr == noErr, "FreeHsys: unexpected error.");
|
|
#endif
|
|
|
|
return NULL;
|
|
|
|
#elif OE_WIN32
|
|
// UNDONE...
|
|
DebAssert(FALSE, "FreeHsys: UNDONE for OE_WIN32");
|
|
return NULL;
|
|
#else
|
|
#error Bad OE
|
|
#endif // OE_WIN16
|
|
return NULL;
|
|
}
|
|
|
|
#endif //DEBUG
|