[emval] Gate val thread-affinity check on __EMSCRIPTEN_PTHREADS__ instead of _REENTRANT#27109
[emval] Gate val thread-affinity check on __EMSCRIPTEN_PTHREADS__ instead of _REENTRANT#27109iakovgi wants to merge 4 commits into
Conversation
…tead of _REENTRANT `_REENTRANT` is a POSIX convention that third-party libraries may define unconditionally for Unix-like targets (including Emscripten) without implying that the pthread runtime is actually present. When some translation units in a non-pthread build inherit `_REENTRANT` via transitive library dependencies and others don't, the `val::thread` field is only initialized in TUs that see `_REENTRANT`. Vals constructed without it have an uninitialized `thread` field; accessing them from TUs with `_REENTRANT` triggers a spurious assertion failure. `__EMSCRIPTEN_PTHREADS__` is set by the compiler only when `-pthread` is passed. It cannot be leaked by user code or build-system definitions, and precisely indicates that the pthread runtime is linked and `pthread_self()` returns meaningful values. Since `-pthread` always implies `_REENTRANT` anyway, there is no configuration where the assertion would be needed but `__EMSCRIPTEN_PTHREADS__` is absent.
|
Hm, thats interesting. I always thought I didn't think its was intended to be set by users. Could you point me to the usages in Poco, glib? |
|
@sbc100 In our use case the |
I think they could be wrong here to define But that doesn't mean to shouldn't necessarily land this change of course. |
Summary
Replace
#ifdef _REENTRANTwith#ifdef __EMSCRIPTEN_PTHREADS__in the two guarded sites inval.h.Motivation
_REENTRANTis a POSIX convention meaning "use reentrant libc variants." It does not guarantee that the pthread runtime is present. Third-party libraries (e.g. Poco) set it as a PUBLIC compile definition for any Unix-like target, and Emscripten qualifies. This leaks_REENTRANTinto consumer TUs via transitive CMake dependencies.The
val::threadfield is declared unconditionally (to keep struct layout stable, see #26508 (comment)), but the constructor only initializes it under#ifdef _REENTRANT. In a non-pthread build where some TUs have_REENTRANT(from library deps) and others don't (standalone libraries built without those deps), vals cross the boundary with an uninitializedthreadfield. The assertion then compares garbage againstpthread_self()and fires spuriously.__EMSCRIPTEN_PTHREADS__is compiler-set (only with-pthread), cannot be leaked by user code, and-pthreadalways implies_REENTRANTanyway - so there is no configuration where the check is needed but__EMSCRIPTEN_PTHREADS__is absent.