diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index ff7a46793a..893a1238ff 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -10,20 +10,28 @@ typedef void (*free_func_t)(void *p); +/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than + * proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */ +#define ALLOCA_MAX (4U*1024U*1024U) + #define new(t, n) ((t*) malloc_multiply(sizeof(t), (n))) #define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t))) -#define newa(t, n) \ - ({ \ - assert(!size_multiply_overflow(sizeof(t), n)); \ - (t*) alloca(sizeof(t)*(n)); \ +#define newa(t, n) \ + ({ \ + size_t _n_ = n; \ + assert(!size_multiply_overflow(sizeof(t), _n_)); \ + assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ + (t*) alloca(sizeof(t)*_n_); \ }) -#define newa0(t, n) \ - ({ \ - assert(!size_multiply_overflow(sizeof(t), n)); \ - (t*) alloca0(sizeof(t)*(n)); \ +#define newa0(t, n) \ + ({ \ + size_t _n_ = n; \ + assert(!size_multiply_overflow(sizeof(t), _n_)); \ + assert(sizeof(t)*_n_ <= ALLOCA_MAX); \ + (t*) alloca0(sizeof(t)*_n_); \ }) #define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n))) @@ -51,16 +59,20 @@ void* memdup_suffix0(const void *p, size_t l) _alloc_(2); #define memdupa(p, l) \ ({ \ void *_q_; \ - _q_ = alloca(l); \ - memcpy(_q_, p, l); \ + size_t _l_ = l; \ + assert(_l_ <= ALLOCA_MAX); \ + _q_ = alloca(_l_); \ + memcpy(_q_, p, _l_); \ }) #define memdupa_suffix0(p, l) \ ({ \ void *_q_; \ - _q_ = alloca(l + 1); \ - ((uint8_t*) _q_)[l] = 0; \ - memcpy(_q_, p, l); \ + size_t _l_ = l; \ + assert(_l_ <= ALLOCA_MAX); \ + _q_ = alloca(_l_ + 1); \ + ((uint8_t*) _q_)[_l_] = 0; \ + memcpy(_q_, p, _l_); \ }) static inline void freep(void *p) { @@ -116,6 +128,7 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); ({ \ char *_new_; \ size_t _len_ = n; \ + assert(_len_ <= ALLOCA_MAX); \ _new_ = alloca(_len_); \ (void *) memset(_new_, 0, _len_); \ }) @@ -125,16 +138,18 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); ({ \ void *_ptr_; \ size_t _mask_ = (align) - 1; \ - _ptr_ = alloca((size) + _mask_); \ + size_t _size_ = size; \ + assert(_size_ <= ALLOCA_MAX); \ + _ptr_ = alloca(_size_ + _mask_); \ (void*)(((uintptr_t)_ptr_ + _mask_) & ~_mask_); \ }) #define alloca0_align(size, align) \ ({ \ void *_new_; \ - size_t _size_ = (size); \ - _new_ = alloca_align(_size_, (align)); \ - (void*)memset(_new_, 0, _size_); \ + size_t _xsize_ = (size); \ + _new_ = alloca_align(_xsize_, (align)); \ + (void*)memset(_new_, 0, _xsize_); \ }) /* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to