From dda8901294d4c820b125c8b13ae6c219b57840ee Mon Sep 17 00:00:00 2001
From: Cheng Shao <terrorjack@type.dance>
Date: Thu, 22 Feb 2024 13:47:54 +0000
Subject: [PATCH] rts: add missing ccs_mutex guard to internal_dlopen

See added comment for details. Closes #24423.

(cherry picked from commit 20f80b775971a4fc08397c9b569f2b72c34cad5b)
---
 rts/Linker.c    | 19 +++++++++++++++++++
 rts/Profiling.c |  2 +-
 rts/Profiling.h |  4 ++++
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/rts/Linker.c b/rts/Linker.c
index 51a10a79a6a..9a9051d8821 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -598,8 +598,27 @@ internal_dlopen(const char *dll_name)
    // (see POSIX also)
 
    ACQUIRE_LOCK(&dl_mutex);
+
+   // When dlopen() loads a profiled dynamic library, it calls the
+   // ctors which will call registerCcsList() to append the defined
+   // CostCentreStacks to CCS_LIST. This execution path starting from
+   // addDLL() was only protected by dl_mutex previously. However,
+   // another thread may be doing other things with the RTS linker
+   // that transitively calls refreshProfilingCCSs() which also
+   // accesses CCS_LIST, and those execution paths are protected by
+   // linker_mutex. So there's a risk of data race that may lead to
+   // segfaults (#24423), and we need to ensure the ctors are also
+   // protected by ccs_mutex.
+#if defined(PROFILING)
+   ACQUIRE_LOCK(&ccs_mutex);
+#endif
+
    hdl = dlopen(dll_name, RTLD_LAZY|RTLD_LOCAL); /* see Note [RTLD_LOCAL] */
 
+#if defined(PROFILING)
+   RELEASE_LOCK(&ccs_mutex);
+#endif
+
    errmsg = NULL;
    if (hdl == NULL) {
       /* dlopen failed; return a ptr to the error msg. */
diff --git a/rts/Profiling.c b/rts/Profiling.c
index 9dde1f28604..c3408fb8098 100644
--- a/rts/Profiling.c
+++ b/rts/Profiling.c
@@ -58,7 +58,7 @@ CostCentre      *CC_LIST  = NULL;
 static CostCentreStack *CCS_LIST = NULL;
 
 #if defined(THREADED_RTS)
-static Mutex ccs_mutex;
+Mutex ccs_mutex;
 #endif
 
 /*
diff --git a/rts/Profiling.h b/rts/Profiling.h
index b3724c3c881..d91e2cc9c1b 100644
--- a/rts/Profiling.h
+++ b/rts/Profiling.h
@@ -55,6 +55,10 @@ extern Arena *prof_arena;
 void debugCCS( CostCentreStack *ccs );
 #endif
 
+#if defined(THREADED_RTS)
+extern Mutex ccs_mutex;
+#endif
+
 #endif
 
 #include "EndPrivate.h"
-- 
GitLab