]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Add some crypto atomic pointer ops
authorNeil Horman <nhorman@openssl.org>
Wed, 1 Apr 2026 16:32:40 +0000 (12:32 -0400)
committerNikola Pajkovsky <nikolap@openssl.org>
Tue, 14 Apr 2026 08:29:28 +0000 (10:29 +0200)
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)

crypto/threads_none.c
crypto/threads_pthread.c
crypto/threads_win.c
include/openssl/crypto.h.in

index 1bc0e85c713a6771e8d89b830a1c980c482e9204..2453983488a80b62ec759d40202779f35dfd9e23 100644 (file)
@@ -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;
index 178d0c8f60225402d40f6d6f831ac7f1c069ddc7..9472cb437aa762498ddc1ebbde518b82f91daf2e 100644 (file)
@@ -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)
 {
index 059f5118bdc932d9d4a6114f8d43cc2f303bec64..beaf7f02521940056ecc17df70245f06b0afd0d0 100644 (file)
@@ -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;
index 5e15358bbcc0f3c6860aa709ef402fd2172daeb5..e5389a4c22f91516e45116d6aaa3e5bc70b5d42d 100644 (file)
@@ -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() \