Commit 5dfc09b1da for openssl.org
commit 5dfc09b1da7f58d446a755b0c5736b0fc55c48ff
Author: Jose A. Diaz <josealf@rocketmail.com>
Date: Tue Sep 1 13:46:04 2026 -0500
threads_win: don't abort CRYPTO_atomic_* on a NULL lock
crypto/threads_win.c provides two implementations of the CRYPTO_atomic_*
family: a lock-free one built on the Interlocked* intrinsics, and a
fallback that takes a CRYPTO_RWLOCK. The fallback is compiled when
OSSL_USE_INTERLOCKEDOR64 is not defined, which per
include/internal/threads_common.h means MSVC 2010 and earlier on x86, or
a MinGW build that is not __MINGW64__ - that is, 32-bit MinGW. The
comment on the rw_lock field in this file names those same two cases.
Eight functions in that fallback path assert that the caller supplied a
lock. That assumption does not hold: OPENSSL_init_crypto() in
crypto/init.c calls
CRYPTO_atomic_load(&optsdone, &tmp, NULL)
deliberately, and the comment above the call explains why. It is an
optimisation that runs before optsdone_lock has been created, so there
is no lock to pass, and it is documented as expected to fail on
platforms without lockless atomic loads, with the failure ignored.
Because OPENSSL_init_crypto() runs on essentially the first use of the
library in any process, the assertion fires immediately on the affected
targets and every binary aborts before doing any work:
$ openssl version
crypto/threads_win.c:694: OpenSSL internal error: \
assertion failed: lock != NULL
The equivalent function in crypto/threads_pthread.c returns 0 for a NULL
lock rather than asserting, which is what the caller in init.c expects,
so this was a difference between the two backends rather than an
invariant of the API.
Return 0 for a NULL lock in all eight functions, matching the pthread
backend. Behaviour when a lock is supplied is unchanged.
This restores the check that commit 1e1ea715a6 replaced with an
assertion. That commit also relied on the assertion to suppress three
-Wmaybe-uninitialized reports in the RCU code; the preceding commit
addresses those directly, so a --strict-warnings build stays clean.
Assisted-by: Claude:claude-opus-5
Reviewed-by: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
Merge-date: Thu Sep 24 09:18:03 2026
Merged-from: https://github.com/openssl/openssl/pull/32633
diff --git a/crypto/threads_win.c b/crypto/threads_win.c
index 0788a0483c..22b59f64d0 100644
--- a/crypto/threads_win.c
+++ b/crypto/threads_win.c
@@ -611,8 +611,7 @@ int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_write_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
return 0;
*val += amount;
*ret = *val;
@@ -632,8 +631,7 @@ int CRYPTO_atomic_add64(uint64_t *val, uint64_t op, uint64_t *ret,
CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_write_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
return 0;
*val += op;
*ret = *val;
@@ -652,8 +650,7 @@ int CRYPTO_atomic_and(uint64_t *val, uint64_t op, uint64_t *ret,
CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_write_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
return 0;
*val &= op;
*ret = *val;
@@ -672,8 +669,7 @@ int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_write_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_write_lock(lock))
return 0;
*val |= op;
*ret = *val;
@@ -691,8 +687,7 @@ int CRYPTO_atomic_or(uint64_t *val, uint64_t op, uint64_t *ret,
int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_read_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
return 0;
*ret = *val;
if (!CRYPTO_THREAD_unlock(lock))
@@ -708,8 +703,7 @@ int CRYPTO_atomic_load(uint64_t *val, uint64_t *ret, CRYPTO_RWLOCK *lock)
int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_read_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
return 0;
*dst = val;
if (!CRYPTO_THREAD_unlock(lock))
@@ -725,8 +719,7 @@ int CRYPTO_atomic_store(uint64_t *dst, uint64_t val, CRYPTO_RWLOCK *lock)
int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_read_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
return 0;
*ret = *val;
if (!CRYPTO_THREAD_unlock(lock))
@@ -743,8 +736,7 @@ int CRYPTO_atomic_load_int(int *val, int *ret, CRYPTO_RWLOCK *lock)
int CRYPTO_atomic_store_int(int *dst, int val, CRYPTO_RWLOCK *lock)
{
#if (!defined(OSSL_USE_INTERLOCKEDOR64))
- OPENSSL_assert(lock != NULL);
- if (!CRYPTO_THREAD_read_lock(lock))
+ if (lock == NULL || !CRYPTO_THREAD_read_lock(lock))
return 0;
*dst = val;
if (!CRYPTO_THREAD_unlock(lock))