Beispiel #1
0
//
// Z_ChangeTag
//
void (Z_ChangeTag)(void *ptr, int tag, __string file, int line)
{
   register memblock_t __near *block = VoidToBlock(ptr);

   DEBUG_CHECKHEAP();

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_ChangeTag: Changed a tag without ZONEID", block, file, line);

   Z_IDCheck(IDBOOL(tag >= PU_PURGELEVEL && !block->user),
             "Z_ChangeTag: an owner is required for purgable blocks",
             block, file, line);

#ifdef INSTRUMENTED
   if(block->tag < PU_PURGELEVEL && tag >= PU_PURGELEVEL)
   {
      active_memory -= block->size - block->extra;
      purgable_memory += block->size - block->extra;
   }
   else if(block->tag >= PU_PURGELEVEL && tag < PU_PURGELEVEL)
   {
      active_memory += block->size - block->extra;
      purgable_memory -= block->size - block->extra;
   }
#endif
   block->tag = tag;

   Z_LogPrintf("* Z_ChangeTag(p=%p, tag=%d, file=%s:%d)\n", ptr, tag, file, line);
}
Beispiel #2
0
//
// Z_Malloc
//
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
//
void *(Z_Malloc)(size_t size, int tag, void **user, const char *file, int line)
{
   memblock_t *block;
   byte *ret;

   DEBUG_CHECKHEAP();

   Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user),
               "Z_Malloc: an owner is required for purgable blocks", 
               file, line);

   if(!size)
      return user ? *user = NULL : NULL;          // malloc(0) returns NULL
   
   if(!(block = (memblock_t *)(malloc(size + header_size))))
   {
      if(blockbytag[PU_CACHE])
      {
         Z_FreeTags(PU_CACHE, PU_CACHE);
         block = (memblock_t *)(malloc(size + header_size));
      }
   }

   if(!block)
   {
      I_FatalError(I_ERR_KILL, "Z_Malloc: Failure trying to allocate %u bytes\n"
                               "Source: %s:%d\n", (unsigned int)size, file, line);
   }
   
   block->size = size;
   
   if((block->next = blockbytag[tag]))
      block->next->prev = &block->next;
   blockbytag[tag] = block;
   block->prev = &blockbytag[tag];
           
   INSTRUMENT(memorybytag[tag] += block->size);
   INSTRUMENT(block->file = file);
   INSTRUMENT(block->line = line);
         
   IDCHECK(block->id = ZONEID); // signature required in block header
   
   block->tag  = tag;           // tag
   block->user = user;          // user
   
   ret = ((byte *) block + header_size);
   if(user)                     // if there is a user
      *user = ret;              // set user to point to new block
   
   // scramble memory -- weed out any bugs
   SCRAMBLER(ret, size);

   Z_LogPrintf("* %p = Z_Malloc(size=%lu, tag=%d, user=%p, source=%s:%d)\n", 
               ret, size, tag, user, file, line);

   return ret;
}
Beispiel #3
0
//
// Z_CheckTag
//
// haleyjd: a function to return the allocation tag of a block.
// This is needed by W_CacheLumpNum so that it does not
// inadvertently lower the cache level of lump allocations and
// cause code which expects them to be static to lose them
//
int (Z_CheckTag)(void *ptr, const char *file, int line)
{
   memblock_t *block = (memblock_t *)((byte *) ptr - header_size);

   DEBUG_CHECKHEAP();

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_CheckTag: block doesn't have ZONEID", block, file, line);
   
   return block->tag;
}
Beispiel #4
0
//
// Z_CheckTag
//
// haleyjd: a function to return the allocation tag of a block.
// This is needed by W_CacheLumpNum so that it does not
// inadvertently lower the cache level of lump allocations and
// cause code which expects them to be static to lose them
//
int (Z_CheckTag)(void *ptr, __string file, int line)
{
   register memblock_t __near *block = VoidToBlock(ptr);

   DEBUG_CHECKHEAP();

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_CheckTag: block doesn't have ZONEID", block, file, line);

   return block->tag;
}
Beispiel #5
0
//
// Z_Free
//
void (Z_Free)(void *p, const char *file, int line)
{
   DEBUG_CHECKHEAP();

   if(p)
   {
      memblock_t *block = (memblock_t *)((byte *) p - header_size);

      Z_IDCheck(IDBOOL(block->id != ZONEID),
                "Z_Free: freed a pointer without ZONEID", block, file, line);

      // haleyjd: permanent blocks are never freed even if the code tries.
      if(block->tag == PU_PERMANENT)
         return;
      
      IDCHECK(block->id = 0); // Nullify id so another free fails

      // haleyjd 01/20/09: check invalid tags
      // catches double frees and possible selective heap corruption
      if(block->tag == PU_FREE || block->tag >= PU_MAX)
      {
         I_FatalError(I_ERR_KILL,
                      "Z_Free: freed a pointer with invalid tag %d\n"
                      "Source: %s:%d\n"
#if defined(ZONEVERBOSE) && defined(INSTRUMENTED)
                      "Source of malloc: %s:%d\n"
                      , block->tag, file, line, block->file, block->line
#else
                      , block->tag, file, line
#endif
                     );
      }
      INSTRUMENT(memorybytag[block->tag] -= block->size);
      block->tag = PU_FREE;       // Mark block freed

      // scramble memory -- weed out any bugs
      SCRAMBLER(p, block->size);

      if(block->user)            // Nullify user if one exists
         *block->user = NULL;

      if((*block->prev = block->next))
         block->next->prev = block->prev;
         
      free(block);
         
      Z_LogPrintf("* Z_Free(p=%p, file=%s:%d)\n", p, file, line);
   }
}
Beispiel #6
0
//
// Z_ChangeTag
//
void (Z_ChangeTag)(void *ptr, int tag, const char *file, int line)
{
   memblock_t *block;
   
   DEBUG_CHECKHEAP();
   
   if(!ptr)
   {
      I_FatalError(I_ERR_KILL, 
                   "Z_ChangeTag: can't change a NULL pointer at %s:%d\n",
                   file, line);
   }
   
   block = (memblock_t *)((byte *) ptr - header_size);

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_ChangeTag: Changed a tag without ZONEID", block, file, line);

   // haleyjd: permanent blocks are not re-tagged even if the code tries.
   if(block->tag == PU_PERMANENT)
      return;

   Z_IDCheck(IDBOOL(tag >= PU_PURGELEVEL && !block->user),
             "Z_ChangeTag: an owner is required for purgable blocks",
             block, file, line);

   if((*block->prev = block->next))
      block->next->prev = block->prev;
   if((block->next = blockbytag[tag]))
      block->next->prev = &block->next;
   block->prev = &blockbytag[tag];
   blockbytag[tag] = block;

   INSTRUMENT(memorybytag[block->tag] -= block->size);
   INSTRUMENT(memorybytag[tag] += block->size);

   block->tag = tag;

   Z_LogPrintf("* Z_ChangeTag(p=%p, tag=%d, file=%s:%d)\n",
               ptr, tag, file, line);
}
Beispiel #7
0
//
// Z_Realloc
//
// For the native heap, this can easily behave as a real realloc, and not
// just an ignorant copy-and-free.
//
void *(Z_Realloc)(void *ptr, size_t n, int tag, void **user,
                  const char *file, int line)
{
   void *p;
   memblock_t *block, *newblock, *origblock;

   // if not allocated at all, defer to Z_Malloc
   if(!ptr)
      return (Z_Malloc)(n, tag, user, file, line);

   // size == 0 is a special case that cannot be handled below
   if(n == 0)
   {
      (Z_Free)(ptr, file, line);
      return NULL;
   }

   DEBUG_CHECKHEAP();

   block = origblock = (memblock_t *)((byte *)ptr - header_size);

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_Realloc: Reallocated a block without ZONEID\n", 
             block, file, line);

   // haleyjd: realloc cannot change the tag of a permanent block
   if(block->tag == PU_PERMANENT)
      tag = PU_PERMANENT;

   // nullify current user, if any
   if(block->user)
      *(block->user) = NULL;

   // detach from list before reallocation
   if((*block->prev = block->next))
      block->next->prev = block->prev;

   block->next = NULL;
   block->prev = NULL;

   INSTRUMENT(memorybytag[block->tag] -= block->size);

   if(!(newblock = (memblock_t *)(realloc(block, n + header_size))))
   {
      // haleyjd 07/09/10: Note that unlinking the block above makes this safe 
      // even if the current block is PU_CACHE; Z_FreeTags won't find it.
      if(blockbytag[PU_CACHE])
      {
         Z_FreeTags(PU_CACHE, PU_CACHE);
         newblock = (memblock_t *)(realloc(block, n + header_size));
      }
   }

   if(!(block = newblock))
   {
      if(origblock->size >= n)
      {
         block = origblock; // restore original block if size was equal or smaller
         n = block->size;   // keep same size in this event
      }
      else
      {
         I_FatalError(I_ERR_KILL, "Z_Realloc: Failure trying to allocate %u bytes\n"
                                  "Source: %s:%d\n", (unsigned int)n, file, line);
      }
   }

   block->size = n;
   block->tag  = tag;

   p = (byte *)block + header_size;

   // set new user, if any
   block->user = user;
   if(user)
      *user = p;

   // reattach to list at possibly new address, new tag
   if((block->next = blockbytag[tag]))
      block->next->prev = &block->next;
   blockbytag[tag] = block;
   block->prev = &blockbytag[tag];

   INSTRUMENT(memorybytag[tag] += block->size);
   INSTRUMENT(block->file = file);
   INSTRUMENT(block->line = line);

   Z_LogPrintf("* %p = Z_Realloc(ptr=%p, n=%lu, tag=%d, user=%p, source=%s:%d)\n", 
               p, ptr, n, tag, user, file, line);

   return p;
}
Beispiel #8
0
//
// Z_Free
//
void (Z_Free)(void *p, __string file, int line)
{
   register memblock_t __near *other, *block;

   if(!p) return;

   DEBUG_CHECKHEAP();

   block = VoidToBlock(p);

   Z_IDCheck(IDBOOL(block->id != ZONEID),
             "Z_Free: freed a pointer without ZONEID", block, file, line);

   IDCHECK(block->id = 0); // Nullify id so another free fails

   // haleyjd 01/20/09: check invalid tags
   // catches double frees and possible selective heap corruption
   if(block->tag == PU_FREE || block->tag >= PU_MAX)
   {
      zonef("Z_Free: freed a pointer with invalid tag %d\nSource: %s:%d\n"
#ifdef INSTRUMENTED
            "Source of malloc: %s:%d\n"
            , block->tag, file, line, block->file, block->line
#else
            , block->tag, file, line
#endif
            );
      abort();
   }

   SCRAMBLER(p, block->size);

   if(block->user)            // Nullify user if one exists
      *block->user = NULL;

#ifdef INSTRUMENTED
   free_memory += block->size;
   inactive_memory -= block->extra;
   if(block->tag >= PU_PURGELEVEL)
      purgable_memory -= block->size - block->extra;
   else
      active_memory -= block->size - block->extra;
#endif

   block->tag = PU_FREE; // Mark block freed

   if(block != zone)
   {
      other = block->prev; // Possibly merge with previous block
      if(other->tag == PU_FREE)
      {
         if(rover == block)  // Move back rover if it points at block
            rover = other;
         (other->next = block->next)->prev = other;
         other->size += block->size + HEADER_SIZE;
         block = other;

         INSTRUMENT(inactive_memory -= HEADER_SIZE);
         INSTRUMENT(free_memory += HEADER_SIZE);
      }
   }

   other = block->next;        // Possibly merge with next block
   if(other->tag == PU_FREE && other != zone)
   {
      if(rover == other) // Move back rover if it points at next block
         rover = block;
      (block->next = other->next)->prev = block;
      block->size += other->size + HEADER_SIZE;

      INSTRUMENT(inactive_memory -= HEADER_SIZE);
      INSTRUMENT(free_memory += HEADER_SIZE);
   }

   Z_PrintStats(); // print memory allocation stats
   Z_LogPrintf("* Z_Free(p=%p, file=%s:%d)\n", p, file, line);
}
Beispiel #9
0
//
// Z_Malloc
//
// You can pass a NULL user if the tag is < PU_PURGELEVEL.
//
void *(Z_Malloc)(size_t size, int tag, void **user, __string file, int line)
{
   register memblock_t __near *block, *start;

   INSTRUMENT(register size_t size_orig = size);

   // davidph 12/10/12: If zone not initialized, do so now.
   if(!zone) (Z_Init)(file, line);

   DEBUG_CHECKHEAP();

   Z_IDCheckNB(IDBOOL(tag >= PU_PURGELEVEL && !user),
               "Z_Malloc: an owner is required for purgable blocks",
               file, line);

   if(!size)
      return user ? *user = NULL : NULL;          // malloc(0) returns NULL

   size = (size+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1);  // round to chunk size

   block = rover;

   if(block->prev->tag == PU_FREE)
      block = block->prev;

   start = block;

   // haleyjd 01/01/01 (happy new year!):
   // the first if() inside the loop below contains cph's memory
   // purging efficiency fix

   do
   {
      // Free purgable blocks; replacement is roughly FIFO
      if(block->tag >= PU_PURGELEVEL)
      {
         start = block->prev;
         Z_Free((char __near *)block + HEADER_SIZE);

         // cph - If start->next == block, we did not merge with the previous
         //       If !=, we did, so we continue from start.
         //  Important: we've reset start!
         if(start->next == block)
            start = start->next;
         else
            block = start;
      }

      if(block->tag == PU_FREE && block->size >= size)   // First-fit
      {
         size_t extra = block->size - size;
         if(extra >= MIN_BLOCK_SPLIT + HEADER_SIZE)
         {
            memblock_t __near *newb = (memblock_t __near *)((char __near *)block + HEADER_SIZE + size);

            (newb->next = block->next)->prev = newb;
            (newb->prev = block)->next = newb;          // Split up block
            block->size = size;
            newb->size = extra - HEADER_SIZE;
            newb->tag = PU_FREE;

            INSTRUMENT(inactive_memory += HEADER_SIZE);
            INSTRUMENT(free_memory -= HEADER_SIZE);
         }

         rover = block->next;           // set roving pointer for next search

#ifdef INSTRUMENTED
         inactive_memory += block->extra = block->size - size_orig;
         if(tag >= PU_PURGELEVEL)
            purgable_memory += size_orig;
         else
            active_memory += size_orig;
         free_memory -= block->size;
#endif

         INSTRUMENT(block->file = file);
         INSTRUMENT(block->line = line);

         IDCHECK(block->id = ZONEID);// signature required in block header
         block->tag = tag;           // tag
         block->user = user;         // user
         block = BlockToVoid(block);
         if(user)                    // if there is a user
            *user = block;           // set user to point to new block

         Z_PrintStats();             // print memory allocation stats

         // scramble memory -- weed out any bugs
         SCRAMBLER(block, size);

         Z_LogPrintf("* %p = Z_Malloc(size=%u, tag=%d, user=%p, source=%s:%d)\n",
                     block, size, tag, user, file, line);

         return block;
      }
   }
   while((block = block->next) != start);   // detect cycles as failure

   zonef("Z_Malloc: Failure trying to allocate %u bytes\nSource: %s:%d\n", size, file, line);
   abort();
}