540 lines
14 KiB
C
540 lines
14 KiB
C
|
/***
|
||
|
*rtcpriv.h - declarations and definitions for RTC use
|
||
|
*
|
||
|
* Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
|
||
|
*
|
||
|
*Purpose:
|
||
|
* Contains the declarations and definitions for all RunTime Check
|
||
|
* support.
|
||
|
*
|
||
|
*Revision History:
|
||
|
* ??-??-?? KBF Created implementation header for RTC
|
||
|
* 05-26-99 KBF Removed RTCl & RTCv, added _RTC_ADVMEM stuff
|
||
|
* 10-14-99 PML Replace InitializeCriticalSection with wrapper function
|
||
|
* __crtInitCritSecAndSpinCount
|
||
|
*
|
||
|
****/
|
||
|
|
||
|
#ifndef _INC_RTCPRIV
|
||
|
#define _INC_RTCPRIV
|
||
|
|
||
|
#ifdef _RTC
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <winbase.h>
|
||
|
#include <malloc.h>
|
||
|
|
||
|
#include "rtcapi.h"
|
||
|
|
||
|
#pragma warning(disable:4710)
|
||
|
#pragma warning(disable:4711)
|
||
|
#ifndef __cplusplus
|
||
|
#error This header is only for use with the C++ compiler while building the RTC library code.
|
||
|
#endif
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma pack(push, 4)
|
||
|
#endif /* _MSC_VER */
|
||
|
|
||
|
#ifndef _RTC_DEBUG
|
||
|
#pragma optimize("gb1", on)
|
||
|
#endif
|
||
|
|
||
|
// Multithreaded code locking stuff...
|
||
|
|
||
|
#define INIT_LOCK __crtInitCritSecAndSpinCount(&_RTC_memlock, _CRT_SPINCOUNT)
|
||
|
#define LOCK EnterCriticalSection(&_RTC_memlock)
|
||
|
#define UNLOCK LeaveCriticalSection(&_RTC_memlock)
|
||
|
#define DEL_LOCK DeleteCriticalSection(&_RTC_memlock)
|
||
|
#define TRY_LOCK TryEnterCriticalSection(&_RTC_memlock)
|
||
|
extern CRITICAL_SECTION _RTC_memlock;
|
||
|
|
||
|
// Typedefs
|
||
|
struct _RTC_globals;
|
||
|
|
||
|
#ifdef _RTC_ADVMEM
|
||
|
class _RTC_SimpleHeap;
|
||
|
class _RTC_Container;
|
||
|
class _RTC_HeapBlock;
|
||
|
class _RTC_BinaryTree;
|
||
|
template<class T> class HashTable;
|
||
|
typedef unsigned char shadowtag;
|
||
|
typedef unsigned char index_elem;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
// General global functions & symbols
|
||
|
|
||
|
extern int _RTC_ErrorLevels[_RTC_ILLEGAL];
|
||
|
extern _RTC_globals *_RTC_globptr;
|
||
|
|
||
|
bool _RTC_Lock();
|
||
|
void _RTC_Unlock();
|
||
|
void _RTC_Failure(void *retaddr, int errnum);
|
||
|
_RTC_error_fn _RTC_GetErrorFunc(LPCVOID addr);
|
||
|
void _RTC_StackFailure(void *retaddr, const char *varname);
|
||
|
BOOL _RTC_GetSrcLine(DWORD address, char* source, int sourcelen,
|
||
|
int* pline, char** moduleName);
|
||
|
extern "C" {
|
||
|
void __fastcall _RTC_APISet(int on_off);
|
||
|
}
|
||
|
void _RTC_NotifyOthersOfChange(void *addr);
|
||
|
|
||
|
|
||
|
// When this changes, you'd better be sure that everything still works with the old stuff!
|
||
|
#define _RTC_CURRENT_VERSION 1
|
||
|
|
||
|
// The order of the initial stuff here can't change AT ALL!!!
|
||
|
struct _RTC_Funcs {
|
||
|
_RTC_error_fn err;
|
||
|
void (*notify)(void);
|
||
|
void *allocationBase;
|
||
|
_RTC_Funcs *next;
|
||
|
#ifdef _RTC_ADVMEM
|
||
|
int (*shadowoff)(void);
|
||
|
#endif
|
||
|
};
|
||
|
|
||
|
// definitions of library globals
|
||
|
// The order of this stuff MUST STAY THE SAME BETWEEN VERSION!!!
|
||
|
struct _RTC_globals {
|
||
|
int version;
|
||
|
CRITICAL_SECTION memlock;
|
||
|
_RTC_Funcs *callbacks;
|
||
|
#ifdef _RTC_ADVMEM
|
||
|
_RTC_SimpleHeap *heap2;
|
||
|
_RTC_SimpleHeap *heap4;
|
||
|
_RTC_SimpleHeap *heap8;
|
||
|
_RTC_Container *memhier;
|
||
|
shadowtag *shadow;
|
||
|
index_elem *pageidx;
|
||
|
HashTable<_RTC_HeapBlock> *heapblocks;
|
||
|
bool *pi_array;
|
||
|
bool shadowmemory;
|
||
|
#endif
|
||
|
};
|
||
|
#define _RTC_GLOBALS_SIZE 1024
|
||
|
|
||
|
/* Shadow Memory stuff */
|
||
|
#ifdef _RTC_ADVMEM
|
||
|
|
||
|
void _RTC_MS_Init();
|
||
|
void _RTC_MemFailure(void *retaddr, int errnum, const void *assign);
|
||
|
short _RTC_MSAllocShadow(memptr addr, unsigned size, unsigned state);
|
||
|
void _RTC_MSRestoreShadow(memptr addr, unsigned size, short id);
|
||
|
short _RTC_MSRenumberShadow(memptr addr, unsigned size, short notID);
|
||
|
void _RTC_MSFreeShadow(memptr addr, unsigned size);
|
||
|
void __cdecl _RTC_MSAllocateGlobals(void);
|
||
|
void _RTC_MSDecommitRange(memptr addr, unsigned size);
|
||
|
void _RTC_MSCommitRange(memptr addr, unsigned size, unsigned state);
|
||
|
extern "C" {
|
||
|
void __fastcall _RTC_CheckMem_API(memref addr, unsigned size);
|
||
|
}
|
||
|
|
||
|
// Unknown MUST be 0
|
||
|
#define IDX_STATE_UNKNOWN 0
|
||
|
#define IDX_STATE_ILLEGAL 1
|
||
|
#define IDX_STATE_PARTIALLY_KNOWN 2
|
||
|
#define IDX_STATE_FULLY_KNOWN 3
|
||
|
|
||
|
extern _RTC_Container *_RTC_memhier;
|
||
|
extern HashTable<_RTC_HeapBlock> *_RTC_heapblocks;
|
||
|
extern _RTC_SimpleHeap *_RTC_heap2;
|
||
|
extern _RTC_SimpleHeap *_RTC_heap4;
|
||
|
extern _RTC_SimpleHeap *_RTC_heap8;
|
||
|
extern shadowtag *_RTC_shadow;
|
||
|
extern index_elem *_RTC_pageidx;
|
||
|
extern bool *_RTC_pi_array;
|
||
|
extern bool _RTC_shadowmemory;
|
||
|
|
||
|
|
||
|
/**********************************/
|
||
|
|
||
|
#define ALLOC_SIZE 65536
|
||
|
|
||
|
class _RTC_SimpleHeap
|
||
|
{
|
||
|
struct FreeList
|
||
|
{
|
||
|
FreeList *next;
|
||
|
};
|
||
|
struct HeapNode
|
||
|
{
|
||
|
HeapNode *next; // next page in list (not necessarily free)
|
||
|
FreeList *free; // node-local free-list
|
||
|
union info
|
||
|
{
|
||
|
struct topStuff
|
||
|
{ // Stuff that pertains only to the top node
|
||
|
HeapNode *nxtFree; // Pointer to node containing free items
|
||
|
short wordSize; // The size of blocks in this heap
|
||
|
bool freePage; // True if there's a 100% free page
|
||
|
} top;
|
||
|
|
||
|
struct nonTopStuff
|
||
|
{ // Stuff that pertais only to non-top nodes
|
||
|
unsigned freeCount; // The free count for this node
|
||
|
HeapNode *prev; // previous link
|
||
|
} nontop;
|
||
|
} inf;
|
||
|
} head;
|
||
|
|
||
|
public:
|
||
|
|
||
|
_RTC_SimpleHeap(unsigned blockSize) throw();
|
||
|
~_RTC_SimpleHeap() throw();
|
||
|
|
||
|
void *operator new(unsigned) throw();
|
||
|
void operator delete(void *addr) throw();
|
||
|
|
||
|
void *alloc() throw();
|
||
|
void free(void *addr) throw();
|
||
|
};
|
||
|
|
||
|
extern _RTC_SimpleHeap *_RTC_heap2;
|
||
|
extern _RTC_SimpleHeap *_RTC_heap4;
|
||
|
extern _RTC_SimpleHeap *_RTC_heap8;
|
||
|
|
||
|
|
||
|
#define DATA(type, name) \
|
||
|
private: \
|
||
|
type _##name; \
|
||
|
public: \
|
||
|
type name() const { return _##name; }\
|
||
|
void name(type a) { _##name = a; }
|
||
|
|
||
|
class _RTC_HeapBlock
|
||
|
{
|
||
|
DATA(void *, addr); // The memory block address
|
||
|
DATA(unsigned, size); // The size of the block
|
||
|
DATA(_RTC_HeapBlock *, next); // The next element
|
||
|
DATA(_RTC_HeapBlock **,list); // The head list pointer
|
||
|
DATA(short, id); // The level ID of the block (for tiers)
|
||
|
DATA(short, tag); // The shadow tag of the block in shadow memory
|
||
|
|
||
|
public:
|
||
|
|
||
|
_RTC_HeapBlock(void *address, short lev)
|
||
|
: _addr(address), _id(lev) , _next(0), _list(0) {}
|
||
|
|
||
|
_RTC_HeapBlock(void *MemAddress, short Identifier, unsigned Size)
|
||
|
: _addr(MemAddress), _id(Identifier), _size(Size), _next(0), _list(0) {}
|
||
|
|
||
|
~_RTC_HeapBlock() throw()
|
||
|
{
|
||
|
if (_list) del(_list);
|
||
|
}
|
||
|
|
||
|
void *operator new(unsigned) throw()
|
||
|
{
|
||
|
return _RTC_heap8->alloc();
|
||
|
}
|
||
|
|
||
|
void operator delete(void *addr) throw()
|
||
|
{
|
||
|
_RTC_heap8->free(addr);
|
||
|
}
|
||
|
|
||
|
int operator<(const _RTC_HeapBlock &h) const
|
||
|
{
|
||
|
return _addr < h._addr;
|
||
|
}
|
||
|
|
||
|
int operator==(const _RTC_HeapBlock &h) const
|
||
|
{
|
||
|
return h._addr == _addr && h._id == _id;
|
||
|
}
|
||
|
|
||
|
bool contains(const _RTC_HeapBlock &h) const
|
||
|
{
|
||
|
return ((unsigned)_addr <= (unsigned)h._addr) &&
|
||
|
((unsigned)h._addr < (unsigned)_addr + _size);
|
||
|
}
|
||
|
|
||
|
unsigned hash(unsigned sz) const
|
||
|
{
|
||
|
return (((unsigned)_addr) ^ _id) % sz;
|
||
|
}
|
||
|
|
||
|
void add(_RTC_HeapBlock **lstHead) throw()
|
||
|
{
|
||
|
this->next(*lstHead);
|
||
|
this->list(lstHead);
|
||
|
*lstHead = this;
|
||
|
}
|
||
|
|
||
|
void del(_RTC_HeapBlock **lstHead) throw()
|
||
|
{
|
||
|
_RTC_HeapBlock *head = *lstHead;
|
||
|
_RTC_HeapBlock *prev = 0;
|
||
|
while (head != this)
|
||
|
{
|
||
|
prev = head;
|
||
|
head = head->next();
|
||
|
}
|
||
|
if (prev)
|
||
|
prev->next(this->next());
|
||
|
else
|
||
|
*lstHead = this->next();
|
||
|
next(0);
|
||
|
list(0);
|
||
|
}
|
||
|
};
|
||
|
|
||
|
#undef DATA
|
||
|
|
||
|
class _RTC_BinaryTree
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
class BinaryNode
|
||
|
{
|
||
|
public:
|
||
|
BinaryNode *l, *r;
|
||
|
_RTC_Container *val;
|
||
|
|
||
|
void *operator new(unsigned) throw()
|
||
|
{
|
||
|
return _RTC_heap4->alloc();
|
||
|
}
|
||
|
|
||
|
void operator delete(void *addr) throw()
|
||
|
{
|
||
|
_RTC_heap4->free(addr);
|
||
|
}
|
||
|
|
||
|
BinaryNode(BinaryNode *L, BinaryNode *R, _RTC_Container *V)
|
||
|
: l(L), r(R), val(V) {}
|
||
|
|
||
|
void kill() throw();
|
||
|
};
|
||
|
|
||
|
private:
|
||
|
|
||
|
BinaryNode *tree;
|
||
|
|
||
|
public:
|
||
|
|
||
|
_RTC_BinaryTree(_RTC_Container *i) throw()
|
||
|
: tree(new BinaryNode(0, 0, i)) {}
|
||
|
|
||
|
~_RTC_BinaryTree() throw()
|
||
|
{
|
||
|
if (tree)
|
||
|
{
|
||
|
tree->kill();
|
||
|
delete tree;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void *operator new(unsigned) throw()
|
||
|
{
|
||
|
return _RTC_heap2->alloc();
|
||
|
}
|
||
|
|
||
|
void operator delete(void *addr) throw() { _RTC_heap2->free(addr); }
|
||
|
|
||
|
// This will return either the container or null
|
||
|
_RTC_Container *get(_RTC_HeapBlock *) throw();
|
||
|
|
||
|
// This just adds to the current sib list
|
||
|
_RTC_Container* add(_RTC_HeapBlock *) throw();
|
||
|
|
||
|
// This just removes the item from the current sib list
|
||
|
_RTC_Container *del(_RTC_HeapBlock *) throw();
|
||
|
|
||
|
// Here's an iterator
|
||
|
class iter
|
||
|
{
|
||
|
_RTC_Container **allSibs;
|
||
|
int curSib;
|
||
|
int totSibs;
|
||
|
friend class _RTC_BinaryTree;
|
||
|
|
||
|
public:
|
||
|
// This thing should never be allocated...
|
||
|
void *operator new(unsigned)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
_RTC_Container *FindFirst(iter *) throw();
|
||
|
_RTC_Container *FindNext(iter *) throw();
|
||
|
};
|
||
|
|
||
|
class _RTC_Container
|
||
|
{
|
||
|
// kids - the item that has all the children
|
||
|
_RTC_BinaryTree *kids;
|
||
|
// inf - the item that specifies containment
|
||
|
_RTC_HeapBlock *inf;
|
||
|
|
||
|
// This kills this container, and all contained info
|
||
|
void kill() throw();
|
||
|
public:
|
||
|
_RTC_Container(_RTC_HeapBlock *hb)
|
||
|
: inf(hb), kids(0) {}
|
||
|
|
||
|
~_RTC_Container() throw()
|
||
|
{
|
||
|
if (inf || kids)
|
||
|
kill();
|
||
|
}
|
||
|
|
||
|
_RTC_HeapBlock *info() const
|
||
|
{
|
||
|
return inf;
|
||
|
}
|
||
|
|
||
|
bool contains(const _RTC_HeapBlock *i) const throw()
|
||
|
{
|
||
|
return inf ? inf->contains(*i) : true;
|
||
|
}
|
||
|
|
||
|
// Returns the parent container
|
||
|
_RTC_Container *DelChild(_RTC_HeapBlock *i) throw();
|
||
|
|
||
|
// Add this item as a child inside this container
|
||
|
// It may or may not be a direct child
|
||
|
// It returns the parent container
|
||
|
_RTC_Container *AddChild(_RTC_HeapBlock *i) throw();
|
||
|
|
||
|
// Find the container that contains the data given
|
||
|
_RTC_Container *FindChild(_RTC_HeapBlock *i) throw();
|
||
|
|
||
|
typedef _RTC_HeapBlock data;
|
||
|
void *operator new(unsigned) throw() { return _RTC_heap2->alloc(); }
|
||
|
void operator delete(void *addr) throw() { _RTC_heap2->free(addr); }
|
||
|
};
|
||
|
|
||
|
|
||
|
template <class T>
|
||
|
class HashTable
|
||
|
{
|
||
|
unsigned size;
|
||
|
T **elems;
|
||
|
|
||
|
public:
|
||
|
|
||
|
HashTable(unsigned s, void *mem)
|
||
|
: elems((T**)mem), size(s)
|
||
|
{
|
||
|
memset(elems, 0, size * sizeof(T*));
|
||
|
}
|
||
|
|
||
|
~HashTable() {}
|
||
|
|
||
|
void *operator new(unsigned) throw()
|
||
|
{
|
||
|
return _RTC_heap2->alloc();
|
||
|
}
|
||
|
|
||
|
void operator delete(void *addr) throw()
|
||
|
{
|
||
|
_RTC_heap2->free(addr);
|
||
|
}
|
||
|
|
||
|
T *find(T *key) throw()
|
||
|
{
|
||
|
unsigned hkey = key->hash(size);
|
||
|
T *elem = elems[hkey];
|
||
|
while (elem && !(*elem == *key))
|
||
|
elem = elem->next();
|
||
|
return elem;
|
||
|
}
|
||
|
|
||
|
void add(T *itm) throw()
|
||
|
{
|
||
|
unsigned hkey = itm->hash(size);
|
||
|
itm->add(&elems[hkey]);
|
||
|
}
|
||
|
|
||
|
void del(T *key) throw()
|
||
|
{
|
||
|
unsigned hkey = key->hash(size);
|
||
|
T *elem = elems[hkey];
|
||
|
while (elem && !(*elem == *key))
|
||
|
elem = elem->next();
|
||
|
elem->del(&elems[hkey]);
|
||
|
}
|
||
|
};
|
||
|
#endif
|
||
|
|
||
|
|
||
|
// Stuff for the debugger exception mechanism
|
||
|
// Swiped fro vcexcept.h in the LangAPI
|
||
|
#if !defined(_vcexcept_h)
|
||
|
#define _vcexcept_h
|
||
|
|
||
|
// the facility code we have chosen is based on the fact that we already
|
||
|
// use an exception of 'msc' when we throw C++ exceptions
|
||
|
|
||
|
#define FACILITY_VISUALCPP ((LONG)0x6D)
|
||
|
|
||
|
#define VcppException(sev,err) ((sev) | (FACILITY_VISUALCPP<<16) | err)
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
// define all exceptions here, so we don't mess with each other
|
||
|
/////////////////////////////////////////////////////////////////
|
||
|
|
||
|
// used by CRTs for C++ exceptions, really defined in ehdata.h
|
||
|
//#define EH_EXCEPTION_NUMBER VcppException( 3<<30, 0x7363 ) // SEV_ERROR, used by CRTs for C++
|
||
|
|
||
|
// used by debugger to do e.g. SetThreadName call
|
||
|
#define EXCEPTION_VISUALCPP_DEBUGGER VcppException(1<<30, 5000) // SEV_INFORMATIONAL
|
||
|
|
||
|
#endif // _vcexcept_h
|
||
|
// Ping the VC debugger
|
||
|
#define HelloVC( exinfo ) \
|
||
|
RaiseException( EXCEPTION_VISUALCPP_DEBUGGER, 0, sizeof(exinfo)/sizeof(DWORD), (DWORD*)&exinfo )
|
||
|
|
||
|
enum EXCEPTION_DEBUGGER_ENUM
|
||
|
{
|
||
|
EXCEPTION_DEBUGGER_NAME_THREAD = 0x1000,
|
||
|
EXCEPTION_DEBUGGER_PROBE = 0x1001,
|
||
|
EXCEPTION_DEBUGGER_RUNTIMECHECK = 0x1002,
|
||
|
|
||
|
EXCEPTION_DEBUGGER_MAX = 0x1002 // largest value this debugger understands
|
||
|
};
|
||
|
|
||
|
// must be convertible to DWORDs for use by RaiseException
|
||
|
typedef struct tagEXCEPTION_VISUALCPP_DEBUG_INFO
|
||
|
{
|
||
|
DWORD dwType; // one of the enums from above
|
||
|
union
|
||
|
{
|
||
|
struct
|
||
|
{
|
||
|
LPCSTR szName; // pointer to name (in user addr space)
|
||
|
DWORD dwThreadID; // thread ID (-1=caller thread)
|
||
|
DWORD dwFlags; // reserved for future use (eg User thread, System thread)
|
||
|
} SetName;
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
DWORD dwLevelRequired; // 0 = do you understand this private exception, else max value of enum
|
||
|
PBYTE pbDebuggerPresent; // debugger puts a non-zero value in this address if there
|
||
|
} DebuggerProbe;
|
||
|
|
||
|
struct
|
||
|
{
|
||
|
DWORD dwRuntimeNumber; // the type of the runtime check
|
||
|
BOOL bRealBug; // TRUE if never a false-positive
|
||
|
PVOID pvReturnAddress; // caller puts a return address in here
|
||
|
PBYTE pbDebuggerPresent; // debugger puts a non-zero value in this address if handled it
|
||
|
LPCWSTR pwRuntimeMessage; // pointer to Unicode message (or NULL)
|
||
|
} RuntimeError;
|
||
|
};
|
||
|
} EXCEPTION_VISUALCPP_DEBUG_INFO;
|
||
|
|
||
|
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#pragma pack(pop)
|
||
|
#endif /* _MSC_VER */
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#endif /* _INC_RTCPRIV */
|