mirror of
https://git.do.srb2.org/KartKrew/Kart-Public.git
synced 2024-11-10 15:22:20 +00:00
76 lines
1.9 KiB
C
76 lines
1.9 KiB
C
/* Fail-proof memory allocation by Graue <graue@oceanbase.org>; public domain */
|
|
|
|
#include <stdlib.h>
|
|
#include <limits.h>
|
|
#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));
|
|
}
|