Commit cd19b150f3 for openssl.org
commit cd19b150f3ef67a267254b13464074e28c317033
Author: Richard Levitte <levitte@openssl.foundation>
Date: Thu Sep 17 14:54:56 2026 +0200
crypto/threads_pthread.c: acquire on cmp_exch failure
Callers of CRYPTO_atomic_cmp_exch_ptr() that fail the exchange adopt
the winning pointer delivered through *expect and access the object
it points to: the publish-after-init pattern, where the winner
publishes a built object with the compare-exchange and the loser
adopts it.
With a relaxed failure memory order there is no happens-before edge
from the winner's initialization writes to the loser's subsequent
reads of the object contents — a genuine data race, latent on
weakly-ordered architectures (ARM, POWER), and visible to
ThreadSanitizer for any caller that adopts the published object this
way.
Unlike the report that motivated 8f9f0d2da0 ("Fix persniketyness in
tsan"), such a report here is a true positive: there, publication
went through locks, so relaxed loads were sufficient; here,
publication goes through the compare-exchange itself, so the failure
path must carry acquire semantics.
The relaxed production memory orders of CRYPTO_atomic_load_ptr() and
CRYPTO_atomic_store_ptr() (the TSAN_LOAD_MEM_ORDER /
TSAN_STORE_MEM_ORDER dance) are untouched; whether they should be
strengthened outside TSan builds is a separate question.
Assisted-by: Pi:moonshotai/kimi-k3
Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Merge-date: Tue Sep 22 09:29:50 2026
Merged-from: https://github.com/openssl/openssl/pull/32868
diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c
index 7cf820b546..132479bab6 100644
--- a/crypto/threads_pthread.c
+++ b/crypto/threads_pthread.c
@@ -1279,10 +1279,10 @@ int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock, int *lock_failed)
{
-#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
+#if defined(__GNUC__) && defined(__ATOMIC_ACQ_REL) && !defined(BROKEN_CLANG_ATOMICS)
if (lock_failed != NULL)
*lock_failed = 0;
- return __atomic_compare_exchange_n(ptr, expect, desire, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED) ? 1 : 0;
+ return __atomic_compare_exchange_n(ptr, expect, desire, 0, __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE) ? 1 : 0;
#else
int lock_sink;
int ret = 0;