/* Fail-proof memory allocation by Graue ; public domain */
#include
#include
#include "err.h"
/* MinGW (for example) appears to lack SIZE_T_MAX. */
#ifndef SIZE_T_MAX
#define SIZE_T_MAX ULONG_MAX
#endif
/*
* The usual xmalloc and xrealloc type routines, for allocating memory
* and bombing out if it fails.
*
* xm and xr here take two values: size and nmemb, like fread/fwrite.
* The idea is to be able to check for overflow, to prevent some weird
* crashes and security problems that can arise if you multiply size
* and nmemb and they overflow.
*/
/* FIXME: use %zu (size_t) in these format arguments if library is C99 */
/*
* Multiply size and number of elements, bombing out if overflow would
* occur.
* Note: In the case where size*nmemb is exactly equal to SIZE_T_MAX,
* this function considers that an overflow, even though it isn't
* really. But it's not likely the program will get that much memory,
* anyway.
*/
static size_t sizmul(size_t size, size_t nmemb)
{
if (SIZE_T_MAX / size <= nmemb)
{
errx(1, "allocating %lu objects of size %lu "
"would overflow", (unsigned long)nmemb,
(unsigned long)size);
}
return size * nmemb; /* won't overflow */
}
static void nomem(size_t size, size_t nmemb)
{
err(1, "cannot allocate %lu objects of size %lu "
"(total %lu bytes)", (unsigned long)nmemb,
(unsigned long)size, (unsigned long)(nmemb*size));
}
void *xm(size_t size, size_t nmemb)
{
const size_t bytes = sizmul(size, nmemb);
void *p;
p = malloc(bytes);
if (p == NULL) nomem(size, nmemb);
return p;
}
void *xr(void *p, size_t size, size_t nmemb)
{
const size_t bytes = sizmul(size, nmemb);
p = realloc(p, bytes);
if (p == NULL) nomem(size, nmemb);
return p;
}
/* expand array */
void *xpnd(void *p, int nit, int *sit, size_t sz)
{
if (nit < *sit) return p;
else if (*sit > 0) return xr(p, sz, (*sit *= 2));
else return xm(sz, (*sit = 10));
}