add h_alloc() which calls errx() on failure and use it for all basic allocation

Rationale: "Basic allocation" refers to things outside of parsing proper,
mostly initialization. If such allocations fail, the system is globally
emory-starved from which it will likely not recover by returning failure.
In this case, terminating the process is in fact the most robust strategy as
it may mean the difference between a permanent hang and a temporary crash.
This commit is contained in:
Sven M. Hallberg 2015-11-30 16:37:00 +01:00
parent ca1d8df06c
commit 3fc56a0dc3
6 changed files with 30 additions and 29 deletions

View file

@ -47,15 +47,20 @@ struct HArena_ {
jmp_buf *except; jmp_buf *except;
}; };
void* h_alloc(HAllocator* mm__, size_t size) {
void *p = mm__->alloc(mm__, size);
if(!p)
h_platform_errx(1, "memory allocation failed (%uB requested)\n", (unsigned int)size);
return p;
}
HArena *h_new_arena(HAllocator* mm__, size_t block_size) { HArena *h_new_arena(HAllocator* mm__, size_t block_size) {
if (block_size == 0) if (block_size == 0)
block_size = 4096; block_size = 4096;
struct HArena_ *ret = h_new(struct HArena_, 1); struct HArena_ *ret = h_new(struct HArena_, 1);
struct arena_link *link = (struct arena_link*)mm__->alloc(mm__, sizeof(struct arena_link) + block_size); struct arena_link *link = (struct arena_link*)h_alloc(mm__, sizeof(struct arena_link) + block_size);
if (!link) { assert(ret != NULL);
// TODO: error-reporting -- let user know that arena link couldn't be allocated assert(link != NULL);
return NULL;
}
memset(link, 0, sizeof(struct arena_link) + block_size); memset(link, 0, sizeof(struct arena_link) + block_size);
link->free = block_size; link->free = block_size;
link->used = 0; link->used = 0;

View file

@ -24,17 +24,6 @@
extern "C" { extern "C" {
#endif #endif
// TODO(thequux): Turn this into an "HAllocatorVtable", and add a wrapper that also takes an environment pointer.
typedef struct HAllocator_ {
void* (*alloc)(struct HAllocator_* allocator, size_t size);
void* (*realloc)(struct HAllocator_* allocator, void* ptr, size_t size);
void (*free)(struct HAllocator_* allocator, void* ptr);
} HAllocator;
typedef struct HArena_ HArena ; // hidden implementation
HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for default...
#if defined __llvm__ #if defined __llvm__
# if __has_attribute(malloc) # if __has_attribute(malloc)
# define ATTR_MALLOC(n) __attribute__((malloc)) # define ATTR_MALLOC(n) __attribute__((malloc))
@ -49,6 +38,19 @@ HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for def
# define ATTR_MALLOC(n) # define ATTR_MALLOC(n)
#endif #endif
// TODO(thequux): Turn this into an "HAllocatorVtable", and add a wrapper that also takes an environment pointer.
typedef struct HAllocator_ {
void* (*alloc)(struct HAllocator_* allocator, size_t size);
void* (*realloc)(struct HAllocator_* allocator, void* ptr, size_t size);
void (*free)(struct HAllocator_* allocator, void* ptr);
} HAllocator;
void* h_alloc(HAllocator* allocator, size_t size) ATTR_MALLOC(2);
typedef struct HArena_ HArena ; // hidden implementation
HArena *h_new_arena(HAllocator* allocator, size_t block_size); // pass 0 for default...
void* h_arena_malloc(HArena *arena, size_t count) ATTR_MALLOC(2); void* h_arena_malloc(HArena *arena, size_t count) ATTR_MALLOC(2);
void h_arena_free(HArena *arena, void* ptr); // For future expansion, with alternate memory managers. void h_arena_free(HArena *arena, void* ptr); // For future expansion, with alternate memory managers.
void h_delete_arena(HArena *arena); void h_delete_arena(HArena *arena);

View file

@ -12,10 +12,8 @@
HBitWriter *h_bit_writer_new(HAllocator* mm__) { HBitWriter *h_bit_writer_new(HAllocator* mm__) {
HBitWriter *writer = h_new(HBitWriter, 1); HBitWriter *writer = h_new(HBitWriter, 1);
memset(writer, 0, sizeof(*writer)); memset(writer, 0, sizeof(*writer));
writer->buf = mm__->alloc(mm__, writer->capacity = 8); writer->buf = h_alloc(mm__, writer->capacity = 8);
if (!writer) { assert(writer != NULL);
return NULL;
}
memset(writer->buf, 0, writer->capacity); memset(writer->buf, 0, writer->capacity);
writer->mm__ = mm__; writer->mm__ = mm__;
writer->flags = BYTE_BIG_ENDIAN | BIT_BIG_ENDIAN; writer->flags = BYTE_BIG_ENDIAN | BIT_BIG_ENDIAN;

View file

@ -49,7 +49,7 @@
rtype_t name##__m(HAllocator* mm__) rtype_t name##__m(HAllocator* mm__)
// Functions with arguments are difficult to forward cleanly. Alas, we will need to forward them manually. // Functions with arguments are difficult to forward cleanly. Alas, we will need to forward them manually.
#define h_new(type, count) ((type*)(mm__->alloc(mm__, sizeof(type)*(count)))) #define h_new(type, count) ((type*)(h_alloc(mm__, sizeof(type)*(count))))
#define h_free(addr) (mm__->free(mm__, (addr))) #define h_free(addr) (mm__->free(mm__, (addr)))
#ifndef __cplusplus #ifndef __cplusplus

View file

@ -186,13 +186,11 @@ static void unamb_sub(const HParsedToken* tok, struct result_buf *buf) {
char* h_write_result_unamb(const HParsedToken* tok) { char* h_write_result_unamb(const HParsedToken* tok) {
struct result_buf buf = { struct result_buf buf = {
.output = (&system_allocator)->alloc(&system_allocator, 16), .output = h_alloc(&system_allocator, 16),
.len = 0, .len = 0,
.capacity = 16 .capacity = 16
}; };
if (!buf.output) { assert(buf.output != NULL);
return NULL;
}
unamb_sub(tok, &buf); unamb_sub(tok, &buf);
append_buf_c(&buf, 0); append_buf_c(&buf, 0);
return buf.output; return buf.output;

View file

@ -46,10 +46,8 @@ static int compare_entries(const void* v1, const void* v2) {
} }
HTokenType h_allocate_token_type(const char* name) { HTokenType h_allocate_token_type(const char* name) {
Entry* new_entry = (&system_allocator)->alloc(&system_allocator, sizeof(*new_entry)); Entry* new_entry = h_alloc(&system_allocator, sizeof(*new_entry));
if (!new_entry) { assert(new_entry != NULL);
return TT_INVALID;
}
new_entry->name = name; new_entry->name = name;
new_entry->value = 0; new_entry->value = 0;
Entry* probe = *(Entry**)tsearch(new_entry, &tt_registry, compare_entries); Entry* probe = *(Entry**)tsearch(new_entry, &tt_registry, compare_entries);