NewDelete.cxx

Go to the documentation of this file.
00001 // @(#)root/new:$Id: NewDelete.cxx 34269 2010-07-01 09:54:58Z rdm $
00002 // Author: Fons Rademakers   29/07/95
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 //////////////////////////////////////////////////////////////////////////
00013 //                                                                      //
00014 // Custom operators new and delete and ReAlloc functions.               //
00015 //                                                                      //
00016 // All new and delete operations in the ROOT system pass                //
00017 // via the custom new and delete operators defined in this file.        //
00018 // This scheme allows extensive memory checking and usage statistics    //
00019 // gathering and an easy way to access shared memory segments.          //
00020 // Memory checking is by default enabled and usage statistics is        //
00021 // gathered. Using the resource (in .rootrc): Root.MemStat one can      //
00022 // toggle statistics gathering on or off. More specifically on can trap //
00023 // the allocation of a block of memory of a certain size. This can be   //
00024 // specified using the resource: Root.MemStat.size, using the resource  //
00025 // Root.MemStat.cnt one can specify after how many allocations of       //
00026 // this size the trap should occur.                                     //
00027 // Set the compile option R__NOSTATS to de-activate all memory checking //
00028 // statistics gathering in the system.                                  //
00029 //                                                                      //
00030 // When memory checking is enabled the following happens during         //
00031 // allocation:                                                          //
00032 //  - each allocation results in the allocation of 9 extra bytes:       //
00033 //    2 words in front and 1 byte at the end of the memory chunck       //
00034 //    returned to the caller.                                           //
00035 //  - the allocated memory is set to 0.                                 //
00036 //  - the size of the chunck is stored in the first word. The second    //
00037 //    word is left empty (for alignment).                               //
00038 //  - the last byte is initialized to MEM_MAGIC.                        //
00039 //                                                                      //
00040 // And during de-allocation this happens:                               //
00041 //  - first the size if the block is checked. It should be >0 and       //
00042 //    <= than any block allocated up to that moment. If not a Fatal     //
00043 //    error is generated.                                               //
00044 //  - the MEM_MAGIC byte at the end of the block is checked. When not   //
00045 //    there, the memory has been overwritten and a Fatal error is       //
00046 //    generated.                                                        //
00047 //  - memory block is reset to 0.                                       //
00048 //                                                                      //
00049 // Although this does not replace powerful tools like Purify, it is a   //
00050 // good first line of protection.                                       //
00051 //                                                                      //
00052 // Independent of any compile option settings the new, and ReAlloc      //
00053 // functions always set the memory to 0.                                //
00054 //                                                                      //
00055 // The powerful MEM_DEBUG and MEM_STAT macros were borrowed from        //
00056 // the ET++ framework.                                                  //
00057 //                                                                      //
00058 //////////////////////////////////////////////////////////////////////////
00059 
00060 #include <stdlib.h>
00061 #include <errno.h>
00062 
00063 #include "MemCheck.h"
00064 #include "TObjectTable.h"
00065 #include "TError.h"
00066 #include "TMapFile.h"
00067 #include "TSystem.h"
00068 #include "mmalloc.h"
00069 
00070 void *CustomReAlloc1(void *ovp, size_t size);
00071 void *CustomReAlloc2(void *ovp, size_t size, size_t oldsize);
00072 
00073 class TReAllocInit {
00074 public:
00075    TReAllocInit() { TStorage::SetReAllocHooks(&CustomReAlloc1, &CustomReAlloc2); }
00076 };
00077 static TReAllocInit gReallocInit;
00078 
00079 
00080 //---- memory checking macros --------------------------------------------------
00081 
00082 #if !defined(R__NOSTATS)
00083 #   define MEM_DEBUG
00084 #   define MEM_STAT
00085 #   define MEM_CHECKOBJECTPOINTERS
00086 #endif
00087 
00088 #if defined(MEM_STAT) && !defined(MEM_DEBUG)
00089 #   define MEM_DEBUG
00090 #endif
00091 
00092 #ifdef MEM_DEBUG
00093 #   define MEM_MAGIC ((unsigned char)0xAB)
00094 #ifdef R__B64
00095 #   define storage_size(p) ((size_t)(((size_t*)p)[-1]))
00096 #   define RealStart(p) ((char*)(p) - sizeof(size_t))
00097 #   define StoreSize(p, sz) (*((size_t*)(p)) = (sz))
00098 #   define ExtStart(p) ((char*)(p) + sizeof(size_t))
00099 #   define RealSize(sz) ((sz) + sizeof(size_t) + sizeof(char))
00100 #   define StoreMagic(p, sz) *((unsigned char*)(p)+sz+sizeof(size_t)) = MEM_MAGIC
00101 #else
00102 #   define storage_size(p) ((size_t)(((int*)p)[-2]))
00103 #   define RealStart(p) ((char*)(p) - 2*sizeof(int))
00104 #   define StoreSize(p, sz) (*((int*)(p)) = (sz))
00105 #   define ExtStart(p) ((char*)(p) + 2*sizeof(int))
00106 #   define RealSize(sz) ((sz) + 2*sizeof(int) + sizeof(char))
00107 #   define StoreMagic(p, sz) *((unsigned char*)(p)+sz+2*sizeof(int)) = MEM_MAGIC
00108 #endif
00109 #   define MemClear(p, start, len) \
00110       if ((len) > 0) memset(&((char*)(p))[(start)], 0, (len))
00111 #   define TestMagic(p, sz) (*((unsigned char*)(p)+sz) != MEM_MAGIC)
00112 #   define CheckMagic(p, s, where) \
00113       if (TestMagic(p, s))    \
00114          Fatal(where, "%s", "storage area overwritten");
00115 #   define CheckFreeSize(p, where) \
00116       if (storage_size((p)) > TStorage::GetMaxBlockSize()) \
00117          Fatal(where, "unreasonable size (%ld)", (Long_t)storage_size(p));
00118 #   define RemoveStatMagic(p, where) \
00119       CheckFreeSize(p, where); \
00120       RemoveStat(p); \
00121       CheckMagic(p, storage_size(p), where)
00122 #   define StoreSizeMagic(p, size, where) \
00123       StoreSize(p, size); \
00124       StoreMagic(p, size); \
00125       EnterStat(size, ExtStart(p)); \
00126       CheckObjPtr(ExtStart(p), where);
00127 #else
00128 #   define storage_size(p) ((size_t)0)
00129 #   define RealSize(sz) (sz)
00130 #   define RealStart(p) (p)
00131 #   define ExtStart(p) (p)
00132 #   define MemClear(p, start, len)
00133 #   define StoreSizeMagic(p, size, where) \
00134       EnterStat(size, ExtStart(p)); \
00135       CheckObjPtr(ExtStart(p), where);
00136 #   define RemoveStatMagic(p, where) \
00137       RemoveStat(p);
00138 #endif
00139 
00140 #define MemClearRe(p, start, len) \
00141    if ((len) > 0) memset(&((char*)(p))[(start)], 0, (len))
00142 
00143 #define CallFreeHook(p, size) \
00144    if (TStorage::GetFreeHook()) TStorage::GetFreeHook()(TStorage::GetFreeHookData(), (p), (size))
00145 
00146 #ifdef MEM_CHECKOBJECTPOINTERS
00147 //#   define CheckObjPtr(p, name) gObjectTable->CheckPtrAndWarn((name), (p));
00148 #   define CheckObjPtr(p, name)
00149 #else
00150 #   define CheckObjPtr(p, name)
00151 #endif
00152 
00153 //------------------------------------------------------------------------------
00154 #ifdef MEM_STAT
00155 
00156 #define EnterStat(s, p) \
00157    TStorage::EnterStat(s, p)
00158 #define RemoveStat(p) \
00159    TStorage::RemoveStat(p)
00160 
00161 #else
00162 
00163 #define EnterStat(s, p) \
00164    TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), s))
00165 #define RemoveStat(p)
00166 
00167 #endif
00168 
00169 //------------------------------------------------------------------------------
00170 
00171 #ifdef __GNUC__
00172 #   if !defined(R__THROWNEWDELETE) && __GNUC__ >= 3
00173 #      define R__THROWNEWDELETE
00174 #   endif
00175 #endif
00176 
00177 #ifdef R__THROWNEWDELETE
00178 #   ifdef R__OLDHPACC
00179 #      define R__THROW_BAD  throw(bad_alloc)
00180 #   else
00181 #      define R__THROW_BAD  throw(std::bad_alloc)
00182 #   endif
00183 #   define R__THROW_NULL throw()
00184 #else
00185 #   define R__THROW_BAD
00186 #   define R__THROW_NULL
00187 #endif
00188 
00189 static const char *gSpaceErr = "storage exhausted (failed to allocate %ld bytes)";
00190 static int gNewInit = 0;
00191 
00192 //______________________________________________________________________________
00193 void *operator new(size_t size) R__THROW_BAD
00194 {
00195    // Custom new() operator.
00196 
00197    // use memory checker
00198    if (TROOT::MemCheck())
00199       return TMemHashTable::AddPointer(size);
00200 
00201    static const char *where = "operator new";
00202 
00203    if (!gNewInit) {
00204       TStorage::SetCustomNewDelete();
00205       gNewInit++;
00206    }
00207 
00208    register void *vp;
00209    if (gMmallocDesc)
00210       vp = ::mcalloc(gMmallocDesc, RealSize(size), sizeof(char));
00211    else
00212       vp = ::calloc(RealSize(size), sizeof(char));
00213    if (vp == 0)
00214       Fatal(where, gSpaceErr, RealSize(size));
00215    StoreSizeMagic(vp, size, where);
00216    return ExtStart(vp);
00217 }
00218 
00219 #ifndef R__PLACEMENTINLINE
00220 //______________________________________________________________________________
00221 void *operator new(size_t size, void *vp) R__THROW_NULL
00222 {
00223    // Custom new() operator with placement argument.
00224 
00225    static const char *where = "operator new(void *at)";
00226 
00227    if (!gNewInit) {
00228       TStorage::SetCustomNewDelete();
00229       gNewInit++;
00230    }
00231 
00232    if (vp == 0) {
00233       // use memory checker
00234       if (TROOT::MemCheck())
00235          return TMemHashTable::AddPointer(size);
00236 
00237       register void *vp;
00238       if (gMmallocDesc)
00239          vp = ::mcalloc(gMmallocDesc, RealSize(size), sizeof(char));
00240       else
00241          vp = ::calloc(RealSize(size), sizeof(char));
00242       if (vp == 0)
00243          Fatal(where, gSpaceErr, RealSize(size));
00244       StoreSizeMagic(vp, size, where);
00245       return ExtStart(vp);
00246    }
00247    return vp;
00248 }
00249 #endif
00250 
00251 //______________________________________________________________________________
00252 void operator delete(void *ptr) R__THROW_NULL
00253 {
00254    // Custom delete() operator.
00255 
00256    // use memory checker
00257    if (TROOT::MemCheck()) {
00258       TMemHashTable::FreePointer(ptr);
00259       return;
00260    }
00261 
00262    static const char *where = "operator delete";
00263 
00264    if (!gNewInit)
00265       Fatal(where, "space was not allocated via custom new");
00266 
00267    if (ptr) {
00268       CheckObjPtr(ptr, where);
00269       CallFreeHook(ptr, storage_size(ptr));
00270       RemoveStatMagic(ptr, where);
00271       MemClear(RealStart(ptr), 0, RealSize(storage_size(ptr)));
00272       TSystem::ResetErrno();
00273       TMapFile *mf = TMapFile::WhichMapFile(RealStart(ptr));
00274       if (mf) {
00275          if (mf->IsWritable()) ::mfree(mf->GetMmallocDesc(), RealStart(ptr));
00276       } else {
00277          do {
00278             TSystem::ResetErrno();
00279             ::free(RealStart(ptr));
00280          } while (TSystem::GetErrno() == EINTR);
00281       }
00282       if (TSystem::GetErrno() != 0)
00283          SysError(where, "free");
00284    }
00285 }
00286 
00287 #ifdef R__VECNEWDELETE
00288 //______________________________________________________________________________
00289 void *operator new[](size_t size) R__THROW_BAD
00290 {
00291    // Custom vector new operator.
00292 
00293    return ::operator new(size);
00294 }
00295 
00296 #ifndef R__PLACEMENTINLINE
00297 //______________________________________________________________________________
00298 void *operator new[](size_t size, void *vp) R__THROW_NULL
00299 {
00300    // Custom vector new() operator with placement argument.
00301 
00302    return ::operator new(size, vp);
00303 }
00304 #endif
00305 
00306 //______________________________________________________________________________
00307 void operator delete[](void *ptr) R__THROW_NULL
00308 {
00309    ::operator delete(ptr);
00310 }
00311 #endif
00312 
00313 //______________________________________________________________________________
00314 void *CustomReAlloc1(void *ovp, size_t size)
00315 {
00316    // Reallocate (i.e. resize) block of memory.
00317 
00318    // use memory checker
00319    if (TROOT::MemCheck())
00320       return TMemHashTable::AddPointer(size, ovp);
00321 
00322    static const char *where = "CustomReAlloc1";
00323 
00324    if (ovp == 0)
00325       return ::operator new(size);
00326 
00327    if (!gNewInit)
00328       Fatal(where, "space was not allocated via custom new");
00329 
00330    size_t oldsize = storage_size(ovp);
00331    if (oldsize == size)
00332       return ovp;
00333    RemoveStatMagic(ovp, where);
00334    void *vp;
00335    if (gMmallocDesc)
00336       vp = ::mrealloc(gMmallocDesc, RealStart(ovp), RealSize(size));
00337    else
00338       vp = ::realloc((char*)RealStart(ovp), RealSize(size));
00339    if (vp == 0)
00340       Fatal(where, gSpaceErr, RealSize(size));
00341    if (size > oldsize)
00342       MemClearRe(ExtStart(vp), oldsize, size-oldsize);
00343 
00344    StoreSizeMagic(vp, size, where);
00345    return ExtStart(vp);
00346 }
00347 
00348 //______________________________________________________________________________
00349 void *CustomReAlloc2(void *ovp, size_t size, size_t oldsize)
00350 {
00351    // Reallocate (i.e. resize) block of memory. Checks if current size is
00352    // equal to oldsize. If not memory was overwritten.
00353 
00354    // use memory checker
00355    if (TROOT::MemCheck())
00356       return TMemHashTable::AddPointer(size, ovp);
00357 
00358    static const char *where = "CustomReAlloc2";
00359 
00360    if (ovp == 0)
00361       return ::operator new(size);
00362 
00363    if (!gNewInit)
00364       Fatal(where, "space was not allocated via custom new");
00365 
00366 #if defined(MEM_DEBUG)
00367    if (oldsize != storage_size(ovp))
00368       fprintf(stderr, "<%s>: passed oldsize %u, should be %u\n", where,
00369               (unsigned int)oldsize, (unsigned int)storage_size(ovp));
00370 #endif
00371    if (oldsize == size)
00372       return ovp;
00373    RemoveStatMagic(ovp, where);
00374    void *vp;
00375    if (gMmallocDesc)
00376       vp = ::mrealloc(gMmallocDesc, RealStart(ovp), RealSize(size));
00377    else
00378       vp = ::realloc((char*)RealStart(ovp), RealSize(size));
00379    if (vp == 0)
00380       Fatal(where, gSpaceErr, RealSize(size));
00381    if (size > oldsize)
00382       MemClearRe(ExtStart(vp), oldsize, size-oldsize);
00383 
00384    StoreSizeMagic(vp, size, where);
00385    return ExtStart(vp);
00386 }

Generated on Tue Jul 5 14:11:56 2011 for ROOT_528-00b_version by  doxygen 1.5.1