summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Williamson <khw@cpan.org>2020-11-25 18:20:28 -0700
committerSteve Hay <steve.m.hay@googlemail.com>2021-01-09 12:14:56 +0000
commit4190e73eba88675cc39af83a5c4ac5905e42c7e5 (patch)
tree90bf111d8c96b62a4d6ac76327e9bcabc556610d
parent922143f2c5dcd5cc6a0bbea393aee2dd3a2ff523 (diff)
downloadperl-4190e73eba88675cc39af83a5c4ac5905e42c7e5.tar.gz
Avoid deadlock with PERL_MEM_LOG
This fixes GH #18341 The Perl wrapper for getenv() was changed in 5.32 to allocate memory to squirrel safely away the result of the wrapped getenv() call. It does this while in a critical section so as to make sure another thread can't interrupt it and destroy it. Unfortunately, when Perl is compiled for debugging memory problems and has PERL_MEM_LOG enabled, that allocation causes a recursive call to getenv() for the purpose of checking an environment variable to see how to log that allocation. And hence it deadlocks trying to enter the critical section. There are various solutions. One is to use or emulate a general semaphore instead of a binary one. This is effectively what PL_lc_numeric_mutex_depth does for another mutex, and the code for that could be used as a template. But given that this is an extreme edge case which requires Perl to be specially compiled to enable this feature which is used only for debugging, a much simpler, if less safe if it were to ever be used in production, solution should suffice. Tony Cook suggested just avoiding the wrapper for this particular purpose. (cherry picked from commit 0cc28fe31b0d416e9c67ecd18b8f38c5833a455a)
-rw-r--r--util.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/util.c b/util.c
index c64e88ddc1..b52f00d4b6 100644
--- a/util.c
+++ b/util.c
@@ -4790,7 +4790,11 @@ S_mem_log_common(enum mem_log_type mlt, const UV n,
PERL_ARGS_ASSERT_MEM_LOG_COMMON;
- pmlenv = PerlEnv_getenv("PERL_MEM_LOG");
+ /* Use plain getenv() to avoid potential deadlock with PerlEnv_getenv().
+ * This means that 'pmlenv' is not protected from other threads overwriting
+ * it on platforms where getenv() returns an internal static pointer. See
+ * GH #18341 */
+ pmlenv = getenv("PERL_MEM_LOG");
if (!pmlenv)
return;
if (mlt < MLT_NEW_SV ? strchr(pmlenv,'m') : strchr(pmlenv,'s'))