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: