Smarter implementation of calloc(3), which uses the fact that mmap(2)
authorotto <otto@openbsd.org>
Fri, 22 Aug 2008 17:14:56 +0000 (17:14 +0000)
committerotto <otto@openbsd.org>
Fri, 22 Aug 2008 17:14:56 +0000 (17:14 +0000)
returns zero filled pages; remember to replace this function as well if you
provide your own malloc implementation; ok djm@ deraadt@

lib/libc/stdlib/Makefile.inc
lib/libc/stdlib/malloc.c

index f1708a1..09db4ce 100644 (file)
@@ -1,10 +1,10 @@
-#      $OpenBSD: Makefile.inc,v 1.38 2008/06/13 21:04:24 landry Exp $
+#      $OpenBSD: Makefile.inc,v 1.39 2008/08/22 17:14:56 otto Exp $
 
 # stdlib sources
 .PATH: ${LIBCSRCDIR}/arch/${MACHINE_ARCH}/stdlib ${LIBCSRCDIR}/stdlib
 
 SRCS+= a64l.c abort.c atexit.c atoi.c atof.c atol.c atoll.c bsearch.c \
-       calloc.c cfree.c exit.c ecvt.c gcvt.c getenv.c getopt_long.c \
+       cfree.c exit.c ecvt.c gcvt.c getenv.c getopt_long.c \
        getsubopt.c hcreate.c heapsort.c imaxabs.c imaxdiv.c l64a.c llabs.c \
        lldiv.c lsearch.c malloc.c merge.c putenv.c qsort.c radixsort.c rand.c \
        random.c realpath.c setenv.c strtoimax.c strtod.c strtof.c strtol.c \
index 645dc5a..d03b831 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: malloc.c,v 1.93 2008/08/07 18:41:47 otto Exp $        */
+/*     $OpenBSD: malloc.c,v 1.94 2008/08/22 17:14:57 otto Exp $        */
 /*
  * Copyright (c) 2008 Otto Moerbeek <otto@drijf.net>
  *
@@ -443,7 +443,7 @@ unmap(struct dir_info *d, void *p, size_t sz)
 }
 
 static void *
-map(struct dir_info *d, size_t sz)
+map(struct dir_info *d, size_t sz, int zero_fill)
 {
        size_t psz = PAGEROUND(sz) >> MALLOC_PAGESHIFT;
        struct region_info *r, *big = NULL;
@@ -454,6 +454,7 @@ map(struct dir_info *d, size_t sz)
                p = MMAP(sz);
                if (p != MAP_FAILED)
                        malloc_used += sz;
+               /* zero fill not needed */
                return p;
        }
        offset = getrbyte();
@@ -469,6 +470,8 @@ map(struct dir_info *d, size_t sz)
                                r->p = NULL;
                                r->size = 0;
                                d->free_regions_size -= psz;
+                               if (zero_fill)
+                                       memset(p, 0, sz);
                                return p;
                        } else if (r->size > psz)
                                big = r;
@@ -483,6 +486,8 @@ map(struct dir_info *d, size_t sz)
                        madvise(p, sz, MADV_NORMAL);
                r->size -= psz;
                d->free_regions_size -= psz;
+               if (zero_fill)
+                       memset(p, 0, sz);
                return p;
        }
        p = MMAP(sz);
@@ -490,6 +495,7 @@ map(struct dir_info *d, size_t sz)
                malloc_used += sz;
        if (d->free_regions_size > malloc_cache)
                wrtwarning("malloc cache");
+       /* zero fill not needed */
        return p;
 }
 
@@ -835,7 +841,7 @@ omalloc_make_chunks(struct dir_info *d, int bits)
        long            i, k;
 
        /* Allocate a new bucket */
-       pp = map(d, MALLOC_PAGESIZE);
+       pp = map(d, MALLOC_PAGESIZE, 0);
        if (pp == MAP_FAILED)
                return NULL;
 
@@ -1053,7 +1059,7 @@ omalloc(size_t sz, int zero_fill)
                }
                sz += malloc_guard;
                psz = PAGEROUND(sz);
-               p = map(&g_pool, psz);
+               p = map(&g_pool, psz, zero_fill);
                if (p == MAP_FAILED) {
                        errno = ENOMEM;
                        return NULL;
@@ -1077,8 +1083,6 @@ omalloc(size_t sz, int zero_fill)
                    sz - malloc_guard < MALLOC_PAGESIZE - MALLOC_MINSIZE)
                        p = ((char *)p) + ((MALLOC_PAGESIZE - MALLOC_MINSIZE -
                            (sz - malloc_guard)) & ~(MALLOC_MINSIZE-1));
-               if (zero_fill)
-                       memset(p, 0, sz - malloc_guard);
        } else {
                /* takes care of SOME_JUNK */
                p = malloc_bytes(&g_pool, sz);
@@ -1323,3 +1327,48 @@ realloc(void *ptr, size_t size)
        }
        return r;
 }
+
+
+#define MUL_NO_OVERFLOW        (1UL << (sizeof(size_t) * 4))
+
+void *
+calloc(size_t nmemb, size_t size)
+{
+       void *r;
+
+       _MALLOC_LOCK();
+       malloc_func = " in calloc():";  
+       if (!g_pool.regions_total) {
+               if (omalloc_init(&g_pool)) {
+                        _MALLOC_UNLOCK();
+                       if (malloc_xmalloc)
+                               wrterror("out of memory");
+                       errno = ENOMEM;
+                       return NULL;
+               }
+       }
+       if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+           nmemb > 0 && SIZE_MAX / nmemb < size) {
+                _MALLOC_UNLOCK();
+               if (malloc_xmalloc)
+                       wrterror("out of memory");
+               errno = ENOMEM;
+               return NULL;
+       }
+
+       if (malloc_active++) {
+               malloc_recurse();
+               return NULL;
+       }
+
+       size *= nmemb;
+       r = omalloc(size, 1);
+  
+       malloc_active--;
+       _MALLOC_UNLOCK();
+       if (r == NULL && malloc_xmalloc) {
+               wrterror("out of memory");
+               errno = ENOMEM;
+       }
+       return r;
+}