Skip to content

dyld: Symbol not found: _perl_tsa_mutex_lock #18991

Open
@ryandesign

Description

@ryandesign

Description
"New Clang" means Apple Clang >= 6.1 or open source Clang >= 3.6
"Old Clang" means Apple Clang < 6.1 or open source Clang < 3.6

If you build perl with Old Clang such that PERL_TSA_ACTIVE is not defined, then functions perl_tsa_mutex_lock and perl_tsa_mutex_unlock do not get compiled and included in perl. If you later build a perl module with New Clang such that PERL_TSA_ACTIVE is defined, the module tries to use the nonexistent perl_tsa_mutex_lock and perl_tsa_mutex_unlock which fails at link time with an undefined symbol error. See https://trac.macports.org/ticket/57648 where this issue was reported to MacPorts; there have been other tickets as well.

In MacPorts it is not practical to guarantee that perl and all modules are compiled with the same compiler. (See also #18939.) For example, between the time that perl and a perl module are built, the version of compiler might have changed due to an Xcode upgrade, or a user may have installed perl from a binary built on another computer with another version of Xcode.

I wonder what a good workaround would be. Would it suffice for us to force the use of New Clang when building just perl? If a perl module is later built with New Clang it would use perl_pthread_mutex_lock which was built into perl and if building a perl module with Old Clang it would use pthread_mutex_lock which is a standard function which should always be available.

Steps to Reproduce
Build perl with Old Clang. Then build a module that uses perl_pthread_mutex_lock with New Clang.

Relevant code appears to be here:

perl5/perl.h

Lines 3237 to 3259 in 415da10

/* clang Thread Safety Analysis/Annotations/Attributes
* http://clang.llvm.org/docs/ThreadSafetyAnalysis.html
*
* Available since clang 3.6-ish (appeared in 3.4, but shaky still in 3.5).
* Apple XCode hijacks __clang_major__ and __clang_minor__
* (6.1 means really clang 3.6), so needs extra hijinks
* (could probably also test the contents of __apple_build_version__).
*/
#if defined(USE_ITHREADS) && defined(I_PTHREAD) && \
defined(__clang__) && \
!defined(SWIG) && \
((!defined(__apple_build_version__) && \
((__clang_major__ == 3 && __clang_minor__ >= 6) || \
(__clang_major__ >= 4))) || \
(defined(__apple_build_version__) && \
((__clang_major__ == 6 && __clang_minor__ >= 1) || \
(__clang_major__ >= 7))))
# define PERL_TSA__(x) __attribute__((x))
# define PERL_TSA_ACTIVE
#else
# define PERL_TSA__(x) /* No TSA, make TSA attributes no-ops. */
# undef PERL_TSA_ACTIVE
#endif

perl5/thread.h

Lines 201 to 207 in 3e25f6d

# ifdef PERL_TSA_ACTIVE
# define perl_pthread_mutex_lock(m) perl_tsa_mutex_lock(m)
# define perl_pthread_mutex_unlock(m) perl_tsa_mutex_unlock(m)
# else
# define perl_pthread_mutex_lock(m) pthread_mutex_lock(m)
# define perl_pthread_mutex_unlock(m) pthread_mutex_unlock(m)
# endif

perl5/util.c

Lines 6741 to 6761 in 6e512bc

#if defined(USE_ITHREADS) && defined(I_PTHREAD)
/* pthread_mutex_t and perl_mutex are typedef equivalent
* so casting the pointers is fine. */
int perl_tsa_mutex_lock(perl_mutex* mutex)
{
return pthread_mutex_lock((pthread_mutex_t *) mutex);
}
int perl_tsa_mutex_unlock(perl_mutex* mutex)
{
return pthread_mutex_unlock((pthread_mutex_t *) mutex);
}
int perl_tsa_mutex_destroy(perl_mutex* mutex)
{
return pthread_mutex_destroy((pthread_mutex_t *) mutex);
}
#endif

Expected behavior
Successful build

Perl configuration
n/a

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions