Commit 70cdba10fa for openssl.org
commit 70cdba10faa2055fc5791bddc3e12ddfbe772496
Author: Neil Horman <nhorman@openssl.org>
Date: Wed Apr 1 12:32:40 2026 -0400
Add some crypto atomic pointer ops
CRYPTO_atomic_load_ptr - load a pointer value with relaxed semantics
CRYPTO_atomic_store_ptr - store a pointer value with relaxed semantics
CRYPTO_atomic_cmp_exch_ptr - cmp/exch a pointer with relaxed or acq/rel
semantics
The addition of these functions enables us to better use atomics to
replace read/write locks where we are almost always doing reads
Reviewed-by: Paul Dale <paul.dale@oracle.com>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
MergeDate: Tue Apr 14 08:29:30 2026
(Merged from https://github.com/openssl/openssl/pull/30670)
diff --git a/crypto/threads_none.c b/crypto/threads_none.c
index 1bc0e85c71..2453983488 100644
--- a/crypto/threads_none.c
+++ b/crypto/threads_none.c
@@ -282,6 +282,28 @@ int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
return 1;
}
+int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
+{
+ *ret = *ptr;
+ return 1;
+}
+
+int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
+{
+ *dst = *val;
+ return 1;
+}
+
+int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock)
+{
+ if (*ptr == *expect) {
+ *ptr = desire;
+ return 1;
+ }
+ *expect = *ptr;
+ return 0;
+}
+
int openssl_init_fork_handlers(void)
{
return 0;
diff --git a/crypto/threads_pthread.c b/crypto/threads_pthread.c
index 178d0c8f60..9472cb437a 100644
--- a/crypto/threads_pthread.c
+++ b/crypto/threads_pthread.c
@@ -1252,6 +1252,53 @@ int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
return 1;
}
+int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
+{
+#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
+ *ret = __atomic_load_n(ptr, __ATOMIC_RELAXED);
+ return 1;
+#else
+ if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
+ return 0;
+ *ret = *ptr;
+ if (!CRYPTO_THREAD_unlock(lock))
+ return 0;
+ return 1;
+#endif
+}
+
+int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
+{
+#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
+ __atomic_store(dst, val, __ATOMIC_RELAXED);
+ return 1;
+#else
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
+ return 0;
+ *dst = *val;
+ if (!CRYPTO_THREAD_unlock(lock))
+ return 0;
+ return 1;
+#endif
+}
+
+int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock)
+{
+#if defined(__GNUC__) && defined(__ATOMIC_RELAXED) && !defined(BROKEN_CLANG_ATOMICS)
+ return __atomic_compare_exchange_n(ptr, expect, desire, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED) ? 1 : 0;
+#else
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
+ return 0;
+ if (*ptr == *expect)
+ *ptr = desire;
+ else
+ *expect = *ptr;
+ if (!CRYPTO_THREAD_unlock(lock))
+ return 0;
+ return 1;
+#endif
+}
+
#ifndef FIPS_MODULE
int openssl_init_fork_handlers(void)
{
diff --git a/crypto/threads_win.c b/crypto/threads_win.c
index 059f5118bd..beaf7f0252 100644
--- a/crypto/threads_win.c
+++ b/crypto/threads_win.c
@@ -756,6 +756,34 @@ int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
#endif
}
+int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock)
+{
+ /*
+ * Windows doesn't have an atomic to do this properly, but the ms learn
+ * site here:
+ * https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-interlockedcompareexchangepointer
+ * suggests that using InterlockedCompareExchangePointer can be used to
+ * devise a load operation
+ */
+ *ret = InterlockedCompareExchangePointer(ptr, NULL, NULL);
+ return 1;
+}
+
+int CRYPTO_atomic_store_ptr(void **dst, void **val, CRYPTO_RWLOCK *lock)
+{
+ InterlockedExchangePointer(dst, *val);
+ return 1;
+}
+
+int CRYPTO_atomic_cmp_exch_ptr(void **ptr, void **expect, void *desire, CRYPTO_RWLOCK *lock)
+{
+ InterlockedCompareExchangePointer(ptr, desire, *expect);
+ if (*ptr == desire)
+ return 1;
+ *expect = *ptr;
+ return 0;
+}
+
int openssl_init_fork_handlers(void)
{
return 0;
diff --git a/include/openssl/crypto.h.in b/include/openssl/crypto.h.in
index 5e15358bbc..e5389a4c22 100644
--- a/include/openssl/crypto.h.in
+++ b/include/openssl/crypto.h.in
@@ -98,6 +98,9 @@ int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock);
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock);
int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock);
int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock);
+int CRYPTO_atomic_load_ptr(void **ptr, void **ret, CRYPTO_RWLOCK *lock);
+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);
/* No longer needed, so this is a no-op */
#define OPENSSL_malloc_init() \