GNU bug report logs -
#79100
segfault with thread initialization
Previous Next
To reply to this bug, email your comments to 79100 AT debbugs.gnu.org.
Toggle the display of automated, internal messages from the tracker.
Report forwarded
to
bug-guile <at> gnu.org:
bug#79100; Package
guile.
(Sat, 26 Jul 2025 05:56:01 GMT)
Full text and
rfc822 format available.
Acknowledgement sent
to
a aa <lgray3420 <at> gmail.com>:
New bug report received and forwarded. Copy sent to
bug-guile <at> gnu.org.
(Sat, 26 Jul 2025 05:56:01 GMT)
Full text and
rfc822 format available.
Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
# version
3.0.10
# `config.guess`
x86_64-pc-linux-gnu
# `config.status`
`--prefix=/usr --build=x86_64-pc-linux-gnu --host=x86_64-pc-linux-gnu
--mandir=/usr/share/man --infodir=/usr/share/info --datadir=/usr/share
--sysconfdir=/etc --localstatedir=/var/lib --datarootdir=/usr/share
--disable-dependency-tracking --disable-silent-rules --disable-static
--docdir=/usr/share/doc/guile-3.0.10-r103
--htmldir=/usr/share/doc/guile-3.0.10-r103/html --with-sysroot=/
--libdir=/usr/lib64 --program-suffix=-3.0
--infodir=/usr/share/guile-data/3.0/info
--with-pkgconfigdir=/usr/share/guile-data/3.0/pkgconfig
--disable-error-on-warning --disable-rpath --disable-lto --enable-posix
--without-libgmp-prefix --without-libiconv-prefix --without-libintl-prefix
--without-libreadline-prefix --without-libunistring-prefix
--disable-guile-debug --disable-debug-malloc --enable-deprecated
--enable-jit --enable-networking --disable-nls --enable-regex
--with-threads build_alias=x86_64-pc-linux-gnu
host_alias=x86_64-pc-linux-gnu CC=gcc 'CFLAGS=-O2 -march=native -pipe
-std=gnu17' LDFLAGS=-fuse-ld=mold
PKG_CONFIG_PATH=/usr/share/guile-data/3.0/pkgconfig`
# How to reproduce
```c
#include <libguile.h>
#include <pthread.h>
void* foo(void*) {
return NULL;
}
void* run_with_guile(void*)
{
scm_with_guile(foo, NULL);
return NULL;
}
int main(void)
{
pthread_t thread_1, thread_2;
pthread_create(&thread_1, NULL, run_with_guile, NULL);
pthread_create(&thread_2, NULL, run_with_guile, NULL);
pthread_join(thread_1, NULL);
pthread_join(thread_2, NULL);
return 0;
}
```
## Output
```txt
Segmentation fault
```
# Intended behaviour
According to the [documentation](
https://www.gnu.org/software/guile/manual/html_node/Guile-Initialization-Functions.html),
you should be able to call `scm_with_guile` concurrently.
[Message part 2 (text/html, inline)]
Information forwarded
to
bug-guile <at> gnu.org:
bug#79100; Package
guile.
(Tue, 02 Sep 2025 20:39:02 GMT)
Full text and
rfc822 format available.
Message #8 received at 79100 <at> debbugs.gnu.org (full text, mbox):
[Message part 1 (text/plain, inline)]
a aa <lgray3420 <at> gmail.com> writes:
> # Intended behaviour
> According to the [documentation](
> https://www.gnu.org/software/guile/manual/html_node/Guile-Initialization-Functions.html),
> you should be able to call `scm_with_guile` concurrently.
It looks like this is an issue in thread.c when multiple threads are
racing, before guile has been initialized, with respect to
scm_i_init_thread_for_guile. All of them will have a dynamic_state value
that came from default_dynamic_state, which is 0L at startup. One of
them will get the scm_i_init_mutex and initialize guile, which will set
the default_dynamic_state to SCM_BOOL_F via scm_init_threads.
Then, when the thread that initialized guile releases scm_i_init_mutex,
the other threads will proceed, pass the stale 0L to guilify_self_2, and
segfault in the is_dynamic_state call in scm_set_current_dynamic_state:
(gdb) where
#0 0x00007ffff7ed4eb6 in is_dynamic_state (x=0x0)
at .../src/guile/up/main/libguile/fluids.c:108
#1 scm_set_current_dynamic_state (state=0x0)
at .../src/guile/up/main/libguile/fluids.c:624
#2 0x00007ffff7f4476d in guilify_self_2 (dynamic_state=dynamic_state <at> entry=0x0)
at .../src/guile/up/main/libguile/threads.c:449
#3 0x00007ffff7f48b28 in scm_i_init_thread_for_guile (base=base <at> entry=0x7ffff7038e60,
dynamic_state=dynamic_state <at> entry=0x0) at .../src/guile/up/main/libguile/threads.c:599
#4 0x00007ffff7f48d56 in scm_i_init_thread_for_guile (base=0x7ffff7038e60, dynamic_state=0x0)
at .../src/guile/up/main/libguile/threads.c:681
#5 with_guile (base=0x7ffff7038e60, data=0x7ffff7038e90)
at .../src/guile/up/main/libguile/threads.c:642
#6 0x00007ffff7c007e4 in GC_call_with_stack_base (fn=fn <at> entry=0x7ffff7f48cb0 <with_guile>,
arg=arg <at> entry=0x7ffff7038e90) at ../extra/../misc.c:2178
#7 0x00007ffff7f41ce8 in scm_i_with_guile (func=<optimized out>, data=<optimized out>,
dynamic_state=<optimized out>) at .../src/guile/up/main/libguile/threads.c:692
#8 scm_with_guile (func=<optimized out>, data=<optimized out>)
at .../src/guile/up/main/libguile/threads.c:698
#9 0x0000555555555188 in run_with_guile () at main.c:10
#10 0x00007ffff7cebb7b in start_thread (arg=<optimized out>) at ./nptl/pthread_create.c:448
#11 0x00007ffff7d697b8 in __GI___clone3 () at ../sysdeps/unix/sysv/linux/x86_64/clone3.S:78
As an aside, I'm also not sure "who" the default_dynamic_state
SCM_BOOL_F value is for (via scm_init_threads).
In any case, you can "fix" the problem by having the other threads
notice that they now have a stale dynamic_state and retrieve a fresh one
like this:
[refresh-init-dynamc-state.diff (text/x-diff, inline)]
diff --git a/libguile/threads.c b/libguile/threads.c
index 6b4510d53..442ce4c45 100644
--- a/libguile/threads.c
+++ b/libguile/threads.c
@@ -368,7 +368,7 @@ static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZE
static scm_thread *all_threads = NULL;
static int thread_count;
-static SCM default_dynamic_state;
+static SCM default_dynamic_state; // Either 0 or SCM_BOOL_F during init
/* Perform first stage of thread initialisation, in non-guile mode.
*/
@@ -595,6 +595,11 @@ scm_i_init_thread_for_guile (struct GC_stack_base *base,
needs_unregister = 1;
#endif
+ // We were blocked while another thread was initializing
+ // guile, so we need to re-read the (now correct) state.
+ if (dynamic_state == 0L || scm_is_eq (dynamic_state, SCM_BOOL_F))
+ dynamic_state = default_dynamic_state;
+
guilify_self_1 (base, needs_unregister);
guilify_self_2 (dynamic_state);
}
[Message part 3 (text/plain, inline)]
which avoids the segfault, but I suspect it may not be the fix we want.
--
Rob Browning
rlb @defaultvalue.org and @debian.org
GPG as of 2011-07-10 E6A9 DA3C C9FD 1FF8 C676 D2C4 C0F0 39E9 ED1B 597A
GPG as of 2002-11-03 14DD 432F AE39 534D B592 F9A0 25C8 D377 8C7E 73A4
This bug report was last modified 63 days ago.
Previous Next
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.