commit: 202d134fb22f2d21ff420b08215e921d42898b93
Author: Sam James <sam <AT> gentoo <DOT> org>
AuthorDate: Thu Dec 18 04:49:16 2025 +0000
Commit: Sam James <sam <AT> gentoo <DOT> org>
CommitDate: Thu Dec 18 04:55:20 2025 +0000
URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=202d134f
dev-libs/boehm-gc: backport crash fix(es) to 8.2.10
Signed-off-by: Sam James <sam <AT> gentoo.org>
dev-libs/boehm-gc/boehm-gc-8.2.10-r1.ebuild | 67 ++++++
.../boehm-gc/files/boehm-gc-8.2.10-crash.patch | 258 +++++++++++++++++++++
2 files changed, 325 insertions(+)
diff --git a/dev-libs/boehm-gc/boehm-gc-8.2.10-r1.ebuild
b/dev-libs/boehm-gc/boehm-gc-8.2.10-r1.ebuild
new file mode 100644
index 000000000000..d3b1a772171c
--- /dev/null
+++ b/dev-libs/boehm-gc/boehm-gc-8.2.10-r1.ebuild
@@ -0,0 +1,67 @@
+# Copyright 1999-2025 Gentoo Authors
+# Distributed under the terms of the GNU General Public License v2
+
+EAPI=8
+
+inherit dot-a multilib-minimal libtool
+
+MY_P="gc-${PV}"
+
+DESCRIPTION="The Boehm-Demers-Weiser conservative garbage collector"
+HOMEPAGE="https://www.hboehm.info/gc/ https://github.com/bdwgc/bdwgc/"
+SRC_URI="https://github.com/bdwgc/bdwgc/releases/download/v${PV}/${MY_P}.tar.gz"
+S="${WORKDIR}/${MY_P}"
+
+LICENSE="boehm-gc"
+# SONAME: libgc.so.1 libgccpp.so.1
+# We've been using subslot 0 for these instead of "1.1".
+SLOT="0"
+# Don't keyword versions if upstream mark them as pre-release.
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~loong ~mips ~ppc ~ppc64 ~riscv
~s390 ~sparc ~x86 ~amd64-linux ~x86-linux ~arm64-macos ~x64-macos ~x64-solaris"
+IUSE="cxx +large static-libs +threads"
+
+RDEPEND=">=dev-libs/libatomic_ops-7.4[${MULTILIB_USEDEP}]"
+DEPEND="${RDEPEND}"
+BDEPEND="virtual/pkgconfig"
+
+PATCHES=(
+ "${FILESDIR}"/${PN}-8.2.10-crash.patch
+)
+
+src_prepare() {
+ default
+
+ # bug #594754
+ elibtoolize
+}
+
+src_configure() {
+ use static-libs && lto-guarantee-fat
+ multilib-minimal_src_configure
+}
+
+multilib_src_configure() {
+ local config=(
+ --disable-docs
+ --with-libatomic-ops
+ $(use_enable cxx cplusplus)
+ $(use_enable static-libs static)
+ $(use threads || echo --disable-threads)
+ $(use_enable large large-config)
+ )
+
+ ECONF_SOURCE="${S}" econf "${config[@]}"
+}
+
+multilib_src_install_all() {
+ local HTML_DOCS=( doc/*.md )
+ einstalldocs
+ dodoc doc/README{.environment,.linux,.macros}
+
+ # Package provides .pc files
+ find "${ED}" -name '*.la' -delete || die
+
+ newman doc/gc.man GC_malloc.1
+
+ strip-lto-bytecode
+}
diff --git a/dev-libs/boehm-gc/files/boehm-gc-8.2.10-crash.patch
b/dev-libs/boehm-gc/files/boehm-gc-8.2.10-crash.patch
new file mode 100644
index 000000000000..be9986e52a96
--- /dev/null
+++ b/dev-libs/boehm-gc/files/boehm-gc-8.2.10-crash.patch
@@ -0,0 +1,258 @@
+https://github.com/bdwgc/bdwgc/issues/783
+https://github.com/bdwgc/bdwgc/issues/802
+https://github.com/bdwgc/bdwgc/commit/910b4f008f3bcb436a23a2d5f9784e5dd9ab66cd
+https://github.com/bdwgc/bdwgc/commit/1058994bc264dd99a7b6d3caefe0c129bfbd1fb7
+https://github.com/bdwgc/bdwgc/commit/73fdfdaf45fd35993c7f9e051875147ca39438c4
+
+From 910b4f008f3bcb436a23a2d5f9784e5dd9ab66cd Mon Sep 17 00:00:00 2001
+From: Ivan Maidanski <[email protected]>
+Date: Sat, 25 Oct 2025 23:19:33 +0300
+Subject: [PATCH] Fix SIGSEGV in remove_all_threads_but_me if fork from
+ unregistered thread (a cherry-pick of commit 44fbb3b9e from 'master')
+
+Issue #783 (bdwgc).
+
+Some clients call `fork()` from an unregistered thread, thus we might
+find no entry for the current thread in `GC_remove_all_threads_but_me`.
+
+* include/gc.h (GC_atfork_child): Add comment about `fork()` from
+an unregistered thread.
+* pthread_support.c [CAN_HANDLE_FORK] (GC_remove_all_threads_but_me):
+If `me` is null, then return immediately after loop (instead of `ABORT`
+or the assertion, regardless of `CPPCHECK` and `LINT2`).
+* win32_threads.c [CAN_HANDLE_FORK] (GC_remove_all_threads_but_me):
+Likewise.
+---
+ include/gc.h | 1 +
+ pthread_support.c | 19 ++++++++-----------
+ win32_threads.c | 4 +++-
+ 3 files changed, 12 insertions(+), 12 deletions(-)
+
+diff --git a/include/gc.h b/include/gc.h
+index 54d704a06..b929240fc 100644
+--- a/include/gc.h
++++ b/include/gc.h
+@@ -512,6 +512,7 @@ GC_API void GC_CALL GC_set_handle_fork(int);
+ /* non-zero); GC_atfork_child is to be called immediately in the child */
+ /* branch (i.e., fork result is 0). Note that GC_atfork_child() call */
+ /* should, of course, precede GC_start_mark_threads call (if any). */
++/* Note that fork() could be called from an unregistered thread. */
+ GC_API void GC_CALL GC_atfork_prepare(void);
+ GC_API void GC_CALL GC_atfork_parent(void);
+ GC_API void GC_CALL GC_atfork_child(void);
+diff --git a/pthread_support.c b/pthread_support.c
+index dbde77f25..0efbcdd9c 100644
+--- a/pthread_support.c
++++ b/pthread_support.c
+@@ -829,11 +829,11 @@ GC_API void GC_CALL GC_register_altstack(void *stack,
GC_word stack_size,
+ GC_threads[hv] = me;
+ }
+
+-/* Remove all entries from the GC_threads table, except the one for */
+-/* the current thread. Also update thread identifiers stored in */
+-/* the table for the current thread. We need to do this in the */
+-/* child process after a fork(), since only the current thread */
+-/* survives in the child. */
++/* Remove all entries from the GC_threads table, except the one (if */
++/* any) for the current thread. Also update thread identifiers */
++/* stored in the table for the current thread. We need to do this */
++/* in the child process after a fork(), since only the current */
++/* thread survives in the child. */
+ STATIC void GC_remove_all_threads_but_me(void)
+ {
+ int hv;
+@@ -870,12 +870,9 @@ STATIC void GC_remove_all_threads_but_me(void)
+ store_to_threads_table(hv, NULL);
+ }
+
+-# if defined(CPPCHECK) || defined(LINT2)
+- if (NULL == me)
+- ABORT("Current thread is not found after fork");
+-# else
+- GC_ASSERT(me != NULL);
+-# endif
++ if (NULL == me)
++ return; /* fork() is called from an unregistered thread */
++
+ /* Update pthread's id as it is not guaranteed to be the same */
+ /* between this (child) process and the parent one. */
+ me -> id = pthread_self();
+diff --git a/win32_threads.c b/win32_threads.c
+index d1b7d5dbe..0335085ed 100644
+--- a/win32_threads.c
++++ b/win32_threads.c
+@@ -1185,8 +1185,10 @@ GC_API void * GC_CALL GC_get_my_stackbottom(struct
GC_stack_base *sb)
+ GC_threads[hv] = NULL;
+ }
+
++ if (NULL == me)
++ return; /* fork() is called from an unregistered thread */
++
+ /* Put "me" back to GC_threads. */
+- GC_ASSERT(me != NULL);
+ thread_id = GetCurrentThreadId(); /* differs from that in parent */
+ GC_threads[THREAD_TABLE_INDEX(thread_id)] = me;
+
+
+From 1058994bc264dd99a7b6d3caefe0c129bfbd1fb7 Mon Sep 17 00:00:00 2001
+From: Ivan Maidanski <[email protected]>
+Date: Thu, 30 Oct 2025 23:39:44 +0300
+Subject: [PATCH] Fix code defect of LOCK/UNLOCK in separate 'if' in
+ GC_generic_malloc_many (a cherry-pick of commit c7d342c83 from 'master')
+
+* mallocx.c [PARALLEL_MARK] (GC_generic_malloc_many): Check
+`GC_parallel` once around `GC_reclaim_generic()` call (so that
+nearby `UNLOCK()` and the following `LOCK()` to be placed inside
+a single `if` statement block).
+---
+ mallocx.c | 82 +++++++++++++++++++++++++++----------------------------
+ 1 file changed, 41 insertions(+), 41 deletions(-)
+
+diff --git a/mallocx.c b/mallocx.c
+index 340bd5231..927008958 100644
+--- a/mallocx.c
++++ b/mallocx.c
+@@ -374,54 +374,54 @@ GC_API void GC_CALL GC_generic_malloc_many(size_t lb,
int k, void **result)
+ ++ GC_fl_builder_count;
+ UNLOCK();
+ GC_release_mark_lock();
+- }
+-# endif
+- op = GC_reclaim_generic(hbp, hhdr, lb,
+- ok -> ok_init, 0, &my_bytes_allocd);
+- if (op != 0) {
+-# ifdef PARALLEL_MARK
+- if (GC_parallel) {
+- *result = op;
+- (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
+- (AO_t)my_bytes_allocd);
++
++ op = GC_reclaim_generic(hbp, hhdr, lb, ok -> ok_init, NULL,
++ &my_bytes_allocd);
++ if (op != NULL) {
++ *result = op;
++ (void)AO_fetch_and_add(&GC_bytes_allocd_tmp,
++ (AO_t)my_bytes_allocd);
++ GC_acquire_mark_lock();
++ -- GC_fl_builder_count;
++ if (GC_fl_builder_count == 0) GC_notify_all_builder();
++# ifdef THREAD_SANITIZER
++ GC_release_mark_lock();
++ LOCK();
++ GC_bytes_found += my_bytes_allocd;
++ UNLOCK();
++# else
++ GC_bytes_found += my_bytes_allocd;
++ /* The result may be inaccurate. */
++ GC_release_mark_lock();
++# endif
++ (void) GC_clear_stack(0);
++ return;
++ }
++
+ GC_acquire_mark_lock();
+ -- GC_fl_builder_count;
+ if (GC_fl_builder_count == 0) GC_notify_all_builder();
+-# ifdef THREAD_SANITIZER
+- GC_release_mark_lock();
+- LOCK();
+- GC_bytes_found += my_bytes_allocd;
+- UNLOCK();
+-# else
+- GC_bytes_found += my_bytes_allocd;
+- /* The result may be inaccurate. */
+- GC_release_mark_lock();
+-# endif
+- (void) GC_clear_stack(0);
+- return;
+- }
+-# endif
+- /* We also reclaimed memory, so we need to adjust */
+- /* that count. */
++ GC_release_mark_lock();
++ LOCK();
++ /* GC lock is needed for reclaim list access. We */
++ /* must decrement fl_builder_count before reacquiring */
++ /* the lock. Hopefully this path is rare. */
++
++ rlh = ok -> ok_reclaim_list; /* reload rlh after locking */
++ if (NULL == rlh) break;
++ continue;
++ }
++# endif
++
++ op = GC_reclaim_generic(hbp, hhdr, lb, ok -> ok_init, NULL,
++ &my_bytes_allocd);
++ if (op != NULL) {
++ /* We also reclaimed memory, so we need to adjust */
++ /* that count. */
+ GC_bytes_found += my_bytes_allocd;
+ GC_bytes_allocd += my_bytes_allocd;
+ goto out;
+ }
+-# ifdef PARALLEL_MARK
+- if (GC_parallel) {
+- GC_acquire_mark_lock();
+- -- GC_fl_builder_count;
+- if (GC_fl_builder_count == 0) GC_notify_all_builder();
+- GC_release_mark_lock();
+- LOCK();
+- /* GC lock is needed for reclaim list access. We */
+- /* must decrement fl_builder_count before reacquiring */
+- /* the lock. Hopefully this path is rare. */
+-
+- rlh = ok -> ok_reclaim_list; /* reload rlh after locking */
+- if (NULL == rlh) break;
+- }
+-# endif
+ }
+ }
+ /* Next try to use prefix of global free list if there is one. */
+From 73fdfdaf45fd35993c7f9e051875147ca39438c4 Mon Sep 17 00:00:00 2001
+From: Ivan Maidanski <[email protected]>
+Date: Fri, 31 Oct 2025 22:44:52 +0300
+Subject: [PATCH] Fix SIGSEGV if pthread_detach is called before collector
+ initialization (a cherry-pick of commit e40697e26 from 'master')
+
+The only case this seems to be needed is when the client calls
+`pthread_detach(pthread_self())` before the collector initialization.
+
+* pthread_support.c [!SN_TARGET_ORBIS && !SN_TARGET_PSP2]
+(GC_pthread_detach): Call `GC_init()` if the collector is not
+initialized; add comment.
+* win32_threads.c [GC_PTHREADS] (GC_pthread_detach): Likewise.
+---
+ pthread_support.c | 7 +++++++
+ win32_threads.c | 1 +
+ 2 files changed, 8 insertions(+)
+
+diff --git a/pthread_support.c b/pthread_support.c
+index 0efbcdd9c..fb09f3d17 100644
+--- a/pthread_support.c
++++ b/pthread_support.c
+@@ -2016,6 +2016,13 @@ GC_INNER_PTHRSTART void GC_thread_exit_proc(void *arg)
+ DCL_LOCK_STATE;
+
+ INIT_REAL_SYMS();
++ if (!EXPECT(GC_is_initialized, TRUE)) {
++ /*
++ * The only case this seems to be needed is when the client calls
++ * pthread_detach(pthread_self()) before the collector initialization.
++ */
++ GC_init();
++ }
+ LOCK();
+ t = (GC_thread)COVERT_DATAFLOW(GC_lookup_thread(thread));
+ UNLOCK();
+diff --git a/win32_threads.c b/win32_threads.c
+index 0335085ed..0ec33cf95 100644
+--- a/win32_threads.c
++++ b/win32_threads.c
+@@ -3257,6 +3257,7 @@ GC_INNER void GC_thr_init(void)
+ GC_thread t;
+ DCL_LOCK_STATE;
+
++ if (!EXPECT(GC_is_initialized, TRUE)) GC_init();
+ GC_ASSERT(!GC_win32_dll_threads);
+ t = GC_lookup_pthread(thread);
+ result = pthread_detach(thread);