Skip to content

Commit 2724b47

Browse files
authored
Handle allocation failures (#63)
Print an error message and exit if memprof fails to allocate memory, instead of crashing: memprof: System out of memory, try lowering memory_limit Ideally we would also dump the memory profile, if in dump_on_limit mode, but since this situation is avoidable by lowering the memory_limit, this is good enough for now.
1 parent 6d18522 commit 2724b47

File tree

1 file changed

+27
-6
lines changed

1 file changed

+27
-6
lines changed

memprof.c

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,27 @@ static zend_mm_heap * orig_zheap = NULL;
237237
#define ALLOC_LIST_INSERT_HEAD(head, elem) alloc_list_insert_head(head, elem)
238238
#define ALLOC_LIST_REMOVE(elem) alloc_list_remove(elem)
239239

240+
static void out_of_memory() {
241+
fprintf(stderr, "memprof: System out of memory, try lowering memory_limit\n");
242+
exit(1);
243+
}
244+
245+
static inline void * malloc_check(size_t size) {
246+
void * ptr = malloc(size);
247+
if (UNEXPECTED(ptr == NULL)) {
248+
out_of_memory();
249+
}
250+
return ptr;
251+
}
252+
253+
static inline void * realloc_check(void * ptr, size_t size) {
254+
void * newptr = realloc(ptr, size);
255+
if (UNEXPECTED(newptr == NULL)) {
256+
out_of_memory();
257+
}
258+
return newptr;
259+
}
260+
240261
static inline void alloc_init(alloc * alloc, size_t size) {
241262
alloc->size = size;
242263
alloc->list.le_next = NULL;
@@ -310,10 +331,10 @@ static void alloc_buckets_grow(alloc_buckets * buckets)
310331
alloc_bucket_item * bucket;
311332

312333
buckets->nbuckets++;
313-
buckets->buckets = realloc(buckets->buckets, sizeof(*buckets->buckets)*buckets->nbuckets);
334+
buckets->buckets = realloc_check(buckets->buckets, sizeof(*buckets->buckets)*buckets->nbuckets);
314335

315336
buckets->growsize <<= 1;
316-
bucket = malloc(sizeof(*bucket)*buckets->growsize);
337+
bucket = malloc_check(sizeof(*bucket)*buckets->growsize);
317338
buckets->buckets[buckets->nbuckets-1] = bucket;
318339

319340
for (i = 1; i < buckets->growsize; ++i) {
@@ -389,7 +410,7 @@ static void frame_dtor(zval * pDest)
389410
static void init_frame(frame * f, frame * prev, char * name, size_t name_len)
390411
{
391412
zend_hash_init(&f->next_cache, 0, NULL, frame_dtor, 0);
392-
f->name = malloc(name_len+1);
413+
f->name = malloc_check(name_len+1);
393414
memcpy(f->name, name, name_len+1);
394415
f->name_len = name_len;
395416
f->calls = 0;
@@ -399,7 +420,7 @@ static void init_frame(frame * f, frame * prev, char * name, size_t name_len)
399420

400421
static frame * new_frame(frame * prev, char * name, size_t name_len)
401422
{
402-
frame * f = malloc(sizeof(*f));
423+
frame * f = malloc_check(sizeof(*f));
403424
init_frame(f, prev, name, name_len);
404425
return f;
405426
}
@@ -484,7 +505,7 @@ static void * malloc_hook(size_t size, const void *caller)
484505

485506
WITHOUT_MALLOC_HOOKS {
486507

487-
result = malloc(size);
508+
result = malloc_check(size);
488509
if (result != NULL) {
489510
alloc * a = alloc_buckets_alloc(&current_alloc_buckets, size);
490511
if (track_mallocs) {
@@ -878,7 +899,7 @@ static void memprof_enable(memprof_profile_flags * pf)
878899
/* There is no way to completely free a zend_mm_heap with custom
879900
* handlers, so we have to allocate it ourselves. We don't know the
880901
* actual size of a _zend_mm_heap struct, but this should be enough. */
881-
zheap = malloc(zend_mm_heap_size);
902+
zheap = malloc_check(zend_mm_heap_size);
882903
memset(zheap, 0, zend_mm_heap_size);
883904
zend_mm_set_custom_handlers(zheap, zend_malloc_handler, zend_free_handler, zend_realloc_handler);
884905
orig_zheap = zend_mm_set_heap(zheap);

0 commit comments

Comments
 (0)