From c03da8f9a4d74192d18ffa205b242d1440b0e730 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 f745b94b..9051f8d1 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,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 b993926b..59e9ee01 100644 --- a/runtime.c +++ b/runtime.c @@ -488,7 +488,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, @@ -3993,10 +3995,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; @@ -4012,6 +4014,16 @@ done: C_regparm void C_fcall C_trace(C_char *name) { + /* 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(show_trace) { C_fputs(name, C_stderr); C_fputc('\n', C_stderr); @@ -4032,6 +4044,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