Skip to content

Commit

Permalink
Avoid marking pthread_atfork() as weak if provided by libc_nonshared.a.
Browse files Browse the repository at this point in the history
On Linux, pthread_atfork() is provided not by libpthread.so, but by
libc_nonshared.a (for glibc >= 2.28) or by libpthread_nonshared.a
(for glibc <= 2.27), and using "#pragma weak pthread_atfork" will
cause pthread_atfork to be undefined (and have an address of NULL)
even if the relevant lib*_nonshared.a was explicitly specified to
the linker.  This is explained by this paragraph from Chapter 4,
section "Symbol Table", of the System V ABI specification, as pointed
out by Hugo Grostabussiat:

	When the link editor searches archive libraries [see ``Archive
	File'' in Chapter 7], it extracts archive members that contain
	definitions of undefined global symbols. The member's definition
	may be either a global or a weak symbol. The link editor does
	not extract archive members to resolve undefined weak symbols.
	Unresolved weak symbols have a zero value.

Therefore, if either of these lib*_nonshared.a libraries exists, we
should avoid marking pthread_atfork as weak.

We were doing this correctly for glibc <= 2.27, as we were checking
for libpthread_nonshared.a, but not for libc_nonshared.a, so we would
still mark pthread_atfork as a weak symbol on machines that provide
libc_nonshared.a but not libpthread_nonshared.a, that is, on glibc
>= 2.28 machines without a dummy backward compatibility version of
libpthread_nonshared.a installed.

This patch makes us do the right thing for glibc >= 2.28 as well, and
was derived from patches provided by Rolf Eike Beer <[email protected]>
and Antal Nemes <[email protected]>.

Thanks to Hugo Grostabussiat <[email protected]>, Henrik Grindal
Bakken <[email protected]> and Tomáš Mózes <[email protected]> for the
discussion and testing.

Reported-by: Changqing Li <[email protected]>
Signed-off-by: Lennert Buytenhek <[email protected]>
  • Loading branch information
buytenh committed May 16, 2019
1 parent 8f8eb78 commit a5e9cad
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 13 deletions.
32 changes: 24 additions & 8 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,31 @@ solaris*)
esac

#
# On Linux, linking against libpthread.so.0 doesn't give you
# pthread_atfork(), as the latter is defined in libpthread_nonshared.a,
# which doesn't get pulled in if libpthread.so.0 is pulled in
# indirectly, e.g. via -lrt, but does get pulled in if you link against
# -lpthread, as libpthread.so is a linker script that references both
# libpthread.so.0 and libpthread_nonshared.a. As we can link in
# libpthread_nonshared.a without pulling in libpthread.so.0, explicitly
# link in libpthread_nonshared.a if it is available.
# On Linux, pthread_atfork() is provided not by libpthread.so, but by
# libc_nonshared.a (for glibc >= 2.28) or by libpthread_nonshared.a
# (for glibc <= 2.27), and using "#pragma weak pthread_atfork" will
# cause pthread_atfork to be undefined (and have an address of NULL)
# even if the relevant lib*_nonshared.a was explicitly specified to
# the linker. This is explained by this paragraph from Chapter 4,
# section "Symbol Table", of the System V ABI specification, as pointed
# out by Hugo Grostabussiat:
#
# When the link editor searches archive libraries [see ``Archive
# File'' in Chapter 7], it extracts archive members that contain
# definitions of undefined global symbols. The member's definition
# may be either a global or a weak symbol. The link editor does
# not extract archive members to resolve undefined weak symbols.
# Unresolved weak symbols have a zero value.
#
# Therefore, if either of these lib*_nonshared.a libraries exists, we
# need to make note of this, to avoid marking pthread_atfork as weak.
# Also, if pthread_atfork is provided by libpthread_nonshared.a, we'll
# need to pull that library in explicitly, as we are not necessarily
# linked against libpthread.so.0.
#
AC_CHECK_LIB([c_nonshared], [pthread_atfork],
[AC_DEFINE(HAVE_LIBC_NONSHARED, 1,
Define to 1 if you have the `c_nonshared' library.)])
AC_CHECK_LIB([pthread_nonshared], [pthread_atfork])

# Checks for header files.
Expand Down
10 changes: 5 additions & 5 deletions src/pthr.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,12 @@ static inline int pthreads_available(void)
#ifdef HAVE_PRAGMA_WEAK

/*
* On Linux, pthread_atfork() is defined in libpthread_nonshared.a,
* a static library, and we want to avoid "#pragma weak" for that
* symbol because that causes it to be undefined even if you link
* libpthread_nonshared.a in explicitly.
* On Linux, pthread_atfork() is defined in libc_nonshared.a (for
* glibc >= 2.28) or libpthread_nonshared.a (for glibc <= 2.27), and
* we want to avoid "#pragma weak" for that symbol because that causes
* it to be undefined even if you link lib*_nonshared.a in explicitly.
*/
#ifndef HAVE_LIBPTHREAD_NONSHARED
#if !defined(HAVE_LIBC_NONSHARED) && !defined(HAVE_LIBPTHREAD_NONSHARED)
#pragma weak pthread_atfork
#endif

Expand Down

0 comments on commit a5e9cad

Please sign in to comment.