#include <errno.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof (size_t) * 4))
void *
recallocarray(void *ptr, size_t oldnelem, size_t newnelem, size_t elsize)
{
size_t oldsize, newsize;
void *newptr;
if (ptr == NULL)
return (calloc(newnelem, elsize));
if ((newnelem >= MUL_NO_OVERFLOW || elsize >= MUL_NO_OVERFLOW) &&
newnelem > 0 && SIZE_MAX / newnelem < elsize) {
errno = ENOMEM;
return (NULL);
}
newsize = newnelem * elsize;
if ((oldnelem >= MUL_NO_OVERFLOW || elsize >= MUL_NO_OVERFLOW) &&
oldnelem > 0 && SIZE_MAX / oldnelem < elsize) {
errno = EINVAL;
return (NULL);
}
oldsize = oldnelem * elsize;
if (newsize <= oldsize) {
size_t d = oldsize - newsize;
if (d < oldsize / 2 && d < getpagesize()) {
(void) memset((char *)ptr + newsize, 0, d);
return (ptr);
}
}
newptr = malloc(newsize);
if (newptr == NULL)
return (NULL);
if (newsize > oldsize) {
(void) memcpy(newptr, ptr, oldsize);
(void) memset((char *)newptr + oldsize, 0, newsize - oldsize);
} else {
(void) memcpy(newptr, ptr, newsize);
}
explicit_bzero(ptr, oldsize);
free(ptr);
return (newptr);
}