From 67e42a95fc4e59e4bdc094200f21db711919c692 Mon Sep 17 00:00:00 2001 From: Peter Bex Date: Sat, 16 Sep 2017 21:03:33 +0200 Subject: [PATCH] Pre-allocate profile bucket to avoid malloc() in signal handler This can cause deadlock because malloc() is not reentrant, see #1414. --- NEWS | 4 ++++ runtime.c | 28 ++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 46420a00..9b756319 100644 --- a/NEWS +++ b/NEWS @@ -124,6 +124,10 @@ - Large literals no longer crash with "invalid encoded numeric literal" on mingw-64 (#1344, thanks to Lemonboy). +- Runtime system: + - The profiler no longer uses malloc from a signal handler which may + cause deadlocks (#1414, thanks to Lemonboy). + - Syntax expander - Renaming an identifier twice no longer results in an undo of the rename (fixes #1362, thanks to "megane"). diff --git a/runtime.c b/runtime.c index ae032f3a..dd78336b 100644 --- a/runtime.c +++ b/runtime.c @@ -473,7 +473,9 @@ static C_TLS FINALIZER_NODE static C_TLS void *current_module_handle; static C_TLS int flonum_print_precision = FLONUM_PRINT_PRECISION; static C_TLS HDUMP_BUCKET **hdump_table; -static C_TLS PROFILE_BUCKET **profile_table = NULL; +static C_TLS PROFILE_BUCKET + *next_profile_bucket = NULL, + **profile_table = NULL; static C_TLS int pending_interrupts[ MAX_PENDING_INTERRUPTS ], pending_interrupts_count, @@ -4391,10 +4393,10 @@ static void take_profile_sample() } /* Not found, allocate a new item and use it as bucket's new head */ - b = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET)); + b = next_profile_bucket; + next_profile_bucket = NULL; - if(b == NULL) - panic(C_text("out of memory - cannot allocate profile table-bucket")); + assert(b != NULL); b->next = *bp; b->key = key; @@ -4415,6 +4417,16 @@ C_regparm void C_fcall C_trace(C_char *name) C_fputc('\n', C_stderr); } + /* When profiling, pre-allocate profile bucket if necessary. This + * is used in the signal handler, because it may not malloc. + */ + if(profiling && next_profile_bucket == NULL) { + next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET)); + if (next_profile_bucket == NULL) { + panic(C_text("out of memory - cannot allocate profile table-bucket")); + } + } + if(trace_buffer_top >= trace_buffer_limit) { trace_buffer_top = trace_buffer; trace_buffer_full = 1; @@ -4430,6 +4442,14 @@ C_regparm void C_fcall C_trace(C_char *name) C_regparm C_word C_fcall C_emit_trace_info2(char *raw, C_word x, C_word y, C_word t) { + /* See above */ + if(profiling && next_profile_bucket == NULL) { + next_profile_bucket = (PROFILE_BUCKET *)C_malloc(sizeof(PROFILE_BUCKET)); + if (next_profile_bucket == NULL) { + panic(C_text("out of memory - cannot allocate profile table-bucket")); + } + } + if(trace_buffer_top >= trace_buffer_limit) { trace_buffer_top = trace_buffer; trace_buffer_full = 1; -- 2.11.0