Remove some compatability with Seventh Edition UNIX realloc().

In Seventh Edition UNIX, the last pointer passed to free() was
guaranteed to not actually have been freed allowing memory to be
"compacted" via the following pattern:

free(foo);
foo = realloc(foo, newsize);

Further, Andrew Koenig reports in "C Traps and Pitfalls" that the
original realloc() implementation required this pattern.

The C standard is clear that this is Undefined Behavior. Modern
allocators don't support it and no portable code could rely on it so
remove this support.

Note: the removed implementation contains an off-by-one error and if
an item isn't found on the freelist, then twice as much memory as the
largest possible allocation will be copied.

Reviewed by:	kib, imp
Obtained from:	CheriBSD
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D21296
This commit is contained in:
Brooks Davis 2019-08-20 16:07:17 +00:00
parent 31c484ad31
commit 98ab79066d
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=351251

View File

@ -85,7 +85,6 @@ union overhead {
static void morecore(int bucket);
static int morepages(int n);
static int findbucket(union overhead *freep, int srchlen);
#define MAGIC 0xef /* magic # on accounting info */
@ -248,19 +247,6 @@ __crt_free(void *cp)
nextf[size] = op;
}
/*
* When a program attempts "storage compaction" as mentioned in the
* old malloc man page, it realloc's an already freed block. Usually
* this is the last block it freed; occasionally it might be farther
* back. We have to search all the free lists for the block in order
* to determine its bucket: 1st we make one pass through the lists
* checking only the first block in each; if that fails we search
* ``realloc_srchlen'' blocks in each list for a match (the variable
* is extern so the caller can modify it). If that fails we just copy
* however many bytes was given to realloc() and hope it's not huge.
*/
static int realloc_srchlen = 4; /* 4 should be plenty, -1 =>'s whole list */
void *
__crt_realloc(void *cp, size_t nbytes)
{
@ -268,80 +254,35 @@ __crt_realloc(void *cp, size_t nbytes)
int i;
union overhead *op;
char *res;
int was_alloced = 0;
if (cp == NULL)
return (__crt_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;
}
if (op->ov_magic != MAGIC)
return (NULL); /* Double-free or bad argument */
i = op->ov_index;
onb = 1 << (i + 3);
if (onb < (u_int)pagesz)
onb -= sizeof(*op);
else
onb += pagesz - sizeof(*op);
/* avoid the copy if same size block */
if (was_alloced) {
if (i) {
i = 1 << (i + 2);
if (i < pagesz)
i -= sizeof(*op);
else
i += pagesz - sizeof(*op);
}
if (nbytes <= onb && nbytes > (size_t)i)
return (cp);
__crt_free(cp);
if (i != 0) {
i = 1 << (i + 2);
if (i < pagesz)
i -= sizeof(*op);
else
i += pagesz - sizeof(*op);
}
if (nbytes <= onb && nbytes > (size_t)i)
return (cp);
if ((res = __crt_malloc(nbytes)) == NULL)
return (NULL);
if (cp != res) /* common optimization if "compacting" */
bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
__crt_free(cp);
return (res);
}
/*
* Search ``srchlen'' elements of each free list for a block whose
* header starts at ``freep''. If srchlen is -1 search the whole list.
* Return bucket number, or -1 if not found.
*/
static int
findbucket(union overhead *freep, int srchlen)
{
union overhead *p;
int i, j;
for (i = 0; i < NBUCKETS; i++) {
j = 0;
for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
if (p == freep)
return (i);
j++;
}
}
return (-1);
}
static int
morepages(int n)
{