summaryrefslogtreecommitdiff
path: root/openbsd-compat/recallocarray.c
diff options
context:
space:
mode:
Diffstat (limited to 'openbsd-compat/recallocarray.c')
-rw-r--r--openbsd-compat/recallocarray.c88
1 files changed, 88 insertions, 0 deletions
diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c
new file mode 100644
index 000000000..506741708
--- /dev/null
+++ b/openbsd-compat/recallocarray.c
@@ -0,0 +1,88 @@
1/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
2/*
3 * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
19
20#include "includes.h"
21#ifndef HAVE_RECALLOCARRAY
22
23#include <errno.h>
24#include <stdlib.h>
25#include <stdint.h>
26#include <string.h>
27#include <unistd.h>
28
29/*
30 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
31 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
32 */
33#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
34
35void *
36recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
37{
38 size_t oldsize, newsize;
39 void *newptr;
40
41 if (ptr == NULL)
42 return calloc(newnmemb, size);
43
44 if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
45 newnmemb > 0 && SIZE_MAX / newnmemb < size) {
46 errno = ENOMEM;
47 return NULL;
48 }
49 newsize = newnmemb * size;
50
51 if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
52 oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
53 errno = EINVAL;
54 return NULL;
55 }
56 oldsize = oldnmemb * size;
57
58 /*
59 * Don't bother too much if we're shrinking just a bit,
60 * we do not shrink for series of small steps, oh well.
61 */
62 if (newsize <= oldsize) {
63 size_t d = oldsize - newsize;
64
65 if (d < oldsize / 2 && d < getpagesize()) {
66 memset((char *)ptr + newsize, 0, d);
67 return ptr;
68 }
69 }
70
71 newptr = malloc(newsize);
72 if (newptr == NULL)
73 return NULL;
74
75 if (newsize > oldsize) {
76 memcpy(newptr, ptr, oldsize);
77 memset((char *)newptr + oldsize, 0, newsize - oldsize);
78 } else
79 memcpy(newptr, ptr, newsize);
80
81 explicit_bzero(ptr, oldsize);
82 free(ptr);
83
84 return newptr;
85}
86/* DEF_WEAK(recallocarray); */
87
88#endif /* HAVE_RECALLOCARRAY */