From: John Carter 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.