bug in 4.2BSD malloc with -DRCHECK
John P. Linderman
jpl at allegra.UUCP
Tue Oct 16 06:42:15 AEST 1984
SYNOPSIS
Realloc can cause errors when malloc is compiled with -DRCHECK -Ddebug
SYMPTOMS
If /usr/src/lib/libc/gen/malloc.c is compiled with -DRCHECK and -Ddebug
to do range checking, a realloc that expands an allocation, but not by
enough to push it into a larger bucket, will cause an ASSERT error when
the area is freed.
REPEAT BY
Compile the following test program together with malloc.c, making sure
that RCHECK and debug are defined when malloc.c is compiled.
#include <stdio.h>
main()
{
char line[BUFSIZ], *p, *q, *malloc(), *realloc();
int m, n;
p = NULL;
while (gets(line)) {
switch (*line) {
case 'q': /* quit */
return (0);
case 'a': /* allocate */
case 'r': /* reallocate */
n = atoi(line+1);
if (n <= 0) {
(void) fprintf(stderr, "Must specify a size > 0\n");
} else {
switch (*line) {
case 'a':
p = malloc(n);
break;
case 'r':
p = realloc(p, n);
break;
}
for (q = p, m = n; --m >= 0; *q++ = 0);
(void) printf("%d bytes at %#x\n", n, p);
}
break;
case 'f': /* free */
if (p != NULL) {
free(p);
p = NULL;
}
break;
default:
(void) fprintf(stderr, "aN allocate N bytes\n");
(void) fprintf(stderr, "f free last allocation\n");
(void) fprintf(stderr, "rN reallocate N bytes\n");
(void) fprintf(stderr, "q quit\n");
}
}
exit(0);
}
Run the result with input
a400
r480
f
q
This causes an ASSERT error out of free().
FIX BY
Change the following lines in subroutine realloc() in malloc.c
/* avoid the copy if same size block */
if (was_alloced &&
! nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
return(cp);
to instead be
/* avoid the copy if same size block */
if (was_alloced &&
! nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP) {
+ #ifdef RCHECK
+ op->ov_size = ((nbytes + sizeof(union overhead) + RSLOP) + 3 & ~3) - 1;
+ *((u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP)) = RMAGIC;
+ #endif
return(cp);
+ }
so the magic number will be where free expects to find it.
There remains a "peculiarity" when 20 or fewer bytes are reallocated
with RCHECK defined. Under these circumstances,
nbytes > (onb >> 1) - sizeof(*op) - RSLOP
fails because the right hand side of the inequality is logically
negative but nbytes is unsigned. Thus, space is always reallocated,
even when existing space would have been suitable. This can't
happen when RCHECK is undefined, and nobody ever promised that
realloc wouldn't do unnecessary copies, so I didn't bother to "fix" it.
Logically speaking, the definition of RCHECK ought to force the
definition of debug, like
#ifdef RCHECK
#define debug
#endif RCHECK
since turning on RCHECK without turning on debug simply adds to the
overhead without reporting any errors that are detected. Malloc is
nowhere near my favorite piece of software, so I shall charitably
shut up at this point.
John P. Linderman Department of Bad Checks allegra!jpl
More information about the Comp.unix.wizards
mailing list