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;