deadlock due to use of async unsafe setenv after fork
xfce4-terminal deadlocks when built with musl libc (alpine linux).
Backtrace:
__futexwait (priv=128, val=-2147483646, addr=0x7f600bd6707c <__malloc_lock>) at ./arch/x86_64/syscall_arch.h:40
40 ./arch/x86_64/syscall_arch.h: No such file or directory.
(gdb) bt
#0 __futexwait (priv=128, val=-2147483646, addr=0x7f600bd6707c <__malloc_lock>) at ./arch/x86_64/syscall_arch.h:40
#1 __lock (l=l@entry=0x7f600bd6707c <__malloc_lock>) at src/thread/__lock.c:44
#2 0x00007f600bcf4e03 in rdlock () at src/malloc/mallocng/glue.h:63
#3 malloc (n=n@entry=87) at src/malloc/mallocng/malloc.c:337
#4 0x00007f600bd1b541 in vasprintf (s=s@entry=0x7f6007170b40,
fmt=0x7f600af12afc "setenv()/putenv() are not thread-safe and should not be used after threads are created",
ap=ap@entry=0x7f6007170c20) at src/stdio/vasprintf.c:13
#5 0x00007f600af09867 in g_vasprintf (string=string@entry=0x7f6007170b40, format=<optimized out>,
args=args@entry=0x7f6007170c20) at ../glib/gprintf.c:337
#6 0x00007f600aeea86b in g_strdup_vprintf (format=<optimized out>, args=args@entry=0x7f6007170c20) at ../glib/gstrfuncs.c:518
#7 0x00007f600aeda0c8 in g_logv (log_domain=0x7f600af1e6ae "GLib", log_level=G_LOG_LEVEL_DEBUG, format=<optimized out>,
args=args@entry=0x7f6007170c20) at ../glib/gmessages.c:1278
#8 0x00007f600aeda41b in g_log (log_domain=log_domain@entry=0x7f600af1e6ae "GLib",
log_level=log_level@entry=G_LOG_LEVEL_DEBUG,
format=format@entry=0x7f600af12afc "setenv()/putenv() are not thread-safe and should not be used after threads are created") at ../glib/gmessages.c:1415
#9 0x00007f600aec4102 in g_setenv (variable=variable@entry=0x7f600bb91b68 "TERM",
value=value@entry=0x7f600bb91b02 "xterm-256color", overwrite=overwrite@entry=1) at ../glib/genviron.c:307
#10 0x00007f600bb61efc in vte::base::Pty::child_setup (this=<optimized out>) at ../src/pty.cc:246
#11 vte::base::Pty::child_setup (this=0x7f6006ae7530) at ../src/pty.cc:108
#12 0x00007f600bb89052 in do_exec (user_data=0x7f6006ae7530,
child_setup=0x7f600bb61f68 <vte::base::pty_child_setup_cb(void*)>, file_and_argv_zero=1, child_inherits_stdin=1,
stderr_to_null=0, stdout_to_null=0, search_path_from_envp=0, search_path=1, close_descriptors=1, envp=0x7f6006af8fe0,
argv=0x7f6006ae4a00, working_directory=0x7f6006ae7560 "/home/ncopa/aports/community/xfce4-terminal",
stderr_fd=<optimized out>, stdout_fd=<optimized out>, stdin_fd=<optimized out>, child_err_report_fd=12)
at ../src/vtespawn.cc:701
#13 fork_exec_with_pipes (error=0x7f6007170f70, pollfd=0x0, timeout=30000, standard_error=0x0, standard_output=0x0,
standard_input=0x0, child_pid=0x7f6007170f60, user_data=0x7f6006ae7530,
child_setup=0x7f600bb61f68 <vte::base::pty_child_setup_cb(void*)>, cloexec_pipes=0, file_and_argv_zero=1,
child_inherits_stdin=1, stderr_to_null=0, stdout_to_null=0, search_path_from_envp=0, search_path=1, close_descriptors=1,
envp=0x7f6006af8fe0, argv=0x7f6006ae4a00, working_directory=0x7f6006ae7560 "/home/ncopa/aports/community/xfce4-terminal",
intermediate_child=0) at ../src/vtespawn.cc:924
#14 vte_spawn_async_with_pipes_cancellable (
working_directory=working_directory@entry=0x7f6006ae7560 "/home/ncopa/aports/community/xfce4-terminal",
argv=argv@entry=0x7f6006ae4a00, envp=envp@entry=0x7f6006af8fe0,
flags=flags@entry=(G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_FILE_AND_ARGV_ZERO), child_setup=child_setup@entry=0x7f600bb61f68 <vte::base::pty_child_setup_cb(void*)>,
user_data=user_data@entry=0x7f6006ae7530, child_pid=0x7f6007170f60, standard_input=0x0, standard_output=0x0,
standard_error=0x0, timeout=30000, pollfd=0x0, error=0x7f6007170f70) at ../src/vtespawn.cc:221
#15 0x00007f600bb62301 in vte::base::Pty::spawn (this=0x7f6006ae7530,
directory=directory@entry=0x7f6006ae7560 "/home/ncopa/aports/community/xfce4-terminal", argv=argv@entry=0x7f6006ae4a00,
envv=envv@entry=0x7f6006b2be20,
spawn_flags_=spawn_flags_@entry=(G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_FILE_AND_ARGV_ZERO),
child_setup_func=child_setup_func@entry=0x0, child_setup_data=0x0, child_pid=0x7f600717108c, timeout=30000,
cancellable=0x0, error=0x7f6007171090) at ../src/glib-glue.hh:58
#16 0x00007f600bb63280 in _vte_pty_spawn (pty=0x7f6006ae7c40,
directory=0x7f6006ae7560 "/home/ncopa/aports/community/xfce4-terminal", argv=0x7f6006ae4a00, envv=0x7f6006b2be20,
spawn_flags_=(G_SPAWN_SEARCH_PATH | G_SPAWN_CHILD_INHERITS_STDIN | G_SPAWN_FILE_AND_ARGV_ZERO), child_setup=0x0,
child_setup_data=0x0, child_pid=0x7f600717108c, timeout=30000, cancellable=0x0, error=0x7f6007171090)
at ../src/vtepty.cc:188
#17 0x00007f600bb632ee in async_spawn_run_in_thread (task=0x7f6006ce23d0, object=<optimized out>, data_=<optimized out>,
cancellable=<optimized out>) at ../src/vtepty.cc:650
#18 0x00007f600b07bd08 in g_task_thread_pool_thread (thread_data=0x7f6006ce23d0, pool_data=<optimized out>)
at ../gio/gtask.c:1412
#19 0x00007f600aef2989 in g_thread_pool_thread_proxy (data=<optimized out>) at ../glib/gthreadpool.c:354
#20 0x00007f600aef22e1 in g_thread_proxy (data=0x7f600740e980) at ../glib/gthread.c:807
#21 0x00007f600bd2343f in start (p=0x7f6007171130) at src/thread/pthread_create.c:196
#22 0x00007f600bd255fe in __clone () at src/thread/x86_64/clone.s:22
Backtrace stopped: frame did not save the PC
It seems that there are calls to setenv which are not async safe. This is not allowed after fork
and before exec
. (see https://developer.gnome.org/glib/stable/glib-Spawning-Processes.html#GSpawnChildSetupFunc for example)
This patch works around the issue:
diff --git a/src/pty.cc b/src/pty.cc
index 3db1a7c..3c97f6c 100644
--- a/src/pty.cc
+++ b/src/pty.cc
@@ -240,15 +240,6 @@ Pty::child_setup() const noexcept
close(fd);
}
- /* Now set the TERM environment variable */
- /* FIXME: Setting environment here seems to have no effect, the merged envp2 will override on exec.
- * By the way, we'd need to set the one from there, if any. */
- g_setenv("TERM", VTE_TERMINFO_NAME, TRUE);
-
- char version[7];
- g_snprintf (version, sizeof (version), "%u", VTE_VERSION_NUMERIC);
- g_setenv ("VTE_VERSION", version, TRUE);
-
/* Finally call an extra child setup */
if (m_extra_child_setup.func) {
m_extra_child_setup.func(m_extra_child_setup.data);
If setting those env vars are really needed, it should be done by modifying envp
in fork_exec_with_pipes
, before the fork
call. Comment indicates that setting those env vars have no effect anyway, so I think they can simply be removed.
Edited by Natanael Copa