Fail cleanly on allocation failures

Previously code in the SWIG tool didn't handle allocation failures
well.  Most places didn't check for NULL return from
malloc()/realloc()/calloc() at all, typically resulting in undefined
behaviour, and some places used assert() to check for a NULL return
(which is a misuse of assert() and such checks disappear if built with
NDEBUG defined leaving us back with undefined behaviour).

All C allocations are now done via wrapper functions (Malloc(),
Realloc() and Calloc()) which emit and error and exit with non-zero
status on failure, so a non-NULL return can be relied upon.

Fixes #1901.
This commit is contained in:
Olly Betts 2022-03-03 17:45:03 +13:00 committed by Olly Betts
commit e38847f7e1
14 changed files with 83 additions and 65 deletions

View file

@ -14,6 +14,9 @@
#include "dohint.h"
#include <stdio.h>
#include <stdlib.h>
#ifndef DOH_POOL_SIZE
#define DOH_POOL_SIZE 4194304
#endif
@ -48,10 +51,7 @@ static int pools_initialized = 0;
static void CreatePool() {
Pool *p = 0;
p = (Pool *) DohMalloc(sizeof(Pool));
assert(p);
p->ptr = (DohBase *) DohMalloc(sizeof(DohBase) * PoolSize);
assert(p->ptr);
memset(p->ptr, 0, sizeof(DohBase) * PoolSize);
p->ptr = (DohBase *) DohCalloc(PoolSize, sizeof(DohBase));
p->len = PoolSize;
p->blen = PoolSize * sizeof(DohBase);
p->current = 0;
@ -234,3 +234,40 @@ void DohMemoryDebug(void) {
#endif
}
static void allocation_failed(size_t n, size_t size) {
/* Report and exit as directly as possible to try to avoid further issues due
* to lack of memory. */
if (n == 1) {
#if defined __STDC_VERSION__ && __STDC_VERSION__-0 >= 19901L
fprintf(stderr, "Failed to allocate %zu bytes\n", size);
#else
fprintf(stderr, "Failed to allocate %lu bytes\n", (unsigned long)size);
#endif
} else {
#if defined __STDC_VERSION__ && __STDC_VERSION__-0 >= 19901L
fprintf(stderr, "Failed to allocate %zu*%zu bytes\n", n, size);
#else
fprintf(stderr, "Failed to allocate %lu*%lu bytes\n", (unsigned long)n, (unsigned long)size);
#endif
}
exit(EXIT_FAILURE);
}
void *DohMalloc(size_t size) {
void *p = malloc(size);
if (!p) allocation_failed(1, size);
return p;
}
void *DohRealloc(void *ptr, size_t size) {
void *p = realloc(ptr, size);
if (!p) allocation_failed(1, size);
return p;
}
void *DohCalloc(size_t n, size_t size) {
void *p = calloc(n, size);
if (!p) allocation_failed(n, size);
return p;
}