Subject: lib/30169: Calling atexit in atexit handler hangs
To: None <lib-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: J.T. Conklin <jtc@acorntoolworks.com>
List: netbsd-bugs
Date: 05/07/2005 21:37:00
>Number: 30169
>Category: lib
>Synopsis: Calling atexit in atexit hangs
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: lib-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat May 07 21:37:00 +0000 2005
>Originator: J.T. Conklin
>Release: NetBSD 3.0_BETA
>Organization:
J.T. Conklin
>Environment:
System: NetBSD k8 3.0_BETA NetBSD 3.0_BETA (GENERIC) #0: Mon May 2 02:38:27 PDT 2005 jtc@k8:/home/jtc/netbsd/NetBSD-3/obj-amd64/sys/arch/amd64/compile/GENERIC amd64
Architecture: x86_64
Machine: amd64
>Description:
Calling atexit() from a atexit() handler can cause the process to hang.
I encountered this while using the Bullseye Coverage C/C++ test tool.
Its runtime library (which is called by the instrumentation added to
your own code) installs a atexit() handler soto write out results.
But depending on initialization/static constructor/static destructor
order, in some cases the atexit handler is installed again.
I understand that one of the changes in C9X is that registering a
new atexit() handler from within an atexit() handler is no longer
undefined behavior.
I googled up this USENET posting from comp.std.c in response to a
question about recursive atexit() semantics which seems on topic:
http://groups-beta.google.com/group/comp.std.c/msg/35d22e912c368db1
The NetBSD implementation protects the atexit list with a default
mutex, and bad things happen with it's tried to use recursively.
>How-To-Repeat:
This test program hangs.
static void
quux()
{
write(1, "quux\n", 5);
}
static void
bar()
{
write(1, "bar\n", 4);
atexit(quux);
}
static void
foo()
{
write(1, "foo\n", 4);
atexit(bar);
}
static void
sna()
{
write(1, "sna\n", 4);
atexit(bar);
}
main()
{
atexit(sna);
atexit(foo);
}
>Fix:
>Unformatted: