windows-nt/Source/XPSP1/NT/admin/burnslib/inc/mem.hpp
2020-09-26 16:20:57 +08:00

371 lines
7.3 KiB
C++

// Copyright (c) 1997-1999 Microsoft Corporation
//
// memory management stuff
//
// 7-30-98 sburns
namespace Burnslib
{
namespace Heap
{
// cause calls to new to capture the call stack at the point of
// allocation.
const WORD TRACE_ALLOCATIONS = (1 << 6);
void
DumpMemoryLeaks();
// called by the InitializationGuard. Read flags from registry,
// sets heap options.
void
Initialize();
// our replacement operator new implementation
void*
OperatorNew(size_t size, const char* file, int line)
throw (std::bad_alloc);
// ... and the corresponding replacement operator delete
// implementation
void
OperatorDelete(void* ptr)
throw ();
} // namespace Heap
} // namespace Burnslib
// Replace the global new and delete operators.
//
// If the allocation fails, the user is given a system modal retry/cancel
// window. If the user opts for retry, re-attempt the allocation. Otherwise
// throw bad_alloc.
//
// Note that the CRT heap APIs are used, and that the debug heap APIs are
// also available. This implies that other modules linking to the same CRT
// dll can install hooks that may break our implementation!
//lint -e(1727) ok that our re-definition is inline
inline
void* __cdecl
operator new(size_t size)
throw (std::bad_alloc)
{
return Burnslib::Heap::OperatorNew(size, 0, 0);
}
//lint -e(1548) ok that our redefinition throw spec doesn't match the CRT
inline
void* __cdecl
operator new[](size_t size)
throw (std::bad_alloc)
{
return Burnslib::Heap::OperatorNew(size, 0, 0);
}
// placement versions of operator new. Although we use the placement syntax,
// we use the additional parameters to record debug information about the
// allocation, rather than indicating a location to allocate memory.
inline
void* __cdecl
operator new(size_t size, const char* file, int line)
throw (std::bad_alloc)
{
return Burnslib::Heap::OperatorNew(size, file, line);
}
inline
void* __cdecl
operator new[](size_t size, const char* file, int line)
throw (std::bad_alloc)
{
return Burnslib::Heap::OperatorNew(size, file, line);
}
inline
void __cdecl
operator delete(void* ptr)
throw ()
{
// check for 0, since deleting the null pointer is legal.
if (ptr)
{
Burnslib::Heap::OperatorDelete(ptr);
}
}
inline
void __cdecl
operator delete[](void* ptr)
throw ()
{
if (ptr)
{
Burnslib::Heap::OperatorDelete(ptr);
}
}
// placement versions of operator delete. We must provide placement versions
// of operator delete with corresponding signatures to the placement versions
// of operator new that we have declared, even though we don't use those
// parameters.
inline
void __cdecl
operator delete(void* ptr, const char*, int)
throw ()
{
if (ptr)
{
Burnslib::Heap::OperatorDelete(ptr);
}
}
inline
void __cdecl
operator delete[](void* ptr, const char*, int)
throw ()
{
if (ptr)
{
Burnslib::Heap::OperatorDelete(ptr);
}
}
namespace Burnslib
{
namespace Heap
{
// An STL-compatible allocator class that uses our replacement new
// and delete operators. We define this class after redefining our
// operator new and delete, above, so that it uses our redefinition.
// @@ (is that necessary, as construct uses placement new?)
template <class T>
class Allocator
{
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
pointer
address(reference x) const
{
return &x;
}
const_pointer
address(const_reference x) const
{
return &x;
}
// allocate enough storage for n elements of type T
pointer
allocate(size_type n, const void * /* hint */ )
{
size_t size = n * sizeof(T);
return
reinterpret_cast<pointer>(
Burnslib::Heap::OperatorNew(size, 0, 0));
}
void
deallocate(void* p, size_type /* n */ )
{
if (p)
{
Burnslib::Heap::OperatorDelete(p);
}
}
void
construct(pointer p, const T& val)
{
// this calls placement new, which just insures that T's copy ctor
// is executed on memory at address p (so that the p becomes the
// this pointer of the new instance.
//lint -e534 -e522 ignore the return value, which is just p.
new (reinterpret_cast<void*>(p)) T(val);
}
void
destroy(pointer p)
{
ASSERT(p);
(p)->~T();
}
size_type
max_size() const
{
return size_t (-1) / sizeof (T);
}
char*
_Charalloc(size_type n)
{
size_t size = n * sizeof(char*);
return reinterpret_cast<char*>(
Burnslib::Heap::OperatorNew(size, 0, 0));
}
// use default ctor, op=, copy ctor, which do nothing, as this class
// has no members.
};
template<class T, class U>
inline
bool
operator==(
const Burnslib::Heap::Allocator<T>&,
const Burnslib::Heap::Allocator<U>&)
{
return (true);
}
template<class T, class U>
inline
bool
operator!=(
const Burnslib::Heap::Allocator<T>&,
const Burnslib::Heap::Allocator<U>&)
{
return (false);
}
} // namespace Heap
} // namespace Burnslib
#ifdef DBG
// redefine new to call our version that offers file and line number
// tracking. This causes calls to new of the form:
// X* px = new X;
// to expand to:
// X* px = new (__FILE__, __LINE__) X;
// which calls operator new(size_t, const char*, int)
#define new new(__FILE__, __LINE__)
#endif
// You should pass -D_DEBUG to the compiler to get this extra heap
// checking behavior. (The correct way to do this is to set DEBUG_CRTS=1
// in your build environment)
#ifdef _DEBUG
// A HeapFrame is an object that, upon destruction, dumps to the debugger a
// snapshot of the heap allocations that were made since its construction.
// This only works on chk builds. HeapFrame instances may overlap. Place
// one at the beginning of a lexical scope, and you will get a dump of all
// the allocations made in that scope.
//
// See HEAP_FRAME.
namespace Burnslib
{
namespace Heap
{
class Frame
{
public:
// Constructs a new instance. The object will track all allocations
// made after this ctor executes.
//
// file - name of the source file to be dumped with the allocation
// report. ** This pointer is aliased, so it should point to a
// static address. **
//
// line - line number in the above source file to be dumped with the
// allocation report.
Frame(const wchar_t* file, unsigned line);
// Dumps the allocations made since construction.
~Frame();
private:
const wchar_t* file;
unsigned line;
_CrtMemState checkpoint;
};
}
}
#define HEAP_FRAME() Burnslib::Heap::Frame __frame(__FILE__, __LINE__)
#else
#define HEAP_FRAME()
#endif