From: Neil Horman Date: Wed, 1 Apr 2026 16:32:40 +0000 (-0400) Subject: Add some crypto atomic pointer ops X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=70cdba10faa2055fc5791bddc3e12ddfbe772496;p=thirdparty%2Fopenssl.git 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 Reviewed-by: Nikola Pajkovsky 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() \