/* $Id: malloc.C,v 1.10 2006/02/15 01:07:00 dm Exp $ */ #include "amisc.h" #ifdef PYMALLOC # ifdef _POSIX_C_SOURCE # undef _POSIX_C_SOURCE # endif # include #endif /* PYMALLOC */ #ifdef DMALLOC bool dmalloc_init::initialized; void dmalloc_init::init () { if (suidsafe () < 0 && (getenv ("DMALLOC_OPTIONS") || getenv ("STKTRACE"))) { setgid (getgid ()); setuid (getuid ()); const char msg[] = "setuid disabled for malloc debugging\n"; write (2, msg, sizeof (msg) - 1); } initialized = true; } #endif /* DMALLOC */ /* The xmalloc handler will have no effect when dmalloc is used, but * we leave it in for compatibility. */ static void default_xmalloc_handler (int size) { const char msg[] = "malloc failed\n"; write (errfd, msg, sizeof (msg) - 1); myabort (); } void (*xmalloc_handler) (int) = default_xmalloc_handler; #ifdef DMALLOC #undef new dmalloc_t dmalloc; #ifndef CHECK_ARRAY_DELETE # define CHECK_ARRAY_DELETE 1 #endif /* !CHECK_ARRAY_DELETE */ #if CHECK_ARRAY_DELETE /* Want to catch array new followed by non-array delete */ enum { new_array_shift = 8 }; static char array_marker[new_array_shift] = { 0x79, 0x46, 0x55, 0x93, 0x12, 0x69, 0xaa, 0x7f }; #endif /* !CHECK_ARRAY_DELETE */ void * operator new (size_t size, dmalloc_t, const char *file, int line) { /* As per the C++ standard, allocating 0 bytes must not return NULL, * and must return a different pointer each time... */ if (!size) size = 1; return _xmalloc_leap (file, line, size); } void * operator new[] (size_t size, dmalloc_t, const char *file, int line) { #if CHECK_ARRAY_DELETE size = size + new_array_shift; #endif /* CHECK_ARRAY_DELETE */ if (!size) size = 1; #if CHECK_ARRAY_DELETE char *ret = static_cast (_xmalloc_leap (file, line, size)); memcpy (ret, array_marker, new_array_shift); return ret + new_array_shift; #else /* !CHECK_ARRAY_DELETE */ return _xmalloc_leap (file, line, size); #endif /* !CHECK_ARRAY_DELETE */ } void * operator new (size_t size, nothrow_t, const char *file, int line) throw () { if (!size) size = 1; return _malloc_leap (file, line, size); } void * operator new[] (size_t size, nothrow_t, const char *file, int line) throw () { #if CHECK_ARRAY_DELETE size = size + new_array_shift; #endif /* CHECK_ARRAY_DELETE */ if (!size) size = 1; #if CHECK_ARRAY_DELETE char *ret = static_cast (_xmalloc_leap (file, line, size)); memcpy (ret, array_marker, new_array_shift); return ret + new_array_shift; #else /* !CHECK_ARRAY_DELETE */ return _xmalloc_leap (file, line, size); #endif /* !CHECK_ARRAY_DELETE */ } #else /* !DMALLOC */ void * xmalloc (size_t size) { void *p; #ifdef PYMALLOC if (!(p = PyMem_Malloc (size))) #else /* ! PYMALLOC */ if (!(p = malloc (size))) #endif /* PYMALLOC */ default_xmalloc_handler (size); return p; } void * xrealloc (void *o, size_t size) { void *p; #ifdef PYMALLOC if (!(p = PyMem_Realloc (o, size))) #else /* ! PYMALLOC */ if (!(p = realloc (o, size))) #endif /* PYMALLOC */ default_xmalloc_handler (size); return p; } char * xstrdup (const char *s) { char *d; d = (char *) xmalloc (strlen (s) + 1); strcpy (d, s); return d; } #endif /* !DMALLOC */ using std::bad_alloc; using std::nothrow_t; void * operator new (size_t size) throw (bad_alloc) { if (!size) size = 1; return txmalloc (size); } void * operator new (size_t size, nothrow_t) throw () { if (!size) size = 1; #if PYMALLOC return PyMem_Malloc (size); #else /* !PYMALLOC */ return malloc (size); #endif } #ifndef delete_throw # define delete_throw throw() #endif /* !delete_throw */ #ifndef DMALLOC void operator delete (void *ptr) delete_throw { xfree (ptr); } void * operator new[] (size_t size) throw (bad_alloc) { if (!size) size = 1; return txmalloc (size); } void * operator new[] (size_t size, nothrow_t) throw () { if (!size) size = 1; #if PYMALLOC return PyMem_Malloc (size); #else /* !PYMALLOC */ return malloc (size); #endif } void operator delete[] (void *ptr) delete_throw { xfree (ptr); } #else /* DMALLOC */ #include struct hashptr { hashptr () {} hash_t operator() (const void *obj) const { return reinterpret_cast (obj); } }; struct objref { const void *obj; const char *refline; int *const flagp; ihash_entry hlink; objref (const void *o, const char *fl, int *fp); ~objref (); }; static ihash objreftab; inline objref::objref (const void *o, const char *fl, int *fp) : obj (o), refline (fl), flagp (fp) { objreftab.insert (this); } inline objref::~objref () { objreftab.remove (this); } int nodelete_ignore_count; static int do_nodelete_flag; inline bool do_nodelete () { return do_nodelete_flag > 0 && !nodelete_ignore_count && !globaldestruction && objreftab.constructed (); } void nodelete_addptr (const void *obj, const char *fl, int *fp) { if (!do_nodelete_flag) { u_long dmalloc_flags = dmalloc_debug_current (); do_nodelete_flag = (dmalloc_flags && 0x800) ? 1 : -1; } if (do_nodelete ()) vNew objref (obj, fl, fp); } void nodelete_remptr (const void *obj, const char *fl, int *fp) { if (do_nodelete ()) for (objref *oref = objreftab[obj]; oref; oref = objreftab.nextkeq (oref)) if (oref->refline == fl && oref->flagp == fp) { delete oref; return; } } inline void nodelete_check (const void *ptr) { if (do_nodelete ()) for (objref *oref = objreftab[ptr]; oref; oref = objreftab.nextkeq (oref)) { if (oref->flagp) (*oref->flagp)++; else panic ("deleting ptr %p still referenced from %s\n", ptr, oref->refline); } } void operator delete (void *ptr) delete_throw { nodelete_check (ptr); if (stktrace_record > 0) dmalloc_free (__backtrace (__FILE__, 2), __LINE__, ptr, DMALLOC_FUNC_FREE); else xfree (ptr); } void * operator new[] (size_t size) throw (bad_alloc) { #if CHECK_ARRAY_DELETE size = size + new_array_shift; #endif /* CHECK_ARRAY_DELETE */ if (!size) size = 1; #if CHECK_ARRAY_DELETE char *ret = static_cast (txmalloc (size)); memcpy (ret, array_marker, new_array_shift); return ret + new_array_shift; #else /* !CHECK_ARRAY_DELETE */ return txmalloc (size); #endif /* !CHECK_ARRAY_DELETE */ } void * operator new[] (size_t size, nothrow_t) throw () { #if CHECK_ARRAY_DELETE size = size + new_array_shift; #endif /* CHECK_ARRAY_DELETE */ if (!size) size = 1; #if CHECK_ARRAY_DELETE char *ret = static_cast (txmalloc (size)); memcpy (ret, array_marker, new_array_shift); return ret + new_array_shift; #else /* !CHECK_ARRAY_DELETE */ return txmalloc (size); #endif /* !CHECK_ARRAY_DELETE */ } void operator delete[] (void *_ptr) delete_throw { #if CHECK_ARRAY_DELETE char *ptr = static_cast (_ptr) - new_array_shift; if (memcmp (ptr, array_marker, new_array_shift)) { char msg[] = "non-array delete of array (or fencepost error)\n"; write (errfd, msg, sizeof (msg) - 1); } xfree (ptr); #else /* !CHECK_ARRAY_DELETE */ xfree (_ptr); #endif /* !CHECK_ARRAY_DELETE */ } #endif /* DMALLOC */