Bug 150959

Summary: [libc] Stub pthread_once in libc should call _libc_once
Product: Base System Reporter: Kenton Varda <temporal>
Component: threadsAssignee: freebsd-threads (Nobody) <threads>
Status: Open ---    
Severity: Affects Only Me CC: andrew, emaste
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Kenton Varda 2010-09-26 08:10:05 UTC
libc.so defines a "stub" version of pthread_once().  Unfortunately, the stub version simply returns zero (success) without ever calling the init function, which does not satisfy the contract of pthread_once.

The effect of this is that if code which uses pthread_once is accidentally linked without libpthread, the code's attempts to initialize data structures using pthread_once will silently fail, probably leading to unexpected and hard-to-debug crashes or other problems.  When debugging this code, the developer may figure out easily enough that pthread_once() is not functioning, but is unlikely to realize that this is because he has not linked against libpthread -- most developers would expect to have seen a linker error if this were the problem.

This also makes it difficult for developers to write libraries which are thread-safe without requiring a threading implementation.  Many libraries have no need to spawn threads of their own, but do need to be safe to use in a multi-threaded program.  These libraries may thus need to use pthread_once to initialize internal data structures.  Unfortunately, this currently means that any program using such a library must link against libpthread whether or not the program actually uses threads.  It would be convenient if such code could simply rely on the libc pthread stubs instead.

Fix: 

The basic fix is trivial:  Have the pthread_once stub (defined in lib/libc/gen/_pthread_stubs.c) call _libc_once (defined in lib/libc/gen/_once_stub.c) instead of just returning zero.

It appears that this was tried before, but reverted:

http://svn.freebsd.org/viewvc/base?view=revision&revision=199614

From the revision description, it seems that libstdc++ has unfortunately decided to rely on the pthread_once stub's incorrect behavior as a way to detect whether libpthread has been linked.  This seems like a very poor choice on libstdc++'s part; it should be fixed to avoid depending on this behavior.

Another possibility would be to return a non-zero error code.  This would at least let the caller know that pthread_once() did not correctly perform its documented behavior.
How-To-Repeat: 1. Write a small program that uses pthread_once().
2. Compile and link without libpthread.
3. Observe that linking succeeds, but at runtime the init function is never called.
Comment 1 Alexander Best freebsd_committer freebsd_triage 2010-09-26 18:08:28 UTC
Responsible Changed
From-To: freebsd-bugs->freebsd-threads

Over to maintainer(s).
Comment 2 John Baldwin freebsd_committer freebsd_triage 2011-05-16 14:57:38 UTC
FWIW, I would also prefer that we fix libstdc++ to not depend on this 
misfeature and properly implement pthread_once() using _libc_once() in 
the non-threaded case as well.

One advantage of fixing libstdc++ to honor __isthreaded would be that 
single threaded C++ apps that linked against libthr (due to using 3rd 
party libraries that can use threads but the specific app doesn't enable 
that, e.g. protobuf) would not always use locks unnecessarily in all of 
libstdc++.

-- 
John Baldwin
Comment 3 Mark Linimon 2013-02-28 09:46:03 UTC
apparently this email never made it into the audit-trail

----- Forwarded message from John Baldwin <jhb@freebsd.org> -----

Date: Mon, 27 Sep 2010 11:46:27 -0400
From: John Baldwin <jhb@freebsd.org>
To: freebsd-threads@freebsd.org
Cc: arundel@freebsd.org, freebsd-bugs@freebsd.org
Subject: Re: misc/150959: [libc] Stub pthread_once in libc should call
	_libc_once
User-Agent: KMail/1.13.5 (FreeBSD/7.3-CBSD-20100819; KDE/4.4.5; amd64; ; )

On Sunday, September 26, 2010 1:11:52 pm arundel@freebsd.org wrote:
> Old Synopsis: Stub pthread_once in libc should call _libc_once
> New Synopsis: [libc] Stub pthread_once in libc should call _libc_once
> 
> Responsible-Changed-From-To: freebsd-bugs->freebsd-threads
> Responsible-Changed-By: arundel
> Responsible-Changed-When: Sun Sep 26 17:08:28 UTC 2010
> Responsible-Changed-Why: 
> Over to maintainer(s).

As you note in the history, libstdc++ depends on this behavior, so it is not 
likely to be changed.  Possibly changing the stub to always return an error 
would be ok, except that POSIX defines no errors for pthread_once().  Note 
that this behavior also matches Solaris apparently:

(From /usr/include/c++/4.2/bits/gthr-default.h)

#if __GXX_WEAK__ && _GLIBCXX_GTHREAD_USE_WEAK

/* On Solaris 2.6 up to 9, the libc exposes a POSIX threads interface even if
   -pthreads is not specified.  The functions are dummies and most return an
   error value.  However pthread_once returns 0 without invoking the routine
   it is passed so we cannot pretend that the interface is active if -pthreads
   is not specified.  On Solaris 2.5.1, the interface is not exposed at all so
   we need to play the usual game with weak symbols.  On Solaris 10 and up, a
   working interface is always exposed.  On FreeBSD 6 and later, libc also
   exposes a dummy POSIX threads interface, similar to what Solaris 2.6 up
   to 9 does.  FreeBSD >= 700014 even provides a pthread_cancel stub in libc,
   which means the alternate __gthread_active_p below cannot be used there.  
*/

#if defined(__FreeBSD__) || (defined(__sun) && defined(__svr4__))

To be honest, I would favor libc exporting '__isthreaded' in some fashion so 
that libstdc++ could depend on that instead.  I think the symbol is already 
public so that libthr can set it.

-- 
John Baldwin
_______________________________________________
freebsd-threads@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-threads
To unsubscribe, send any mail to "freebsd-threads-unsubscribe@freebsd.org"


----- End forwarded message -----
Comment 4 Eitan Adler freebsd_committer freebsd_triage 2017-12-31 07:59:52 UTC
For bugs matching the following criteria:

Status: In Progress Changed: (is less than) 2014-06-01

Reset to default assignee and clear in-progress tags.

Mail being skipped
Comment 5 Andrew "RhodiumToad" Gierth 2019-08-31 11:52:36 UTC
The current stub implementation of pthread_once now fails with an error return, which does not seem much of an improvement.

In particular, it causes code that is static-linked with openssl to segfault unless libthr is linked into the process (the fact that openssl has inadequate error checks is a separate issue).

I've been told in another bug thread that the only reason to have pthread stubs at all is to allow for libraries that might be dynamically loaded into either a threaded or unthreaded process. It seems to me that such libraries would be very likely to want to use pthread_once, and very unlikely to be able to cope with it failing (it has no normal reason to fail).

Accordingly, libc should provide either a pthread_once stub that actually works (interoperably with the real implementation in case libthr gets pulled in later), or it should not provide the symbol at all, forcing libraries that want to use it to pull in libthr themselves.

see also https://twitter.com/RhodiumToad/status/1165523338481061888