summaryrefslogtreecommitdiff
path: root/lib/libc/stdlib/malloc.c
diff options
context:
space:
mode:
authorkleink <kleink@NetBSD.org>1999-01-29 08:11:36 +0000
committerkleink <kleink@NetBSD.org>1999-01-29 08:11:36 +0000
commitfd13be3c46bcbfdacc1cc071866404e33ee4c8df (patch)
treea46671ebc7de1ec50315671a78fb96d472eb7589 /lib/libc/stdlib/malloc.c
parentf9e92fac2336557277f9b74d9c5166292af4315e (diff)
Protect access of state with a mutex. Miscellaneous notes:
* still needs an implementation-independent ("reentrant.h") method for disabling cancellation, * break a leg to leave realloc() `storage compaction' as was for non-reentrant code, * use of stdio in assertion code is unsafe.
Diffstat (limited to 'lib/libc/stdlib/malloc.c')
-rw-r--r--lib/libc/stdlib/malloc.c113
1 files changed, 85 insertions, 28 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c
index e1139b7b1ad..c8eb841cca4 100644
--- a/lib/libc/stdlib/malloc.c
+++ b/lib/libc/stdlib/malloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: malloc.c,v 1.15 1998/11/15 17:13:51 christos Exp $ */
+/* $NetBSD: malloc.c,v 1.16 1999/01/29 08:11:36 kleink Exp $ */
/*
* Copyright (c) 1983, 1993
@@ -38,7 +38,7 @@
#if 0
static char sccsid[] = "@(#)malloc.c 8.1 (Berkeley) 6/4/93";
#else
-__RCSID("$NetBSD: malloc.c,v 1.15 1998/11/15 17:13:51 christos Exp $");
+__RCSID("$NetBSD: malloc.c,v 1.16 1999/01/29 08:11:36 kleink Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
@@ -54,15 +54,17 @@ __RCSID("$NetBSD: malloc.c,v 1.15 1998/11/15 17:13:51 christos Exp $");
*/
#include "namespace.h"
-#if defined(DEBUG) || defined(RCHECK) || defined(MSTATS)
+#include <sys/types.h>
+#if defined(DEBUG) || defined(RCHECK)
+#include <sys/uio.h>
+#endif
+#if defined(RCHECK) || defined(MSTATS)
#include <stdio.h>
#endif
-#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-
-#define NULL 0
+#include "reentrant.h"
/*
@@ -92,7 +94,9 @@ union overhead {
};
#define MAGIC 0xef /* magic # on accounting info */
+#ifdef RCHECK
#define RMAGIC 0x5555 /* magic # on range info */
+#endif
#ifdef RCHECK
#define RSLOP sizeof (u_short)
@@ -117,26 +121,53 @@ static int pagebucket; /* page size bucket */
* for a given block size.
*/
static u_int nmalloc[NBUCKETS];
-#include <stdio.h>
+#endif
+
+#ifdef _REENT
+static mutex_t malloc_mutex = MUTEX_INITIALIZER;
#endif
static void morecore __P((int));
static int findbucket __P((union overhead *, int));
#ifdef MSTATS
-void mstats __P((char *));
+void mstats __P((const char *));
#endif
#if defined(DEBUG) || defined(RCHECK)
#define ASSERT(p) if (!(p)) botch(__STRING(p))
-static botch __P((char *));
+static void botch __P((const char *));
-static
+/*
+ * NOTE: since this may be called while malloc_mutex is locked, stdio must not
+ * be used in this function.
+ */
+static void
botch(s)
- char *s;
+ const char *s;
{
- fprintf(stderr, "\r\nassertion botched: %s\r\n", s);
- (void) fflush(stderr); /* just in case user buffered it */
+ struct iovec iov[3];
+
+ iov[0].iov_base = "\nassertion botched: ";
+ iov[0].iov_len = 20;
+ iov[1].iov_base = (void *)s;
+ iov[1].iov_len = strlen(s);
+ iov[2].iov_base = "\n";
+ iov[2].iov_len = 1;
+
+ /*
+ * This place deserves a word of warning: a cancellation point will
+ * occur when executing writev(), and we might be still owning
+ * malloc_mutex. At this point we need to disable cancellation
+ * until `after' abort() because i) establishing a cancellation handler
+ * might, depending on the implementation, result in another malloc()
+ * to be executed, and ii) it is really not desirable to let execution
+ * continue. `Fix me.'
+ *
+ * Note that holding mutex_lock during abort() is safe.
+ */
+
+ (void)writev(STDERR_FILENO, iov, 3);
abort();
}
#else
@@ -152,19 +183,24 @@ malloc(nbytes)
long n;
unsigned amt;
+ mutex_lock(&malloc_mutex);
+
/*
* First time malloc is called, setup page size and
* align break pointer so all data will be page aligned.
*/
if (pagesz == 0) {
pagesz = n = getpagesize();
+ ASSERT(pagesz > 0);
op = (union overhead *)(void *)sbrk(0);
n = n - sizeof (*op) - ((long)op & (n - 1));
if (n < 0)
n += pagesz;
- if (n) {
- if (sbrk((int)n) == (char *)-1)
+ if (n) {
+ if (sbrk((int)n) == (void *)-1) {
+ mutex_unlock(&malloc_mutex);
return (NULL);
+ }
}
bucket = 0;
amt = 8;
@@ -204,8 +240,10 @@ malloc(nbytes)
*/
if ((op = nextf[bucket]) == NULL) {
morecore(bucket);
- if ((op = nextf[bucket]) == NULL)
+ if ((op = nextf[bucket]) == NULL) {
+ mutex_unlock(&malloc_mutex);
return (NULL);
+ }
}
/* remove from linked list */
nextf[bucket] = op->ov_next;
@@ -214,6 +252,7 @@ malloc(nbytes)
#ifdef MSTATS
nmalloc[bucket]++;
#endif
+ mutex_unlock(&malloc_mutex);
#ifdef RCHECK
/*
* Record allocated size of block and
@@ -223,7 +262,7 @@ malloc(nbytes)
op->ov_rmagic = RMAGIC;
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
- return ((char *)(void *)(op + 1));
+ return ((void *)(op + 1));
}
/*
@@ -276,7 +315,7 @@ void
free(cp)
void *cp;
{
- long size;
+ long size;
union overhead *op;
if (cp == NULL)
@@ -294,11 +333,13 @@ free(cp)
#endif
size = op->ov_index;
ASSERT(size < NBUCKETS);
- op->ov_next = nextf[(size_t)size]; /* also clobbers ov_magic */
- nextf[(size_t)size] = op;
+ mutex_lock(&malloc_mutex);
+ op->ov_next = nextf[(unsigned int)size];/* also clobbers ov_magic */
+ nextf[(unsigned int)size] = op;
#ifdef MSTATS
nmalloc[(size_t)size]--;
#endif
+ mutex_unlock(&malloc_mutex);
}
/*
@@ -322,16 +363,17 @@ realloc(cp, nbytes)
u_long onb;
long i;
union overhead *op;
- char *res;
+ char *res;
int was_alloced = 0;
if (cp == NULL)
return (malloc(nbytes));
if (nbytes == 0) {
free (cp);
- return NULL;
+ return (NULL);
}
op = (union overhead *)(void *)((caddr_t)cp - sizeof (union overhead));
+ mutex_lock(&malloc_mutex);
if (op->ov_magic == MAGIC) {
was_alloced++;
i = op->ov_index;
@@ -373,14 +415,29 @@ realloc(cp, nbytes)
op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
*(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
#endif
- return(cp);
- } else
+ mutex_unlock(&malloc_mutex);
+ return (cp);
+
+ }
+#ifndef _REENT
+ else
free(cp);
+#endif
+ }
+ mutex_unlock(&malloc_mutex);
+ if ((res = malloc(nbytes)) == NULL) {
+#ifdef _REENT
+ free(cp);
+#endif
+ return (NULL);
}
- if ((res = malloc(nbytes)) == NULL)
- return (NULL);
- if (cp != res) /* common optimization if "compacting" */
- memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
+#ifndef _REENT
+ if (cp != res) /* common optimization if "compacting" */
+ (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
+#else
+ (void)memmove(res, cp, (size_t)((nbytes < onb) ? nbytes : onb));
+ free(cp);
+#endif
return (res);
}