Commit 6a3c9527ce for openssl.org

commit 6a3c9527ce46e1ef6b0dfe339c79ced7a7f2f6ad
Author: Jakub Zelenka <jakub.zelenka@openssl.foundation>
Date:   Mon Jun 1 20:04:37 2026 +0200

    mfail: add all tests iterable variants

    It adds ADD_MFAIL_ALL_TESTS and ADD_MFAIL_ALL_NO_CHECK_TESTS that work
    in similar way as ADD_ALL_TESTS but with mfail testing.

    Reviewed-by: Norbert Pocs <norbertp@openssl.org>
    Reviewed-by: Tomas Mraz <tomas@openssl.foundation>
    MergeDate: Thu Jun 11 16:00:12 2026
    (Merged from https://github.com/openssl/openssl/pull/31356)

diff --git a/test/README.md b/test/README.md
index bc4bd73f49..2a423d3511 100644
--- a/test/README.md
+++ b/test/README.md
@@ -192,8 +192,10 @@ Some tests use the `ADD_MFAIL_TEST` framework to exhaustively verify that
 functions handle every possible allocation failure gracefully. These tests
 run repeatedly, failing one allocation later each iteration. The
 `ADD_MFAIL_NO_CHECK_TEST` variant relaxes the requirement that the test
-return 0 when a failure was triggered. Behavior is controlled with the
-following environment variables:
+return 0 when a failure was triggered. The `ADD_MFAIL_ALL_TESTS` and
+`ADD_MFAIL_ALL_NO_CHECK_TESTS` variants apply the same cycle to each index
+of a parameterised test, the same way `ADD_ALL_TESTS` does. Behavior is
+controlled with the following environment variables:

     OPENSSL_TEST_MFAIL_DISABLE=1    Disable mfail custom allocator installation.

diff --git a/test/testutil.h b/test/testutil.h
index 31e5f87412..b38791b287 100644
--- a/test/testutil.h
+++ b/test/testutil.h
@@ -79,6 +79,12 @@
 #define ADD_MFAIL_NO_CHECK_TEST(test_fn) \
     add_mfail_test(#test_fn, test_fn, MFAIL_TEST_NO_CHECK)

+/* Runs the exhaustive mfail cycle for each 0 <= idx < num */
+#define ADD_MFAIL_ALL_TESTS(test_fn, num) \
+    add_mfail_all_tests(#test_fn, test_fn, num, 0)
+#define ADD_MFAIL_ALL_NO_CHECK_TESTS(test_fn, num) \
+    add_mfail_all_tests(#test_fn, test_fn, num, MFAIL_TEST_NO_CHECK)
+
 /*
  * A variant of the same without TAP output.
  */
@@ -251,6 +257,8 @@ void add_all_tests(const char *test_case_name, int (*test_fn)(int idx), int num,
     int subtest);
 void add_mfail_test(const char *test_case_name, int (*test_fn)(void),
     int flags);
+void add_mfail_all_tests(const char *test_case_name, int (*test_fn)(int idx),
+    int num, int flags);

 #define MFAIL_start mfail_start
 #define MFAIL_end mfail_end
diff --git a/test/testutil/driver.c b/test/testutil/driver.c
index eb9087fe64..a3fdc59cc0 100644
--- a/test/testutil/driver.c
+++ b/test/testutil/driver.c
@@ -96,6 +96,20 @@ void add_mfail_test(const char *test_case_name, int (*test_fn)(void), int flags)
     ++num_test_cases;
 }

+void add_mfail_all_tests(const char *test_case_name, int (*test_fn)(int idx),
+    int num, int flags)
+{
+    assert(num_tests != OSSL_NELEM(all_tests));
+    all_tests[num_tests].test_case_name = test_case_name;
+    all_tests[num_tests].param_test_fn = test_fn;
+    all_tests[num_tests].num = num;
+    all_tests[num_tests].subtest = 1;
+    all_tests[num_tests].mfail = 1;
+    all_tests[num_tests].mfail_flags = flags;
+    ++num_tests;
+    ++num_test_cases;
+}
+
 static int gcd(int a, int b)
 {
     while (b != 0) {
@@ -300,19 +314,18 @@ static double mfail_elapsed_secs(clock_t start)
     return (double)(clock() - start) / CLOCKS_PER_SEC;
 }

-static int mfail_run_test(const char *test_case_name,
-    int (*test_fn)(void), int flags)
+static int mfail_run_test(const TEST_INFO *t, int idx)
 {
     int counting_ok = 1;
     int injection_ok = 1;
     int injections = 0;
     int allocations = 0;
-    int no_check = (flags & MFAIL_TEST_NO_CHECK) != 0;
+    int no_check = (t->mfail_flags & MFAIL_TEST_NO_CHECK) != 0;
     clock_t start = clock();

     level += 4;
     test_adjust_streams_tap_level(level);
-    test_printf_stdout("Subtest: %s\n", test_case_name);
+    test_printf_stdout("Subtest: %s[%d]\n", t->test_case_name, idx);
     test_printf_tapout("1..2\n");
     test_flush_stdout();
     test_flush_tapout();
@@ -324,13 +337,13 @@ static int mfail_run_test(const char *test_case_name,
         int rv;

         ERR_clear_error();
-        rv = test_fn();
+        rv = t->param_test_fn != NULL ? t->param_test_fn(idx) : t->test_fn();

         if (phase == MFAIL_PHASE_COUNTING) {
             allocations = mfail_get_count();
             if (!TEST_int_eq(rv, 1)) {
                 TEST_error("mfail test '%s': counting iteration failed",
-                    test_case_name);
+                    t->test_case_name);
                 counting_ok = 0;
             }
             test_verdict(counting_ok, "1 - counting (%d allocations)",
@@ -343,7 +356,7 @@ static int mfail_run_test(const char *test_case_name,
                 if (!no_check && !TEST_int_eq(rv, 0)) {
                     TEST_error("mfail test '%s': allocation failure at "
                                "point %d not handled",
-                        test_case_name, mfail_get_point());
+                        t->test_case_name, mfail_get_point());
                     injection_ok = 0;
                 }
             } else if (mfail_get_mode() == MFAIL_MODE_SINGLE) {
@@ -353,7 +366,7 @@ static int mfail_run_test(const char *test_case_name,
                 test_flush_tapout();
             } else if (!TEST_int_eq(rv, 1)) {
                 TEST_error("mfail test '%s': no injection but test failed",
-                    test_case_name);
+                    t->test_case_name);
                 injection_ok = 0;
             }
         }
@@ -435,8 +448,7 @@ int run_tests(const char *test_prog_name)
             set_test_title(all_tests[i].test_case_name);
             ERR_clear_error();
             if (all_tests[i].mfail)
-                verdict = mfail_run_test(all_tests[i].test_case_name,
-                    all_tests[i].test_fn, all_tests[i].mfail_flags);
+                verdict = mfail_run_test(&all_tests[i], 0);
             else
                 verdict = all_tests[i].test_fn();
             finalize(verdict != 0);
@@ -473,7 +485,10 @@ int run_tests(const char *test_prog_name)
                 if (single_iter != -1 && ((jj + 1) != single_iter))
                     continue;
                 ERR_clear_error();
-                v = all_tests[i].param_test_fn(j);
+                if (all_tests[i].mfail)
+                    v = mfail_run_test(&all_tests[i], j);
+                else
+                    v = all_tests[i].param_test_fn(j);

                 if (v == 0) {
                     verdict = 0;