Commit 21f2aa66bc for openssl.org

commit 21f2aa66bca86bb3a5b786135495b074415243db
Author: Neil Horman <nhorman@openssl.org>
Date:   Thu Oct 1 10:43:20 2026 -0400

    add provider load_unload / doall test

    Add a test to torture loading/unloading of a provider while we run
    parallel calls to OSSL_DECODER_do_all

    Reviewed-by: Nikola Pajkovsky <nikolap@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    Merge-date: Mon Oct  5 09:31:07 2026
    Merged-from: https://github.com/openssl/openssl/pull/33056

diff --git a/test/threadstest.c b/test/threadstest.c
index 65c7afcae6..2c0877341d 100644
--- a/test/threadstest.c
+++ b/test/threadstest.c
@@ -27,6 +27,7 @@
 #include <openssl/rand.h>
 #include <openssl/pem.h>
 #include <openssl/evp.h>
+#include <openssl/decoder.h>
 #include "internal/tsan_assist.h"
 #include "internal/nelem.h"
 #include "internal/time.h"
@@ -1502,6 +1503,92 @@ static void test_obj_create_worker(void)
     }
 }

+#if defined(OPENSSL_THREADS)
+static thread_t do_all_thread;
+static thread_t load_unload_thread;
+static OSSL_LIB_CTX *do_all_ctx = NULL;
+static OSSL_PROVIDER *defprov = NULL;
+static int load_unload_err = 0;
+static int do_all_err = 0;
+
+static void do_all_fn(void)
+{
+    OSSL_TIME t1, t2;
+    EVP_PKEY *pkey = NULL;
+    OSSL_DECODER_CTX *dctx = NULL;
+
+    t1 = ossl_time_now();
+
+    for (;;) {
+        dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, "RSA",
+            EVP_PKEY_KEYPAIR,
+            do_all_ctx, "");
+        EVP_PKEY_free(pkey);
+        OSSL_DECODER_CTX_free(dctx);
+        t2 = ossl_time_now();
+        if ((ossl_time2seconds(t2) - ossl_time2seconds(t1)) >= TORTURE_SECONDS)
+            break;
+    }
+    do_all_err = 0;
+    return;
+}
+
+static void load_unload_fn(void)
+{
+    OSSL_TIME t1, t2;
+
+    t1 = ossl_time_now();
+
+    for (;;) {
+        if (defprov == NULL) {
+            defprov = OSSL_PROVIDER_load(do_all_ctx, "default");
+            if (!TEST_ptr(defprov)) {
+                load_unload_err = 1;
+                return;
+            }
+        } else {
+            if (!TEST_true(OSSL_PROVIDER_unload(defprov))) {
+                load_unload_err = 1;
+                return;
+            }
+            defprov = NULL;
+        }
+        t2 = ossl_time_now();
+        if ((ossl_time2seconds(t2) - ossl_time2seconds(t1)) >= TORTURE_SECONDS)
+            break;
+    }
+    if (defprov != NULL)
+        OSSL_PROVIDER_unload(defprov);
+    return;
+}
+
+static int test_do_all_stress(void)
+{
+    do_all_ctx = OSSL_LIB_CTX_new();
+    int ret = 0;
+
+    if (!TEST_ptr(do_all_ctx))
+        goto err;
+
+    if (!TEST_true(run_thread(&load_unload_thread, load_unload_fn))
+        || !TEST_true(run_thread(&do_all_thread, do_all_fn))
+        || !TEST_true(wait_for_thread(load_unload_thread))
+        || !TEST_true(wait_for_thread(do_all_thread)))
+        goto err;
+
+    if (!TEST_int_eq(load_unload_err, 0))
+        goto err;
+
+    if (!TEST_int_eq(do_all_err, 0))
+        goto err;
+
+    ret = 1;
+err:
+    OSSL_LIB_CTX_free(do_all_ctx);
+    return ret;
+}
+#endif
+
 static int test_obj_stress(void)
 {
     return thread_run_test(&test_obj_create_worker, MAXIMUM_THREADS,
@@ -1577,6 +1664,7 @@ int setup_tests(void)
     ADD_TEST(torture_rcu_low);
     ADD_TEST(torture_rcu_high);
     ADD_TEST(torture_rcu_high2);
+    ADD_TEST(test_do_all_stress);
 #endif
     ADD_TEST(test_once);
     ADD_TEST(test_thread_local);