Revision a794a6590d1184c57f65760f9e382c5c6c9bfb03 authored by Unknown Author on 31 May 2006, 07:48:57 UTC, committed by Unknown Author on 31 May 2006, 07:48:57 UTC
git-svn-id: http://root.cern.ch/svn/root/tags/v5-11-04@15252 27541ba8-7e3a-0410-8455-c3a389f83636
1 parent ca81efd
NewDelete.cxx
// @(#)root/new:$Name: $:$Id: NewDelete.cxx,v 1.7 2005/09/18 13:19:22 rdm Exp $
// Author: Fons Rademakers 29/07/95
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// Custom operators new and delete and ReAlloc functions. //
// //
// All new and delete operations in the ROOT system pass //
// via the custom new and delete operators defined in this file. //
// This scheme allows extensive memory checking and usage statistics //
// gathering and an easy way to access shared memory segments. //
// Memory checking is by default enabled and usage statistics is //
// gathered. Using the resource (in .rootrc): Root.MemStat one can //
// toggle statistics gathering on or off. More specifically on can trap //
// the allocation of a block of memory of a certain size. This can be //
// specified using the resource: Root.MemStat.size, using the resource //
// Root.MemStat.cnt one can specify after how many allocations of //
// this size the trap should occur. //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// statistics gathering in the system. //
// //
// When memory checking is enabled the following happens during //
// allocation: //
// - each allocation results in the allocation of 9 extra bytes: //
// 2 words in front and 1 byte at the end of the memory chunck //
// returned to the caller. //
// - the allocated memory is set to 0. //
// - the size of the chunck is stored in the first word. The second //
// word is left empty (for alignment). //
// - the last byte is initialized to MEM_MAGIC. //
// //
// And during de-allocation this happens: //
// - first the size if the block is checked. It should be >0 and //
// <= than any block allocated up to that moment. If not a Fatal //
// error is generated. //
// - the MEM_MAGIC byte at the end of the block is checked. When not //
// there, the memory has been overwritten and a Fatal error is //
// generated. //
// - memory block is reset to 0. //
// //
// Although this does not replace powerful tools like Purify, it is a //
// good first line of protection. //
// //
// Independent of any compile option settings the new, and ReAlloc //
// functions always set the memory to 0. //
// //
// The powerful MEM_DEBUG and MEM_STAT macros were borrowed from //
// the ET++ framework. //
// //
//////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include <errno.h>
#include "MemCheck.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TMath.h"
#include "TMapFile.h"
#include "TSystem.h"
#include "mmalloc.h"
void *CustomReAlloc1(void *ovp, size_t size);
void *CustomReAlloc2(void *ovp, size_t size, size_t oldsize);
class TReAllocInit {
public:
TReAllocInit() { TStorage::SetReAllocHooks(&CustomReAlloc1, &CustomReAlloc2); }
};
static TReAllocInit gReallocInit;
//---- memory checking macros --------------------------------------------------
#if !defined(R__NOSTATS)
# define MEM_DEBUG
# define MEM_STAT
# define MEM_CHECKOBJECTPOINTERS
#endif
#if defined(MEM_STAT) && !defined(MEM_DEBUG)
# define MEM_DEBUG
#endif
#ifdef MEM_DEBUG
# define MEM_MAGIC ((unsigned char)0xAB)
#ifdef R__B64
# define storage_size(p) ((size_t)(((size_t*)p)[-1]))
# define RealStart(p) ((char*)(p) - sizeof(size_t))
# define StoreSize(p, sz) (*((size_t*)(p)) = (sz))
# define ExtStart(p) ((char*)(p) + sizeof(size_t))
# define RealSize(sz) ((sz) + sizeof(size_t) + sizeof(char))
# define StoreMagic(p, sz) *((unsigned char*)(p)+sz+sizeof(size_t)) = MEM_MAGIC
#else
# define storage_size(p) ((size_t)(((int*)p)[-2]))
# define RealStart(p) ((char*)(p) - 2*sizeof(int))
# define StoreSize(p, sz) (*((int*)(p)) = (sz))
# define ExtStart(p) ((char*)(p) + 2*sizeof(int))
# define RealSize(sz) ((sz) + 2*sizeof(int) + sizeof(char))
# define StoreMagic(p, sz) *((unsigned char*)(p)+sz+2*sizeof(int)) = MEM_MAGIC
#endif
# define MemClear(p, start, len) \
if ((len) > 0) memset(&((char*)(p))[(start)], 0, (len))
# define TestMagic(p, sz) (*((unsigned char*)(p)+sz) != MEM_MAGIC)
# define CheckMagic(p, s, where) \
if (TestMagic(p, s)) \
Fatal(where, "storage area overwritten");
# define CheckFreeSize(p, where) \
if (storage_size((p)) > TStorage::GetMaxBlockSize()) \
Fatal(where, "unreasonable size (%ld)", storage_size(p));
# define RemoveStatMagic(p, where) \
CheckFreeSize(p, where); \
RemoveStat(p); \
CheckMagic(p, storage_size(p), where)
# define StoreSizeMagic(p, size, where) \
StoreSize(p, size); \
StoreMagic(p, size); \
EnterStat(size, ExtStart(p)); \
CheckObjPtr(ExtStart(p), where);
#else
# define storage_size(p) ((size_t)0)
# define RealSize(sz) (sz)
# define RealStart(p) (p)
# define ExtStart(p) (p)
# define MemClear(p, start, len)
# define StoreSizeMagic(p, size, where) \
EnterStat(size, ExtStart(p)); \
CheckObjPtr(ExtStart(p), where);
# define RemoveStatMagic(p, where) \
RemoveStat(p);
#endif
#define MemClearRe(p, start, len) \
if ((len) > 0) memset(&((char*)(p))[(start)], 0, (len))
#define CallFreeHook(p, size) \
if (TStorage::GetFreeHook()) TStorage::GetFreeHook()(TStorage::GetFreeHookData(), (p), (size))
#ifdef MEM_CHECKOBJECTPOINTERS
//# define CheckObjPtr(p, name) gObjectTable->CheckPtrAndWarn((name), (p));
# define CheckObjPtr(p, name)
#else
# define CheckObjPtr(p, name)
#endif
//------------------------------------------------------------------------------
#ifdef MEM_STAT
#define EnterStat(s, p) \
TStorage::EnterStat(s, p)
#define RemoveStat(p) \
TStorage::RemoveStat(p)
#else
#define EnterStat(s, p) \
TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), s))
#define RemoveStat(p)
#endif
//------------------------------------------------------------------------------
#ifdef R__THROWNEWDELETE
# ifdef R__OLDHPACC
# define R__THROW_BAD throw(bad_alloc)
# else
# define R__THROW_BAD throw(std::bad_alloc)
#endif
#define R__THROW_NULL throw()
#else
#define R__THROW_BAD
#define R__THROW_NULL
#endif
static const char *gSpaceErr = "storage exhausted (failed to allocate %ld bytes)";
static int gNewInit = 0;
//______________________________________________________________________________
void *operator new(size_t size) R__THROW_BAD
{
// Custom new() operator.
// use memory checker
if (TROOT::MemCheck())
return TMemHashTable::AddPointer(size);
static const char *where = "operator new";
if (!gNewInit) {
TStorage::SetCustomNewDelete();
gNewInit++;
}
register void *vp;
if (gMmallocDesc)
vp = ::mcalloc(gMmallocDesc, RealSize(size), sizeof(char));
else
vp = ::calloc(RealSize(size), sizeof(char));
if (vp == 0)
Fatal(where, gSpaceErr, RealSize(size));
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
#ifndef R__PLACEMENTINLINE
//______________________________________________________________________________
void *operator new(size_t size, void *vp) R__THROW_NULL
{
// Custom new() operator with placement argument.
static const char *where = "operator new(void *at)";
if (!gNewInit) {
TStorage::SetCustomNewDelete();
gNewInit++;
}
if (vp == 0) {
// use memory checker
if (TROOT::MemCheck())
return TMemHashTable::AddPointer(size);
register void *vp;
if (gMmallocDesc)
vp = ::mcalloc(gMmallocDesc, RealSize(size), sizeof(char));
else
vp = ::calloc(RealSize(size), sizeof(char));
if (vp == 0)
Fatal(where, gSpaceErr, RealSize(size));
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
return vp;
}
#endif
//______________________________________________________________________________
void operator delete(void *ptr) R__THROW_NULL
{
// Custom delete() operator.
// use memory checker
if (TROOT::MemCheck()) {
TMemHashTable::FreePointer(ptr);
return;
}
static const char *where = "operator delete";
if (!gNewInit)
Fatal(where, "space was not allocated via custom new");
if (ptr) {
CheckObjPtr(ptr, where);
CallFreeHook(ptr, storage_size(ptr));
RemoveStatMagic(ptr, where);
MemClear(RealStart(ptr), 0, RealSize(storage_size(ptr)));
TSystem::ResetErrno();
TMapFile *mf = TMapFile::WhichMapFile(RealStart(ptr));
if (mf) {
if (mf->IsWritable()) ::mfree(mf->GetMmallocDesc(), RealStart(ptr));
} else {
do {
TSystem::ResetErrno();
::free(RealStart(ptr));
} while (TSystem::GetErrno() == EINTR);
}
if (TSystem::GetErrno() != 0)
SysError(where, "free");
}
}
#ifdef R__VECNEWDELETE
//______________________________________________________________________________
void *operator new[](size_t size) R__THROW_BAD
{
// Custom vector new operator.
return ::operator new(size);
}
#ifndef R__PLACEMENTINLINE
//______________________________________________________________________________
void *operator new[](size_t size, void *vp) R__THROW_NULL
{
// Custom vector new() operator with placement argument.
return ::operator new(size, vp);
}
#endif
//______________________________________________________________________________
void operator delete[](void *ptr) R__THROW_NULL
{
::operator delete(ptr);
}
#endif
//______________________________________________________________________________
void *CustomReAlloc1(void *ovp, size_t size)
{
// Reallocate (i.e. resize) block of memory.
// use memory checker
if (TROOT::MemCheck())
return TMemHashTable::AddPointer(size, ovp);
static const char *where = "CustomReAlloc1";
if (ovp == 0)
return ::operator new(size);
if (!gNewInit)
Fatal(where, "space was not allocated via custom new");
size_t oldsize = storage_size(ovp);
if (oldsize == size)
return ovp;
RemoveStatMagic(ovp, where);
void *vp;
if (gMmallocDesc)
vp = ::mrealloc(gMmallocDesc, RealStart(ovp), RealSize(size));
else
vp = ::realloc((char*)RealStart(ovp), RealSize(size));
if (vp == 0)
Fatal(where, gSpaceErr, RealSize(size));
if (size > oldsize)
MemClearRe(ExtStart(vp), oldsize, size-oldsize);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
//______________________________________________________________________________
void *CustomReAlloc2(void *ovp, size_t size, size_t oldsize)
{
// Reallocate (i.e. resize) block of memory. Checks if current size is
// equal to oldsize. If not memory was overwritten.
// use memory checker
if (TROOT::MemCheck())
return TMemHashTable::AddPointer(size, ovp);
static const char *where = "CustomReAlloc2";
if (ovp == 0)
return ::operator new(size);
if (!gNewInit)
Fatal(where, "space was not allocated via custom new");
#if defined(MEM_DEBUG)
if (oldsize != storage_size(ovp))
fprintf(stderr, "<%s>: passed oldsize %u, should be %u\n", where,
(unsigned int)oldsize, (unsigned int)storage_size(ovp));
#endif
if (oldsize == size)
return ovp;
RemoveStatMagic(ovp, where);
void *vp;
if (gMmallocDesc)
vp = ::mrealloc(gMmallocDesc, RealStart(ovp), RealSize(size));
else
vp = ::realloc((char*)RealStart(ovp), RealSize(size));
if (vp == 0)
Fatal(where, gSpaceErr, RealSize(size));
if (size > oldsize)
MemClearRe(ExtStart(vp), oldsize, size-oldsize);
StoreSizeMagic(vp, size, where);
return ExtStart(vp);
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...