17ec681f3Smrg/**************************************************************************
27ec681f3Smrg *
37ec681f3Smrg * Copyright 2008 VMware, Inc.
47ec681f3Smrg * All Rights Reserved.
57ec681f3Smrg *
67ec681f3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77ec681f3Smrg * copy of this software and associated documentation files (the
87ec681f3Smrg * "Software"), to deal in the Software without restriction, including
97ec681f3Smrg * without limitation the rights to use, copy, modify, merge, publish,
107ec681f3Smrg * distribute, sub license, and/or sell copies of the Software, and to
117ec681f3Smrg * permit persons to whom the Software is furnished to do so, subject to
127ec681f3Smrg * the following conditions:
137ec681f3Smrg *
147ec681f3Smrg * The above copyright notice and this permission notice (including the
157ec681f3Smrg * next paragraph) shall be included in all copies or substantial portions
167ec681f3Smrg * of the Software.
177ec681f3Smrg *
187ec681f3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
197ec681f3Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
207ec681f3Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
217ec681f3Smrg * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
227ec681f3Smrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
237ec681f3Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
247ec681f3Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
257ec681f3Smrg *
267ec681f3Smrg **************************************************************************/
277ec681f3Smrg
287ec681f3Smrg/**
297ec681f3Smrg * @file
307ec681f3Smrg * Memory debugging.
317ec681f3Smrg *
327ec681f3Smrg * @author José Fonseca <jfonseca@vmware.com>
337ec681f3Smrg */
347ec681f3Smrg
357ec681f3Smrg#include "pipe/p_config.h"
367ec681f3Smrg
377ec681f3Smrg#define DEBUG_MEMORY_IMPLEMENTATION
387ec681f3Smrg
397ec681f3Smrg#include "os/os_thread.h"
407ec681f3Smrg
417ec681f3Smrg#include "util/u_debug.h"
427ec681f3Smrg#include "util/u_debug_stack.h"
437ec681f3Smrg#include "util/list.h"
447ec681f3Smrg#include "util/os_memory.h"
457ec681f3Smrg#include "util/os_memory_debug.h"
467ec681f3Smrg
477ec681f3Smrg
487ec681f3Smrg#define DEBUG_MEMORY_MAGIC 0x6e34090aU
497ec681f3Smrg#define DEBUG_MEMORY_STACK 0 /* XXX: disabled until we have symbol lookup */
507ec681f3Smrg
517ec681f3Smrg/**
527ec681f3Smrg * Set to 1 to enable checking of freed blocks of memory.
537ec681f3Smrg * Basically, don't really deallocate freed memory; keep it in the list
547ec681f3Smrg * but mark it as freed and do extra checking in debug_memory_check().
557ec681f3Smrg * This can detect some cases of use-after-free.  But note that since we
567ec681f3Smrg * never really free anything this will use a lot of memory.
577ec681f3Smrg */
587ec681f3Smrg#define DEBUG_FREED_MEMORY 0
597ec681f3Smrg#define DEBUG_FREED_BYTE 0x33
607ec681f3Smrg
617ec681f3Smrg
627ec681f3Smrgstruct debug_memory_header
637ec681f3Smrg{
647ec681f3Smrg   struct list_head head;
657ec681f3Smrg
667ec681f3Smrg   unsigned long no;
677ec681f3Smrg   const char *file;
687ec681f3Smrg   unsigned line;
697ec681f3Smrg   const char *function;
707ec681f3Smrg#if DEBUG_MEMORY_STACK
717ec681f3Smrg   struct debug_stack_frame backtrace[DEBUG_MEMORY_STACK];
727ec681f3Smrg#endif
737ec681f3Smrg   size_t size;
747ec681f3Smrg#if DEBUG_FREED_MEMORY
757ec681f3Smrg   boolean freed;  /**< Is this a freed block? */
767ec681f3Smrg#endif
777ec681f3Smrg
787ec681f3Smrg   unsigned magic;
797ec681f3Smrg   unsigned tag;
807ec681f3Smrg};
817ec681f3Smrg
827ec681f3Smrgstruct debug_memory_footer
837ec681f3Smrg{
847ec681f3Smrg   unsigned magic;
857ec681f3Smrg};
867ec681f3Smrg
877ec681f3Smrg
887ec681f3Smrgstatic struct list_head list = { &list, &list };
897ec681f3Smrg
907ec681f3Smrgstatic mtx_t list_mutex = _MTX_INITIALIZER_NP;
917ec681f3Smrg
927ec681f3Smrgstatic unsigned long last_no = 0;
937ec681f3Smrg
947ec681f3Smrg
957ec681f3Smrgstatic inline struct debug_memory_header *
967ec681f3Smrgheader_from_data(void *data)
977ec681f3Smrg{
987ec681f3Smrg   if (data)
997ec681f3Smrg      return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header));
1007ec681f3Smrg   else
1017ec681f3Smrg      return NULL;
1027ec681f3Smrg}
1037ec681f3Smrg
1047ec681f3Smrgstatic inline void *
1057ec681f3Smrgdata_from_header(struct debug_memory_header *hdr)
1067ec681f3Smrg{
1077ec681f3Smrg   if (hdr)
1087ec681f3Smrg      return (void *)((char *)hdr + sizeof(struct debug_memory_header));
1097ec681f3Smrg   else
1107ec681f3Smrg      return NULL;
1117ec681f3Smrg}
1127ec681f3Smrg
1137ec681f3Smrgstatic inline struct debug_memory_footer *
1147ec681f3Smrgfooter_from_header(struct debug_memory_header *hdr)
1157ec681f3Smrg{
1167ec681f3Smrg   if (hdr)
1177ec681f3Smrg      return (struct debug_memory_footer *)((char *)hdr + sizeof(struct debug_memory_header) + hdr->size);
1187ec681f3Smrg   else
1197ec681f3Smrg      return NULL;
1207ec681f3Smrg}
1217ec681f3Smrg
1227ec681f3Smrg
1237ec681f3Smrgvoid *
1247ec681f3Smrgdebug_malloc(const char *file, unsigned line, const char *function,
1257ec681f3Smrg             size_t size)
1267ec681f3Smrg{
1277ec681f3Smrg   struct debug_memory_header *hdr;
1287ec681f3Smrg   struct debug_memory_footer *ftr;
1297ec681f3Smrg
1307ec681f3Smrg   hdr = os_malloc(sizeof(*hdr) + size + sizeof(*ftr));
1317ec681f3Smrg   if (!hdr) {
1327ec681f3Smrg      debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
1337ec681f3Smrg                   file, line, function,
1347ec681f3Smrg                   (long unsigned)size);
1357ec681f3Smrg      return NULL;
1367ec681f3Smrg   }
1377ec681f3Smrg
1387ec681f3Smrg   hdr->no = last_no++;
1397ec681f3Smrg   hdr->file = file;
1407ec681f3Smrg   hdr->line = line;
1417ec681f3Smrg   hdr->function = function;
1427ec681f3Smrg   hdr->size = size;
1437ec681f3Smrg   hdr->magic = DEBUG_MEMORY_MAGIC;
1447ec681f3Smrg   hdr->tag = 0;
1457ec681f3Smrg#if DEBUG_FREED_MEMORY
1467ec681f3Smrg   hdr->freed = FALSE;
1477ec681f3Smrg#endif
1487ec681f3Smrg
1497ec681f3Smrg#if DEBUG_MEMORY_STACK
1507ec681f3Smrg   debug_backtrace_capture(hdr->backtrace, 0, DEBUG_MEMORY_STACK);
1517ec681f3Smrg#endif
1527ec681f3Smrg
1537ec681f3Smrg   ftr = footer_from_header(hdr);
1547ec681f3Smrg   ftr->magic = DEBUG_MEMORY_MAGIC;
1557ec681f3Smrg
1567ec681f3Smrg   mtx_lock(&list_mutex);
1577ec681f3Smrg   list_addtail(&hdr->head, &list);
1587ec681f3Smrg   mtx_unlock(&list_mutex);
1597ec681f3Smrg
1607ec681f3Smrg   return data_from_header(hdr);
1617ec681f3Smrg}
1627ec681f3Smrg
1637ec681f3Smrgvoid
1647ec681f3Smrgdebug_free(const char *file, unsigned line, const char *function,
1657ec681f3Smrg           void *ptr)
1667ec681f3Smrg{
1677ec681f3Smrg   struct debug_memory_header *hdr;
1687ec681f3Smrg   struct debug_memory_footer *ftr;
1697ec681f3Smrg
1707ec681f3Smrg   if (!ptr)
1717ec681f3Smrg      return;
1727ec681f3Smrg
1737ec681f3Smrg   hdr = header_from_data(ptr);
1747ec681f3Smrg   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
1757ec681f3Smrg      debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n",
1767ec681f3Smrg                   file, line, function,
1777ec681f3Smrg                   ptr);
1787ec681f3Smrg      debug_assert(0);
1797ec681f3Smrg      return;
1807ec681f3Smrg   }
1817ec681f3Smrg
1827ec681f3Smrg   ftr = footer_from_header(hdr);
1837ec681f3Smrg   if (ftr->magic != DEBUG_MEMORY_MAGIC) {
1847ec681f3Smrg      debug_printf("%s:%u:%s: buffer overflow %p\n",
1857ec681f3Smrg                   hdr->file, hdr->line, hdr->function,
1867ec681f3Smrg                   ptr);
1877ec681f3Smrg      debug_assert(0);
1887ec681f3Smrg   }
1897ec681f3Smrg
1907ec681f3Smrg#if DEBUG_FREED_MEMORY
1917ec681f3Smrg   /* Check for double-free */
1927ec681f3Smrg   assert(!hdr->freed);
1937ec681f3Smrg   /* Mark the block as freed but don't really free it */
1947ec681f3Smrg   hdr->freed = TRUE;
1957ec681f3Smrg   /* Save file/line where freed */
1967ec681f3Smrg   hdr->file = file;
1977ec681f3Smrg   hdr->line = line;
1987ec681f3Smrg   /* set freed memory to special value */
1997ec681f3Smrg   memset(ptr, DEBUG_FREED_BYTE, hdr->size);
2007ec681f3Smrg#else
2017ec681f3Smrg   mtx_lock(&list_mutex);
2027ec681f3Smrg   list_del(&hdr->head);
2037ec681f3Smrg   mtx_unlock(&list_mutex);
2047ec681f3Smrg   hdr->magic = 0;
2057ec681f3Smrg   ftr->magic = 0;
2067ec681f3Smrg
2077ec681f3Smrg   os_free(hdr);
2087ec681f3Smrg#endif
2097ec681f3Smrg}
2107ec681f3Smrg
2117ec681f3Smrgvoid *
2127ec681f3Smrgdebug_calloc(const char *file, unsigned line, const char *function,
2137ec681f3Smrg             size_t count, size_t size )
2147ec681f3Smrg{
2157ec681f3Smrg   void *ptr = debug_malloc( file, line, function, count * size );
2167ec681f3Smrg   if (ptr)
2177ec681f3Smrg      memset( ptr, 0, count * size );
2187ec681f3Smrg   return ptr;
2197ec681f3Smrg}
2207ec681f3Smrg
2217ec681f3Smrgvoid *
2227ec681f3Smrgdebug_realloc(const char *file, unsigned line, const char *function,
2237ec681f3Smrg              void *old_ptr, size_t old_size, size_t new_size )
2247ec681f3Smrg{
2257ec681f3Smrg   struct debug_memory_header *old_hdr, *new_hdr;
2267ec681f3Smrg   struct debug_memory_footer *old_ftr, *new_ftr;
2277ec681f3Smrg   void *new_ptr;
2287ec681f3Smrg
2297ec681f3Smrg   if (!old_ptr)
2307ec681f3Smrg      return debug_malloc( file, line, function, new_size );
2317ec681f3Smrg
2327ec681f3Smrg   if (!new_size) {
2337ec681f3Smrg      debug_free( file, line, function, old_ptr );
2347ec681f3Smrg      return NULL;
2357ec681f3Smrg   }
2367ec681f3Smrg
2377ec681f3Smrg   old_hdr = header_from_data(old_ptr);
2387ec681f3Smrg   if (old_hdr->magic != DEBUG_MEMORY_MAGIC) {
2397ec681f3Smrg      debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n",
2407ec681f3Smrg                   file, line, function,
2417ec681f3Smrg                   old_ptr);
2427ec681f3Smrg      debug_assert(0);
2437ec681f3Smrg      return NULL;
2447ec681f3Smrg   }
2457ec681f3Smrg
2467ec681f3Smrg   old_ftr = footer_from_header(old_hdr);
2477ec681f3Smrg   if (old_ftr->magic != DEBUG_MEMORY_MAGIC) {
2487ec681f3Smrg      debug_printf("%s:%u:%s: buffer overflow %p\n",
2497ec681f3Smrg                   old_hdr->file, old_hdr->line, old_hdr->function,
2507ec681f3Smrg                   old_ptr);
2517ec681f3Smrg      debug_assert(0);
2527ec681f3Smrg   }
2537ec681f3Smrg
2547ec681f3Smrg   /* alloc new */
2557ec681f3Smrg   new_hdr = os_malloc(sizeof(*new_hdr) + new_size + sizeof(*new_ftr));
2567ec681f3Smrg   if (!new_hdr) {
2577ec681f3Smrg      debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
2587ec681f3Smrg                   file, line, function,
2597ec681f3Smrg                   (long unsigned)new_size);
2607ec681f3Smrg      return NULL;
2617ec681f3Smrg   }
2627ec681f3Smrg   new_hdr->no = old_hdr->no;
2637ec681f3Smrg   new_hdr->file = old_hdr->file;
2647ec681f3Smrg   new_hdr->line = old_hdr->line;
2657ec681f3Smrg   new_hdr->function = old_hdr->function;
2667ec681f3Smrg   new_hdr->size = new_size;
2677ec681f3Smrg   new_hdr->magic = DEBUG_MEMORY_MAGIC;
2687ec681f3Smrg   new_hdr->tag = 0;
2697ec681f3Smrg#if DEBUG_FREED_MEMORY
2707ec681f3Smrg   new_hdr->freed = FALSE;
2717ec681f3Smrg#endif
2727ec681f3Smrg
2737ec681f3Smrg   new_ftr = footer_from_header(new_hdr);
2747ec681f3Smrg   new_ftr->magic = DEBUG_MEMORY_MAGIC;
2757ec681f3Smrg
2767ec681f3Smrg   mtx_lock(&list_mutex);
2777ec681f3Smrg   list_replace(&old_hdr->head, &new_hdr->head);
2787ec681f3Smrg   mtx_unlock(&list_mutex);
2797ec681f3Smrg
2807ec681f3Smrg   /* copy data */
2817ec681f3Smrg   new_ptr = data_from_header(new_hdr);
2827ec681f3Smrg   memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size );
2837ec681f3Smrg
2847ec681f3Smrg   /* free old */
2857ec681f3Smrg   old_hdr->magic = 0;
2867ec681f3Smrg   old_ftr->magic = 0;
2877ec681f3Smrg   os_free(old_hdr);
2887ec681f3Smrg
2897ec681f3Smrg   return new_ptr;
2907ec681f3Smrg}
2917ec681f3Smrg
2927ec681f3Smrgunsigned long
2937ec681f3Smrgdebug_memory_begin(void)
2947ec681f3Smrg{
2957ec681f3Smrg   return last_no;
2967ec681f3Smrg}
2977ec681f3Smrg
2987ec681f3Smrgvoid
2997ec681f3Smrgdebug_memory_end(unsigned long start_no)
3007ec681f3Smrg{
3017ec681f3Smrg   size_t total_size = 0;
3027ec681f3Smrg   struct list_head *entry;
3037ec681f3Smrg
3047ec681f3Smrg   if (start_no == last_no)
3057ec681f3Smrg      return;
3067ec681f3Smrg
3077ec681f3Smrg   entry = list.prev;
3087ec681f3Smrg   for (; entry != &list; entry = entry->prev) {
3097ec681f3Smrg      struct debug_memory_header *hdr;
3107ec681f3Smrg      void *ptr;
3117ec681f3Smrg      struct debug_memory_footer *ftr;
3127ec681f3Smrg
3137ec681f3Smrg      hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
3147ec681f3Smrg      ptr = data_from_header(hdr);
3157ec681f3Smrg      ftr = footer_from_header(hdr);
3167ec681f3Smrg
3177ec681f3Smrg      if (hdr->magic != DEBUG_MEMORY_MAGIC) {
3187ec681f3Smrg         debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
3197ec681f3Smrg                      hdr->file, hdr->line, hdr->function,
3207ec681f3Smrg                      ptr);
3217ec681f3Smrg         debug_assert(0);
3227ec681f3Smrg      }
3237ec681f3Smrg
3247ec681f3Smrg      if ((start_no <= hdr->no && hdr->no < last_no) ||
3257ec681f3Smrg          (last_no < start_no && (hdr->no < last_no || start_no <= hdr->no))) {
3267ec681f3Smrg         debug_printf("%s:%u:%s: %lu bytes at %p not freed\n",
3277ec681f3Smrg                      hdr->file, hdr->line, hdr->function,
3287ec681f3Smrg                      (unsigned long) hdr->size, ptr);
3297ec681f3Smrg#if DEBUG_MEMORY_STACK
3307ec681f3Smrg         debug_backtrace_dump(hdr->backtrace, DEBUG_MEMORY_STACK);
3317ec681f3Smrg#endif
3327ec681f3Smrg         total_size += hdr->size;
3337ec681f3Smrg      }
3347ec681f3Smrg
3357ec681f3Smrg      if (ftr->magic != DEBUG_MEMORY_MAGIC) {
3367ec681f3Smrg         debug_printf("%s:%u:%s: buffer overflow %p\n",
3377ec681f3Smrg                      hdr->file, hdr->line, hdr->function,
3387ec681f3Smrg                      ptr);
3397ec681f3Smrg         debug_assert(0);
3407ec681f3Smrg      }
3417ec681f3Smrg   }
3427ec681f3Smrg
3437ec681f3Smrg   if (total_size) {
3447ec681f3Smrg      debug_printf("Total of %lu KB of system memory apparently leaked\n",
3457ec681f3Smrg                   (unsigned long) (total_size + 1023)/1024);
3467ec681f3Smrg   }
3477ec681f3Smrg   else {
3487ec681f3Smrg      debug_printf("No memory leaks detected.\n");
3497ec681f3Smrg   }
3507ec681f3Smrg}
3517ec681f3Smrg
3527ec681f3Smrg
3537ec681f3Smrg/**
3547ec681f3Smrg * Put a tag (arbitrary integer) on a memory block.
3557ec681f3Smrg * Can be useful for debugging.
3567ec681f3Smrg */
3577ec681f3Smrgvoid
3587ec681f3Smrgdebug_memory_tag(void *ptr, unsigned tag)
3597ec681f3Smrg{
3607ec681f3Smrg   struct debug_memory_header *hdr;
3617ec681f3Smrg
3627ec681f3Smrg   if (!ptr)
3637ec681f3Smrg      return;
3647ec681f3Smrg
3657ec681f3Smrg   hdr = header_from_data(ptr);
3667ec681f3Smrg   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
3677ec681f3Smrg      debug_printf("%s corrupted memory at %p\n", __FUNCTION__, ptr);
3687ec681f3Smrg      debug_assert(0);
3697ec681f3Smrg   }
3707ec681f3Smrg
3717ec681f3Smrg   hdr->tag = tag;
3727ec681f3Smrg}
3737ec681f3Smrg
3747ec681f3Smrg
3757ec681f3Smrg/**
3767ec681f3Smrg * Check the given block of memory for validity/corruption.
3777ec681f3Smrg */
3787ec681f3Smrgvoid
3797ec681f3Smrgdebug_memory_check_block(void *ptr)
3807ec681f3Smrg{
3817ec681f3Smrg   struct debug_memory_header *hdr;
3827ec681f3Smrg   struct debug_memory_footer *ftr;
3837ec681f3Smrg
3847ec681f3Smrg   if (!ptr)
3857ec681f3Smrg      return;
3867ec681f3Smrg
3877ec681f3Smrg   hdr = header_from_data(ptr);
3887ec681f3Smrg   ftr = footer_from_header(hdr);
3897ec681f3Smrg
3907ec681f3Smrg   if (hdr->magic != DEBUG_MEMORY_MAGIC) {
3917ec681f3Smrg      debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
3927ec681f3Smrg                   hdr->file, hdr->line, hdr->function, ptr);
3937ec681f3Smrg      debug_assert(0);
3947ec681f3Smrg   }
3957ec681f3Smrg
3967ec681f3Smrg   if (ftr->magic != DEBUG_MEMORY_MAGIC) {
3977ec681f3Smrg      debug_printf("%s:%u:%s: buffer overflow %p\n",
3987ec681f3Smrg                   hdr->file, hdr->line, hdr->function, ptr);
3997ec681f3Smrg      debug_assert(0);
4007ec681f3Smrg   }
4017ec681f3Smrg}
4027ec681f3Smrg
4037ec681f3Smrg
4047ec681f3Smrg
4057ec681f3Smrg/**
4067ec681f3Smrg * We can periodically call this from elsewhere to do a basic sanity
4077ec681f3Smrg * check of the heap memory we've allocated.
4087ec681f3Smrg */
4097ec681f3Smrgvoid
4107ec681f3Smrgdebug_memory_check(void)
4117ec681f3Smrg{
4127ec681f3Smrg   struct list_head *entry;
4137ec681f3Smrg
4147ec681f3Smrg   entry = list.prev;
4157ec681f3Smrg   for (; entry != &list; entry = entry->prev) {
4167ec681f3Smrg      struct debug_memory_header *hdr;
4177ec681f3Smrg      struct debug_memory_footer *ftr;
4187ec681f3Smrg      const char *ptr;
4197ec681f3Smrg
4207ec681f3Smrg      hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
4217ec681f3Smrg      ftr = footer_from_header(hdr);
4227ec681f3Smrg      ptr = (const char *) data_from_header(hdr);
4237ec681f3Smrg
4247ec681f3Smrg      if (hdr->magic != DEBUG_MEMORY_MAGIC) {
4257ec681f3Smrg         debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
4267ec681f3Smrg                      hdr->file, hdr->line, hdr->function, ptr);
4277ec681f3Smrg         debug_assert(0);
4287ec681f3Smrg      }
4297ec681f3Smrg
4307ec681f3Smrg      if (ftr->magic != DEBUG_MEMORY_MAGIC) {
4317ec681f3Smrg         debug_printf("%s:%u:%s: buffer overflow %p\n",
4327ec681f3Smrg                      hdr->file, hdr->line, hdr->function, ptr);
4337ec681f3Smrg         debug_assert(0);
4347ec681f3Smrg      }
4357ec681f3Smrg
4367ec681f3Smrg#if DEBUG_FREED_MEMORY
4377ec681f3Smrg      /* If this block is marked as freed, check that it hasn't been touched */
4387ec681f3Smrg      if (hdr->freed) {
4397ec681f3Smrg         int i;
4407ec681f3Smrg         for (i = 0; i < hdr->size; i++) {
4417ec681f3Smrg            if (ptr[i] != DEBUG_FREED_BYTE) {
4427ec681f3Smrg               debug_printf("Memory error: byte %d of block at %p of size %d is 0x%x\n",
4437ec681f3Smrg                            i, ptr, hdr->size, ptr[i]);
4447ec681f3Smrg               debug_printf("Block was freed at %s:%d\n", hdr->file, hdr->line);
4457ec681f3Smrg            }
4467ec681f3Smrg            assert(ptr[i] == DEBUG_FREED_BYTE);
4477ec681f3Smrg         }
4487ec681f3Smrg      }
4497ec681f3Smrg#endif
4507ec681f3Smrg   }
4517ec681f3Smrg}
452