(linenum→info "unix/slp.c:2238")

glibc/2.7/malloc/hooks.c

    1: /* Malloc implementation for multiple threads without lock contention.
    2:    Copyright (C) 2001-2006, 2007 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
    5: 
    6:    The GNU C Library is free software; you can redistribute it and/or
    7:    modify it under the terms of the GNU Lesser General Public License as
    8:    published by the Free Software Foundation; either version 2.1 of the
    9:    License, or (at your option) any later version.
   10: 
   11:    The GNU C Library is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   14:    Lesser General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU Lesser General Public
   17:    License along with the GNU C Library; see the file COPYING.LIB.  If not,
   18:    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   19:    Boston, MA 02111-1307, USA.  */
   20: 
   21: /* What to do if the standard debugging hooks are in place and a
   22:    corrupt pointer is detected: do nothing (0), print an error message
   23:    (1), or call abort() (2). */
   24: 
   25: /* Hooks for debugging versions.  The initial hooks just call the
   26:    initialization routine, then do the normal work. */
   27: 
   28: static Void_t*
   29: #if __STD_C
   30: malloc_hook_ini(size_t sz, const __malloc_ptr_t caller)
   31: #else
   32: malloc_hook_ini(sz, caller)
   33:      size_t sz; const __malloc_ptr_t caller;
   34: #endif
   35: {
   36:   __malloc_hook = NULL;
   37:   ptmalloc_init();
   38:   return public_mALLOc(sz);
   39: }
   40: 
   41: static Void_t*
   42: #if __STD_C
   43: realloc_hook_ini(Void_t* ptr, size_t sz, const __malloc_ptr_t caller)
   44: #else
   45: realloc_hook_ini(ptr, sz, caller)
   46:      Void_t* ptr; size_t sz; const __malloc_ptr_t caller;
   47: #endif
   48: {
   49:   __malloc_hook = NULL;
   50:   __realloc_hook = NULL;
   51:   ptmalloc_init();
   52:   return public_rEALLOc(ptr, sz);
   53: }
   54: 
   55: static Void_t*
   56: #if __STD_C
   57: memalign_hook_ini(size_t alignment, size_t sz, const __malloc_ptr_t caller)
   58: #else
   59: memalign_hook_ini(alignment, sz, caller)
   60:      size_t alignment; size_t sz; const __malloc_ptr_t caller;
   61: #endif
   62: {
   63:   __memalign_hook = NULL;
   64:   ptmalloc_init();
   65:   return public_mEMALIGn(alignment, sz);
   66: }
   67: 
   68: /* Whether we are using malloc checking.  */
   69: static int using_malloc_checking;
   70: 
   71: /* A flag that is set by malloc_set_state, to signal that malloc checking
   72:    must not be enabled on the request from the user (via the MALLOC_CHECK_
   73:    environment variable).  It is reset by __malloc_check_init to tell
   74:    malloc_set_state that the user has requested malloc checking.
   75: 
   76:    The purpose of this flag is to make sure that malloc checking is not
   77:    enabled when the heap to be restored was constructed without malloc
   78:    checking, and thus does not contain the required magic bytes.
   79:    Otherwise the heap would be corrupted by calls to free and realloc.  If
   80:    it turns out that the heap was created with malloc checking and the
   81:    user has requested it malloc_set_state just calls __malloc_check_init
   82:    again to enable it.  On the other hand, reusing such a heap without
   83:    further malloc checking is safe.  */
   84: static int disallow_malloc_check;
   85: 
   86: /* Activate a standard set of debugging hooks. */
   87: void
   88: __malloc_check_init()
   89: {
   90:   if (disallow_malloc_check) {
   91:     disallow_malloc_check = 0;
   92:     return;
   93:   }
   94:   using_malloc_checking = 1;
   95:   __malloc_hook = malloc_check;
   96:   __free_hook = free_check;
   97:   __realloc_hook = realloc_check;
   98:   __memalign_hook = memalign_check;
   99:   if(check_action & 1)
  100:     malloc_printerr (5, "malloc: using debugging hooks", NULL);
  101: }
  102: 
  103: /* A simple, standard set of debugging hooks.  Overhead is `only' one
  104:    byte per chunk; still this will catch most cases of double frees or
  105:    overruns.  The goal here is to avoid obscure crashes due to invalid
  106:    usage, unlike in the MALLOC_DEBUG code. */
  107: 
  108: #define MAGICBYTE(p) ( ( ((size_t)p >> 3) ^ ((size_t)p >> 11)) & 0xFF )
  109: 
  110: /* Instrument a chunk with overrun detector byte(s) and convert it
  111:    into a user pointer with requested size sz. */
  112: 
  113: static Void_t*
  114: internal_function
  115: #if __STD_C
  116: mem2mem_check(Void_t *ptr, size_t sz)
  117: #else
  118: mem2mem_check(ptr, sz) Void_t *ptr; size_t sz;
  119: #endif
  120: {
  121:   mchunkptr p;
  122:   unsigned char* m_ptr = (unsigned char*)BOUNDED_N(ptr, sz);
  123:   size_t i;
  124: 
  125:   if (!ptr)
  126:     return ptr;
  127:   p = mem2chunk(ptr);
  128:   for(i = chunksize(p) - (chunk_is_mmapped(p) ? 2*SIZE_SZ+1 : SIZE_SZ+1);
  129:       i > sz;
  130:       i -= 0xFF) {
  131:     if(i-sz < 0x100) {
  132:       m_ptr[i] = (unsigned char)(i-sz);
  133:       break;
  134:     }
  135:     m_ptr[i] = 0xFF;
  136:   }
  137:   m_ptr[sz] = MAGICBYTE(p);
  138:   return (Void_t*)m_ptr;
  139: }
  140: 
  141: /* Convert a pointer to be free()d or realloc()ed to a valid chunk
  142:    pointer.  If the provided pointer is not valid, return NULL. */
  143: 
  144: static mchunkptr
  145: internal_function
  146: #if __STD_C
  147: mem2chunk_check(Void_t* mem, unsigned char **magic_p)
  148: #else
  149: mem2chunk_check(mem, magic_p) Void_t* mem; unsigned char **magic_p;
  150: #endif
  151: {
  152:   mchunkptr p;
  153:   INTERNAL_SIZE_T sz, c;
  154:   unsigned char magic;
  155: 
  156:   if(!aligned_OK(mem)) return NULL;
  157:   p = mem2chunk(mem);
  158:   if (!chunk_is_mmapped(p)) {
  159:     /* Must be a chunk in conventional heap memory. */
  160:     int contig = contiguous(&main_arena);
  161:     sz = chunksize(p);
  162:     if((contig &&
  163:         ((char*)p<mp_.sbrk_base ||
  164:          ((char*)p + sz)>=(mp_.sbrk_base+main_arena.system_mem) )) ||
  165:        sz<MINSIZE || sz&MALLOC_ALIGN_MASK || !inuse(p) ||
  166:        ( !prev_inuse(p) && (p->prev_size&MALLOC_ALIGN_MASK ||
  167:                             (contig && (char*)prev_chunk(p)<mp_.sbrk_base) ||
  168:                             next_chunk(prev_chunk(p))!=p) ))
  169:       return NULL;
  170:     magic = MAGICBYTE(p);
  171:     for(sz += SIZE_SZ-1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
  172:       if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
  173:     }
  174:   } else {
  175:     unsigned long offset, page_mask = malloc_getpagesize-1;
  176: 
  177:     /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
  178:        alignment relative to the beginning of a page.  Check this
  179:        first. */
  180:     offset = (unsigned long)mem & page_mask;
  181:     if((offset!=MALLOC_ALIGNMENT && offset!=0 && offset!=0x10 &&
  182:         offset!=0x20 && offset!=0x40 && offset!=0x80 && offset!=0x100 &&
  183:         offset!=0x200 && offset!=0x400 && offset!=0x800 && offset!=0x1000 &&
  184:         offset<0x2000) ||
  185:        !chunk_is_mmapped(p) || (p->size & PREV_INUSE) ||
  186:        ( (((unsigned long)p - p->prev_size) & page_mask) != 0 ) ||
  187:        ( (sz = chunksize(p)), ((p->prev_size + sz) & page_mask) != 0 ) )
  188:       return NULL;
  189:     magic = MAGICBYTE(p);
  190:     for(sz -= 1; (c = ((unsigned char*)p)[sz]) != magic; sz -= c) {
  191:       if(c<=0 || sz<(c+2*SIZE_SZ)) return NULL;
  192:     }
  193:   }
  194:   ((unsigned char*)p)[sz] ^= 0xFF;
  195:   if (magic_p)
  196:     *magic_p = (unsigned char *)p + sz;
  197:   return p;
  198: }
  199: 
  200: /* Check for corruption of the top chunk, and try to recover if
  201:    necessary. */
  202: 
  203: static int
  204: internal_function
  205: #if __STD_C
  206: top_check(void)
  207: #else
  208: top_check()
  209: #endif
  210: {
  211:   mchunkptr t = top(&main_arena);
  212:   char* brk, * new_brk;
  213:   INTERNAL_SIZE_T front_misalign, sbrk_size;
  214:   unsigned long pagesz = malloc_getpagesize;
  215: 
  216:   if (t == initial_top(&main_arena) ||
  217:       (!chunk_is_mmapped(t) &&
  218:        chunksize(t)>=MINSIZE &&
  219:        prev_inuse(t) &&
  220:        (!contiguous(&main_arena) ||
  221:         (char*)t + chunksize(t) == mp_.sbrk_base + main_arena.system_mem)))
  222:     return 0;
  223: 
  224:   malloc_printerr (check_action, "malloc: top chunk is corrupt", t);
  225: 
  226:   /* Try to set up a new top chunk. */
  227:   brk = MORECORE(0);
  228:   front_misalign = (unsigned long)chunk2mem(brk) & MALLOC_ALIGN_MASK;
  229:   if (front_misalign > 0)
  230:     front_misalign = MALLOC_ALIGNMENT - front_misalign;
  231:   sbrk_size = front_misalign + mp_.top_pad + MINSIZE;
  232:   sbrk_size += pagesz - ((unsigned long)(brk + sbrk_size) & (pagesz - 1));
  233:   new_brk = (char*)(MORECORE (sbrk_size));
  234:   if (new_brk == (char*)(MORECORE_FAILURE))
  235:     {
  236:       MALLOC_FAILURE_ACTION;
  237:       return -1;
  238:     }
  239:   /* Call the `morecore' hook if necessary.  */
  240:   if (__after_morecore_hook)
  241:     (*__after_morecore_hook) ();
  242:   main_arena.system_mem = (new_brk - mp_.sbrk_base) + sbrk_size;
  243: 
  244:   top(&main_arena) = (mchunkptr)(brk + front_misalign);
  245:   set_head(top(&main_arena), (sbrk_size - front_misalign) | PREV_INUSE);
  246: 
  247:   return 0;
  248: }
  249: 
  250: static Void_t*
  251: #if __STD_C
  252: malloc_check(size_t sz, const Void_t *caller)
  253: #else
  254: malloc_check(sz, caller) size_t sz; const Void_t *caller;
  255: #endif
  256: {
  257:   Void_t *victim;
  258: 
  259:   if (sz+1 == 0) {
  260:     MALLOC_FAILURE_ACTION;
  261:     return NULL;
  262:   }
  263: 
  264:   (void)mutex_lock(&main_arena.mutex);
  265:   victim = (top_check() >= 0) ? _int_malloc(&main_arena, sz+1) : NULL;
  266:   (void)mutex_unlock(&main_arena.mutex);
  267:   return mem2mem_check(victim, sz);
  268: }
  269: 
  270: static void
  271: #if __STD_C
  272: free_check(Void_t* mem, const Void_t *caller)
  273: #else
  274: free_check(mem, caller) Void_t* mem; const Void_t *caller;
  275: #endif
  276: {
  277:   mchunkptr p;
  278: 
  279:   if(!mem) return;
  280:   (void)mutex_lock(&main_arena.mutex);
  281:   p = mem2chunk_check(mem, NULL);
  282:   if(!p) {
  283:     (void)mutex_unlock(&main_arena.mutex);
  284: 
  285:     malloc_printerr(check_action, "free(): invalid pointer", mem);
  286:     return;
  287:   }
  288: #if HAVE_MMAP
  289:   if (chunk_is_mmapped(p)) {
  290:     (void)mutex_unlock(&main_arena.mutex);
  291:     munmap_chunk(p);
  292:     return;
  293:   }
  294: #endif
  295: #if 0 /* Erase freed memory. */
  296:   memset(mem, 0, chunksize(p) - (SIZE_SZ+1));
  297: #endif
  298:   _int_free(&main_arena, mem);
  299:   (void)mutex_unlock(&main_arena.mutex);
  300: }
  301: 
  302: static Void_t*
  303: #if __STD_C
  304: realloc_check(Void_t* oldmem, size_t bytes, const Void_t *caller)
  305: #else
  306: realloc_check(oldmem, bytes, caller)
  307:      Void_t* oldmem; size_t bytes; const Void_t *caller;
  308: #endif
  309: {
  310:   mchunkptr oldp;
  311:   INTERNAL_SIZE_T nb, oldsize;
  312:   Void_t* newmem = 0;
  313:   unsigned char *magic_p;
  314: 
  315:   if (bytes+1 == 0) {
  316:     MALLOC_FAILURE_ACTION;
  317:     return NULL;
  318:   }
  319:   if (oldmem == 0) return malloc_check(bytes, NULL);
  320:   if (bytes == 0) {
  321:     free_check (oldmem, NULL);
  322:     return NULL;
  323:   }
  324:   (void)mutex_lock(&main_arena.mutex);
  325:   oldp = mem2chunk_check(oldmem, &magic_p);
  326:   (void)mutex_unlock(&main_arena.mutex);
  327:   if(!oldp) {
  328:     malloc_printerr(check_action, "realloc(): invalid pointer", oldmem);
  329:     return malloc_check(bytes, NULL);
  330:   }
  331:   oldsize = chunksize(oldp);
  332: 
  333:   checked_request2size(bytes+1, nb);
  334:   (void)mutex_lock(&main_arena.mutex);
  335: 
  336: #if HAVE_MMAP
  337:   if (chunk_is_mmapped(oldp)) {
  338: #if HAVE_MREMAP
  339:     mchunkptr newp = mremap_chunk(oldp, nb);
  340:     if(newp)
  341:       newmem = chunk2mem(newp);
  342:     else
  343: #endif
  344:     {
  345:       /* Note the extra SIZE_SZ overhead. */
  346:       if(oldsize - SIZE_SZ >= nb)
  347:         newmem = oldmem; /* do nothing */
  348:       else {
  349:         /* Must alloc, copy, free. */
  350:         if (top_check() >= 0)
  351:           newmem = _int_malloc(&main_arena, bytes+1);
  352:         if (newmem) {
  353:           MALLOC_COPY(BOUNDED_N(newmem, bytes+1), oldmem, oldsize - 2*SIZE_SZ);
  354:           munmap_chunk(oldp);
  355:         }
  356:       }
  357:     }
  358:   } else {
  359: #endif /* HAVE_MMAP */
  360:     if (top_check() >= 0)
  361:       newmem = _int_realloc(&main_arena, oldmem, bytes+1);
  362: #if 0 /* Erase freed memory. */
  363:     if(newmem)
  364:       newp = mem2chunk(newmem);
  365:     nb = chunksize(newp);
  366:     if(oldp<newp || oldp>=chunk_at_offset(newp, nb)) {
  367:       memset((char*)oldmem + 2*sizeof(mbinptr), 0,
  368:              oldsize - (2*sizeof(mbinptr)+2*SIZE_SZ+1));
  369:     } else if(nb > oldsize+SIZE_SZ) {
  370:       memset((char*)BOUNDED_N(chunk2mem(newp), bytes) + oldsize,
  371:              0, nb - (oldsize+SIZE_SZ));
  372:     }
  373: #endif
  374: #if HAVE_MMAP
  375:   }
  376: #endif
  377: 
  378:   /* mem2chunk_check changed the magic byte in the old chunk.
  379:      If newmem is NULL, then the old chunk will still be used though,
  380:      so we need to invert that change here.  */
  381:   if (newmem == NULL) *magic_p ^= 0xFF;
  382: 
  383:   (void)mutex_unlock(&main_arena.mutex);
  384: 
  385:   return mem2mem_check(newmem, bytes);
  386: }
  387: 
  388: static Void_t*
  389: #if __STD_C
  390: memalign_check(size_t alignment, size_t bytes, const Void_t *caller)
  391: #else
  392: memalign_check(alignment, bytes, caller)
  393:      size_t alignment; size_t bytes; const Void_t *caller;
  394: #endif
  395: {
  396:   INTERNAL_SIZE_T nb;
  397:   Void_t* mem;
  398: 
  399:   if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL);
  400:   if (alignment <  MINSIZE) alignment = MINSIZE;
  401: 
  402:   if (bytes+1 == 0) {
  403:     MALLOC_FAILURE_ACTION;
  404:     return NULL;
  405:   }
  406:   checked_request2size(bytes+1, nb);
  407:   (void)mutex_lock(&main_arena.mutex);
  408:   mem = (top_check() >= 0) ? _int_memalign(&main_arena, alignment, bytes+1) :
  409:     NULL;
  410:   (void)mutex_unlock(&main_arena.mutex);
  411:   return mem2mem_check(mem, bytes);
  412: }
  413: 
  414: #ifndef NO_THREADS
  415: 
  416: # ifdef _LIBC
  417: #  if USE___THREAD || !defined SHARED
  418:     /* These routines are never needed in this configuration.  */
  419: #   define NO_STARTER
  420: #  endif
  421: # endif
  422: 
  423: # ifdef NO_STARTER
  424: #  undef NO_STARTER
  425: # else
  426: 
  427: /* The following hooks are used when the global initialization in
  428:    ptmalloc_init() hasn't completed yet. */
  429: 
  430: static Void_t*
  431: #if __STD_C
  432: malloc_starter(size_t sz, const Void_t *caller)
  433: #else
  434: malloc_starter(sz, caller) size_t sz; const Void_t *caller;
  435: #endif
  436: {
  437:   Void_t* victim;
  438: 
  439:   victim = _int_malloc(&main_arena, sz);
  440: 
  441:   return victim ? BOUNDED_N(victim, sz) : 0;
  442: }
  443: 
  444: static Void_t*
  445: #if __STD_C
  446: memalign_starter(size_t align, size_t sz, const Void_t *caller)
  447: #else
  448: memalign_starter(align, sz, caller) size_t align, sz; const Void_t *caller;
  449: #endif
  450: {
  451:   Void_t* victim;
  452: 
  453:   victim = _int_memalign(&main_arena, align, sz);
  454: 
  455:   return victim ? BOUNDED_N(victim, sz) : 0;
  456: }
  457: 
  458: static void
  459: #if __STD_C
  460: free_starter(Void_t* mem, const Void_t *caller)
  461: #else
  462: free_starter(mem, caller) Void_t* mem; const Void_t *caller;
  463: #endif
  464: {
  465:   mchunkptr p;
  466: 
  467:   if(!mem) return;
  468:   p = mem2chunk(mem);
  469: #if HAVE_MMAP
  470:   if (chunk_is_mmapped(p)) {
  471:     munmap_chunk(p);
  472:     return;
  473:   }
  474: #endif
  475:   _int_free(&main_arena, mem);
  476: }
  477: 
  478: # endif /* !defiend NO_STARTER */
  479: #endif /* NO_THREADS */
  480: 
  481: 
  482: /* Get/set state: malloc_get_state() records the current state of all
  483:    malloc variables (_except_ for the actual heap contents and `hook'
  484:    function pointers) in a system dependent, opaque data structure.
  485:    This data structure is dynamically allocated and can be free()d
  486:    after use.  malloc_set_state() restores the state of all malloc
  487:    variables to the previously obtained state.  This is especially
  488:    useful when using this malloc as part of a shared library, and when
  489:    the heap contents are saved/restored via some other method.  The
  490:    primary example for this is GNU Emacs with its `dumping' procedure.
  491:    `Hook' function pointers are never saved or restored by these
  492:    functions, with two exceptions: If malloc checking was in use when
  493:    malloc_get_state() was called, then malloc_set_state() calls
  494:    __malloc_check_init() if possible; if malloc checking was not in
  495:    use in the recorded state but the user requested malloc checking,
  496:    then the hooks are reset to 0.  */
  497: 
  498: #define MALLOC_STATE_MAGIC   0x444c4541l
  499: #define MALLOC_STATE_VERSION (0*0x100l + 3l) /* major*0x100 + minor */
  500: 
  501: struct malloc_save_state {
  502:   long          magic;
  503:   long          version;
  504:   mbinptr       av[NBINS * 2 + 2];
  505:   char*         sbrk_base;
  506:   int           sbrked_mem_bytes;
  507:   unsigned long trim_threshold;
  508:   unsigned long top_pad;
  509:   unsigned int  n_mmaps_max;
  510:   unsigned long mmap_threshold;
  511:   int           check_action;
  512:   unsigned long max_sbrked_mem;
  513:   unsigned long max_total_mem;
  514:   unsigned int  n_mmaps;
  515:   unsigned int  max_n_mmaps;
  516:   unsigned long mmapped_mem;
  517:   unsigned long max_mmapped_mem;
  518:   int           using_malloc_checking;
  519: };
  520: 
  521: Void_t*
  522: public_gET_STATe(void)
  523: {
  524:   struct malloc_save_state* ms;
  525:   int i;
  526:   mbinptr b;
  527: 
  528:   ms = (struct malloc_save_state*)public_mALLOc(sizeof(*ms));
  529:   if (!ms)
  530:     return 0;
  531:   (void)mutex_lock(&main_arena.mutex);
  532:   malloc_consolidate(&main_arena);
  533:   ms->magic = MALLOC_STATE_MAGIC;
  534:   ms->version = MALLOC_STATE_VERSION;
  535:   ms->av[0] = 0;
  536:   ms->av[1] = 0; /* used to be binblocks, now no longer used */
  537:   ms->av[2] = top(&main_arena);
  538:   ms->av[3] = 0; /* used to be undefined */
  539:   for(i=1; i<NBINS; i++) {
  540:     b = bin_at(&main_arena, i);
  541:     if(first(b) == b)
  542:       ms->av[2*i+2] = ms->av[2*i+3] = 0; /* empty bin */
  543:     else {
  544:       ms->av[2*i+2] = first(b);
  545:       ms->av[2*i+3] = last(b);
  546:     }
  547:   }
  548:   ms->sbrk_base = mp_.sbrk_base;
  549:   ms->sbrked_mem_bytes = main_arena.system_mem;
  550:   ms->trim_threshold = mp_.trim_threshold;
  551:   ms->top_pad = mp_.top_pad;
  552:   ms->n_mmaps_max = mp_.n_mmaps_max;
  553:   ms->mmap_threshold = mp_.mmap_threshold;
  554:   ms->check_action = check_action;
  555:   ms->max_sbrked_mem = main_arena.max_system_mem;