[BACK]Return to compat_recallocarray.c CVS log [TXT][DIR] Up to [cvsweb.bsd.lv] / mandoc

Annotation of mandoc/compat_recallocarray.c, Revision 1.2

1.2     ! schwarze    1: /*     $Id: compat_recallocarray.c,v 1.1 2017/06/12 19:05:47 schwarze Exp $ */
        !             2: /*     $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $  */
1.1       schwarze    3: /*
1.2     ! schwarze    4:  * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
1.1       schwarze    5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
1.2     ! schwarze   18: #include "config.h"
1.1       schwarze   19:
                     20: #include <sys/types.h>
                     21: #include <errno.h>
1.2     ! schwarze   22: #include <stdlib.h>
1.1       schwarze   23: #include <stdint.h>
                     24: #include <string.h>
                     25:
                     26: /*
                     27:  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
                     28:  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
                     29:  */
1.2     ! schwarze   30: #define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
1.1       schwarze   31:
                     32: /*
                     33:  * Even though specified in POSIX, the PAGESIZE and PAGE_SIZE
                     34:  * macros have very poor portability.  Since we only use this
                     35:  * to avoid free() overhead for small shrinking, simply pick
                     36:  * an arbitrary number.
                     37:  */
1.2     ! schwarze   38: #define getpagesize()  (1UL << 12)
1.1       schwarze   39:
                     40:
                     41: void *
                     42: recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
                     43: {
                     44:        size_t oldsize, newsize;
                     45:        void *newptr;
                     46:
                     47:        if (ptr == NULL)
                     48:                return calloc(newnmemb, size);
                     49:
                     50:        if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
                     51:            newnmemb > 0 && SIZE_MAX / newnmemb < size) {
                     52:                errno = ENOMEM;
                     53:                return NULL;
                     54:        }
                     55:        newsize = newnmemb * size;
                     56:
                     57:        if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
                     58:            oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
                     59:                errno = EINVAL;
                     60:                return NULL;
                     61:        }
                     62:        oldsize = oldnmemb * size;
                     63:
                     64:        /*
                     65:         * Don't bother too much if we're shrinking just a bit,
                     66:         * we do not shrink for series of small steps, oh well.
                     67:         */
                     68:        if (newsize <= oldsize) {
                     69:                size_t d = oldsize - newsize;
                     70:
1.2     ! schwarze   71:                if (d < oldsize / 2 && d < getpagesize()) {
1.1       schwarze   72:                        memset((char *)ptr + newsize, 0, d);
                     73:                        return ptr;
                     74:                }
                     75:        }
                     76:
                     77:        newptr = malloc(newsize);
                     78:        if (newptr == NULL)
                     79:                return NULL;
                     80:
                     81:        if (newsize > oldsize) {
                     82:                memcpy(newptr, ptr, oldsize);
                     83:                memset((char *)newptr + oldsize, 0, newsize - oldsize);
                     84:        } else
                     85:                memcpy(newptr, ptr, newsize);
                     86:
                     87:        /*
                     88:         * At this point, the OpenBSD implementation calls
                     89:         * explicit_bzero() on the old memory before it is
                     90:         * freed.  Since explicit_bzero() is hard to implement
                     91:         * portably and we don't handle confidential data in
                     92:         * mandoc in the first place, simply free the memory
                     93:         * without clearing it.
                     94:         */
                     95:
                     96:        free(ptr);
                     97:
                     98:        return newptr;
                     99: }

CVSweb