Summary: | Linking libthr with -nodefaultlibs statically can cause infinite recursion | ||
---|---|---|---|
Product: | Base System | Reporter: | Alex Richardson <arichardson> |
Component: | threads | Assignee: | freebsd-threads (Nobody) <threads> |
Status: | Closed FIXED | ||
Severity: | Affects Only Me | CC: | kib |
Priority: | --- | ||
Version: | 11.2-RELEASE | ||
Hardware: | Any | ||
OS: | Any |
Description
Alex Richardson
2019-07-27 11:51:41 UTC
For me it was reproduced as infinite loop, perhaps due to the the tail call elimination. The issue is that when -lc is passed first, __pthread_cleanup_push_imp is found in libc, and then the libthr jump table, which references the symbol, is satisfied with the same libc definition. Try this, I did not even compiled with the patch. It might require some additional tweaking to get the stuff actually working. diff --git a/lib/libthr/thread/thr_clean.c b/lib/libthr/thread/thr_clean.c index 5a93d94a7e5..7bc7d62b617 100644 --- a/lib/libthr/thread/thr_clean.c +++ b/lib/libthr/thread/thr_clean.c @@ -49,6 +49,10 @@ __FBSDID("$FreeBSD$"); __weak_reference(_pthread_cleanup_push, pthread_cleanup_push); __weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop); +/* help static linking when libc symbols have preference */ +__weak_reference(__pthread_cleanup_push_imp, __pthread_cleanup_push_imp1); +__weak_reference(__pthread_cleanup_pop_imp, pthread_cleanup_pop_imp1); + void __pthread_cleanup_push_imp(void (*routine)(void *), void *arg, struct _pthread_cleanup_info *info) diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c index 7b043a38b1f..22802c0ae1a 100644 --- a/lib/libthr/thread/thr_init.c +++ b/lib/libthr/thread/thr_init.c @@ -202,6 +202,10 @@ STATIC_LIB_REQUIRE(_thread_state_running); #define DUAL_ENTRY(entry) \ (pthread_func_t)entry, (pthread_func_t)entry +void __pthread_cleanup_push_imp1(void (*)(void *), void *, + struct _pthread_cleanup_info *); +void __pthread_cleanup_pop_imp1(int); + static pthread_func_t jmp_table[][2] = { {DUAL_ENTRY(_pthread_atfork)}, /* PJT_ATFORK */ {DUAL_ENTRY(_pthread_attr_destroy)}, /* PJT_ATTR_DESTROY */ @@ -265,8 +269,8 @@ static pthread_func_t jmp_table[][2] = { {DUAL_ENTRY(_pthread_setspecific)}, /* PJT_SETSPECIFIC */ {DUAL_ENTRY(_pthread_sigmask)}, /* PJT_SIGMASK */ {DUAL_ENTRY(_pthread_testcancel)}, /* PJT_TESTCANCEL */ - {DUAL_ENTRY(__pthread_cleanup_pop_imp)},/* PJT_CLEANUP_POP_IMP */ - {DUAL_ENTRY(__pthread_cleanup_push_imp)},/* PJT_CLEANUP_PUSH_IMP */ + {DUAL_ENTRY(__pthread_cleanup_pop_imp1)},/* PJT_CLEANUP_POP_IMP */ + {DUAL_ENTRY(__pthread_cleanup_push_imp1)},/* PJT_CLEANUP_PUSH_IMP */ {DUAL_ENTRY(_pthread_cancel_enter)}, /* PJT_CANCEL_ENTER */ {DUAL_ENTRY(_pthread_cancel_leave)}, /* PJT_CANCEL_LEAVE */ {DUAL_ENTRY(_pthread_mutex_consistent)},/* PJT_MUTEX_CONSISTENT */ Thanks, I guess that should work. However, we probably have to do it for all the functions in the table? Or maybe only the ones referenced in libc? This seems to be: void _pthread_cancel_enter(int); void _pthread_cancel_leave(int); void ___pthread_cleanup_push_imp(void (*)(void *), void *, struct _pthread_cleanup_info *); void ___pthread_cleanup_pop_imp(int); A commit references this bug: Author: kib Date: Wed Jul 31 19:27:24 UTC 2019 New revision: 350481 URL: https://svnweb.freebsd.org/changeset/base/350481 Log: Avoid conflicts with libc symbols in libthr jump table. In some corner cases of static linking and unexpected libraries order on the linker command line, libc symbol might preempt the same libthr symbol, in which case libthr jump table points back to libc causing either infinite recursion or loop. Handle all of such symbols by using private libthr names for them, ensuring that the right pointers are installed into the table. In collaboration with: arichardson PR: 239475 Tested by: pho MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D21088 Changes: head/lib/libthr/thread/thr_attr.c head/lib/libthr/thread/thr_cancel.c head/lib/libthr/thread/thr_clean.c head/lib/libthr/thread/thr_cond.c head/lib/libthr/thread/thr_detach.c head/lib/libthr/thread/thr_equal.c head/lib/libthr/thread/thr_exit.c head/lib/libthr/thread/thr_fork.c head/lib/libthr/thread/thr_getthreadid_np.c head/lib/libthr/thread/thr_init.c head/lib/libthr/thread/thr_join.c head/lib/libthr/thread/thr_kill.c head/lib/libthr/thread/thr_main_np.c head/lib/libthr/thread/thr_mutex.c head/lib/libthr/thread/thr_mutexattr.c head/lib/libthr/thread/thr_once.c head/lib/libthr/thread/thr_private.h head/lib/libthr/thread/thr_rwlock.c head/lib/libthr/thread/thr_self.c head/lib/libthr/thread/thr_sig.c head/lib/libthr/thread/thr_spec.c A commit references this bug: Author: kib Date: Wed Jul 31 20:04:40 UTC 2019 New revision: 350483 URL: https://svnweb.freebsd.org/changeset/base/350483 Log: Avoid conflicts with libc symbols in libthr jump table. In some corner cases of static linking and unexpected libraries order on the linker command line, libc symbol might preempt the same libthr symbol, in which case libthr jump table points back to libc causing either infinite recursion or loop. Handle all of such symbols by using private libthr names for them, ensuring that the right pointers are installed into the table. In collaboration with: arichardson PR: 239475 Tested by: pho MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential revision: https://reviews.freebsd.org/D21088 Changes: head/lib/libthr/thread/thr_private.h |