www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1995/10/16/03:52:42

From: John Carter <ECE AT dwaf-hri DOT pwv DOT gov DOT za>
Organization: Dpt Water Affairs & Forestry (IWQS)
To: djgpp AT sun DOT soe DOT clarkson DOT edu
Date: Mon, 16 Oct 1995 08:54:14 +0200
Subject: Re: realloc-free question

>When realloc returns NULL, it really frees the memory block that the
>pointer originally had? The knowledge of the right answer is very 
>important for the memory management in C.
The answer is probably No. Why, because what does realloc do?
1) if requested size <= actual size of allocated block then
      return same block. //Note that actual size of allocated block 
                         //is only gauranteed to be greater than or 
                         //equal to original requested size.
2) temp = malloc( requested size)
3) if !temp return null // Haven't freed old block yet.
4) move data from old block to new block.
5) free old block
6) return temp                         

>********************
>If the answer is YES,
>********************
>
>The following code, compiled with DJGPP should produce a protection
>fault, but it does not (it seems to run perfectly)
But even if the answer was yes, C is a hostile place.
You stuff up, C gives you no protection, not even an error message.
It will let you scribble over a freed block quite happily. Note that 
free'ing a block doesn't deallocate that virtual memory. Malloc 
usually holds on to it on the basis that you will want some more 
memory later... This is probably bad news in a multitasking 
environment but that is what we have large swap files for. Note that 
free has a pass by value parameter. There is no way free() can set 
the pointer passed to zero. (Wouldn't really help anyway, there are 
too many ways to get around such a protection)

>********************
>If the answer is NO,
>********************
>it seems to me a problem with the C language, because there is no way to
>free this memory block unless you save the original pointer. 
Not the first and certainly not the last problem.

Hokay the way to answer this is to grab the source code for malloc.c
and have a look.

Here is realloc from \src\libgplus\src\malloc.c...
-----------------------------------------------------------
void* realloc(void* mem, size_t bytes)
{
  if (mem == 0) 
    return malloc(bytes);
  else
  {
    size_t       nb      = request2size(bytes);
    mchunkptr    p       = mem2chunk(mem);
    size_t       oldsize;
    long         room;
    mchunkptr    nxt;

    if (p == returned_list) /* support realloc-last-freed-chunk 
idiocy */
       returned_list = returned_list->fd;

    clear_inuse(p);
    oldsize = p->size;

    /* try to expand (even if already big enough), to clean up chunk 
*/

    free_returned_list(); /* make freed chunks available to 
consolidate */

    while (!inuse(nxt = next_chunk(p))) /* Expand the chunk forward */
    {
      unlink(nxt);
      set_size(p, p->size + nxt->size);
    }

    room = p->size - nb;
    if (room >= 0)          /* Successful expansion */
    {
      if (room >= MINSIZE)  /* give some back if possible */
      {
        mchunkptr remainder = (mchunkptr)((char*)(p) + nb);
        set_size(remainder, room);
        cleanlink(remainder);
        set_size(p, nb);
      }
      set_inuse(p);
      return chunk2mem(p);
    }
    else /* Could not expand. Get another chunk and copy. */
    {
      void* newmem;
      size_t count;
      size_t* src;
      size_t* dst;

      set_inuse(p);    /* don't let malloc consolidate us yet! */
      newmem = malloc(nb);

      /* Copy -- we know that alignment is at least `size_t' */

      src = (size_t*) mem;
      dst = (size_t*) newmem;
      count = (oldsize - SIZE_SZ) / sizeof(size_t);
      while (count-- > 0) *dst++ = *src++;

      free(mem);
      return newmem;
    }
  }
}
----------------------------------------------------------------------
Whoops! BUG!
They don't check to see if the malloc is successful! Although this 
version has so many macros, they may have that hidden in a define 
somewhere. But certainly the free( mem) is done after the malloc 
newmem.

Hmm. Lets see if the other malloc.c is better behaved. (Yes there are 
two malloc.c in the src code for DJGPP.)
This one is from libsrc\c\lib\malloc.c
-------------------------------------------------
void *
realloc(cp, nbytes)
     void *cp; 
     size_t nbytes;
{   
    register u_int onb;
    register int i;
    union overhead *op;
    char *res;
    int was_alloced = 0;

    if (cp == NULL)
        return (malloc(nbytes));
    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
    if (op->ov_magic == MAGIC) {
        was_alloced++;
        i = op->ov_index;
    } else {
        /*
         * Already free, doing "compaction".
         *
         * Search for the old block of memory on the
         * free list.  First, check the most common
         * case (last element free'd), then (this failing)
         * the last ``realloc_srchlen'' items free'd.
         * If all lookups fail, then assume the size of
         * the memory block being realloc'd is the
         * largest possible (so that all "nbytes" of new
         * memory are copied into).  Note that this could cause
         * a memory fault if the old area was tiny, and the moon
         * is gibbous.  However, that is very unlikely.
         */
        if ((i = findbucket(op, 1)) < 0 &&
            (i = findbucket(op, realloc_srchlen)) < 0)
            i = NBUCKETS;
    }
    onb = 1 << (i + 3);
    if (onb < pagesz)
        onb -= sizeof (*op) + RSLOP;
    else
        onb += pagesz - sizeof (*op) - RSLOP;
    /* avoid the copy if same size block */
    if (was_alloced) {
        if (i) {
            i = 1 << (i + 2);
            if (i < pagesz)
                i -= sizeof (*op) + RSLOP;
            else
                i += pagesz - sizeof (*op) - RSLOP;
        }
        if (nbytes <= onb && nbytes > i) {
#ifdef RCHECK
            op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
            *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
            return(cp);
        } else
            free(cp);
    }
    if ((res = malloc(nbytes)) == NULL)
        return (NULL);
    if (cp != res)      /* common optimization if "compacting" */
        bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
    return (res);
}
--------------------------------------
Aha! This one cheats slightly. It frees first, then copies. Here it 
even relies on the fact that free() doesn't deallocate virtual memory.
At least it checks to see if malloc was sucessful.

Try to sleep well as you think on the dictum...
"If builders built as programmers wrote, then the first woodpecker 
that came along would destroy all of civilization."


John Carter
Institute for Water Quality Studies. Department of Water Affairs.
Internet : ece AT dwaf-hri DOT pwv DOT gov DOT za  Phone    : 27-12-808-0374x194      
Fax : 27-12-808-0338 [Host for Afwater list server]

Let's keep this matter in perspective. One insignificant galaxy, one 
of the thousands of millions of galaxies, has a small yellow sun on 
its outer rim. About this sun orbits a molten iron ball. On the 
surface of this ball is a very thin crust of silica slag. This crust 
is partly coated by a microscopically thin layer of carbon hydrogen 
compounds. Some of which has delusions of grandeur.

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019