Commit f5a5e89044 for openssl.org

commit f5a5e89044174e1b9509841baa2b334b368bdadc
Author: Neil Horman <nhorman@openssl.org>
Date:   Wed Jun 24 15:55:48 2026 -0400

    ensure writes are syncronized on windows in CRYPTO_THREAD_run_once

    We've tried to fix this properly using InitOnceExecuteOnce, but it
    results in an ABI breakage, so we're doing it this way.

    on windows, CRYPTO_THREAD_run_once, on weakly memory ordered systems,
    may complete the write of the run once variable lock before some of the
    writes made by the init callback routine complete.  The result is that
    on a heavily multithreaded application, other therads may see the data
    that was meant to be in an initalized state, as in some erroneous
    in-between state, leading to errors.

    Fix it by inserting a full memory barrier after we return from the init
    callback, and prior to setting the run once variable to ONCE_DONE.

    Reviewed-by: Saša NedvÄ›dický <sashan@openssl.org>
    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    MergeDate: Tue Jun 30 08:51:16 2026
    (Merged from https://github.com/openssl/openssl/pull/31713)

diff --git a/crypto/threads_win.c b/crypto/threads_win.c
index b52c8dd520..d777010cd8 100644
--- a/crypto/threads_win.c
+++ b/crypto/threads_win.c
@@ -527,6 +527,20 @@ int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
         result = InterlockedCompareExchange(lock, ONCE_ININIT, ONCE_UNINITED);
         if (result == ONCE_UNINITED) {
             init();
+            /*
+             * On weakly ordered systems, it may happen that the write to *lock
+             * below completes prior to some writes in whatever the init()
+             * callback routine above may do.  In this case, other threads
+             * entering here may see unsynchronized data in whatever the init
+             * routine initializes, leading to erroneous behavior.
+             *
+             * We should use InitOnceExecuteOnce here to implement this, but
+             * doing so requires that we modify the definition of the
+             * CRYPTO_ONCE type, which is an ABI breakage.  So instead
+             * just insert a memory barrier here to ensure that any pending
+             * writes are flushed to memory prior to setting ONCE_DONE below
+             */
+            MemoryBarrier();
             *lock = ONCE_DONE;
             return 1;
         }