Merge pull request #8689 from paul-elliott-arm/make_tests_thread_safe

Make test data thread safe
diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c
index 7616b69..a65332a 100644
--- a/programs/ssl/ssl_test_lib.c
+++ b/programs/ssl/ssl_test_lib.c
@@ -427,7 +427,7 @@
     mbedtls_test_mutex_usage_check();
 #endif
 
-    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_SUCCESS) {
+    if (mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_SUCCESS) {
         return 1;
     }
     return 0;
diff --git a/programs/test/metatest.c b/programs/test/metatest.c
index 82ecf95..8e798cd 100644
--- a/programs/test/metatest.c
+++ b/programs/test/metatest.c
@@ -344,9 +344,11 @@
 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
             mbedtls_test_mutex_usage_check();
 #endif
+            int result = (int) mbedtls_test_get_result();
+
             mbedtls_printf("Running metatest %s... done, result=%d\n",
-                           argv[1], (int) mbedtls_test_info.result);
-            mbedtls_exit(mbedtls_test_info.result == MBEDTLS_TEST_RESULT_SUCCESS ?
+                           argv[1], result);
+            mbedtls_exit(result == MBEDTLS_TEST_RESULT_SUCCESS ?
                          MBEDTLS_EXIT_SUCCESS :
                          MBEDTLS_EXIT_FAILURE);
         }
diff --git a/tests/include/test/bignum_helpers.h b/tests/include/test/bignum_helpers.h
index 2f6bf89..a5e49cb 100644
--- a/tests/include/test/bignum_helpers.h
+++ b/tests/include/test/bignum_helpers.h
@@ -77,14 +77,14 @@
  *
  * - This function guarantees that if \p s begins with '-' then the sign
  *   bit of the result will be negative, even if the value is 0.
- *   When this function encounters such a "negative 0", it
- *   increments #mbedtls_test_case_uses_negative_0.
- * - The size of the result is exactly the minimum number of limbs needed
- *   to fit the digits in the input. In particular, this function constructs
- *   a bignum with 0 limbs for an empty string, and a bignum with leading 0
- *   limbs if the string has sufficiently many leading 0 digits.
- *   This is important so that the "0 (null)" and "0 (1 limb)" and
- *   "leading zeros" test cases do what they claim.
+ *   When this function encounters such a "negative 0", it calls
+ *   mbedtls_test_increment_case_uses_negative_0().
+ * - The size of the result is exactly the minimum number of limbs needed to fit
+ *   the digits in the input. In particular, this function constructs a bignum
+ *   with 0 limbs for an empty string, and a bignum with leading 0 limbs if the
+ *   string has sufficiently many leading 0 digits. This is important so that
+ *   the "0 (null)" and "0 (1 limb)" and "leading zeros" test cases do what they
+ *   claim.
  *
  * \param[out] X        The MPI object to populate. It must be initialized.
  * \param[in] s         The null-terminated hexadecimal string to read from.
@@ -93,14 +93,6 @@
  */
 int mbedtls_test_read_mpi(mbedtls_mpi *X, const char *s);
 
-/** Nonzero if the current test case had an input parsed with
- * mbedtls_test_read_mpi() that is a negative 0 (`"-"`, `"-0"`, `"-00"`, etc.,
- * constructing a result with the sign bit set to -1 and the value being
- * all-limbs-0, which is not a valid representation in #mbedtls_mpi but is
- * tested for robustness).
- */
-extern unsigned mbedtls_test_case_uses_negative_0;
-
 #endif /* MBEDTLS_BIGNUM_C */
 
 #endif /* TEST_BIGNUM_HELPERS_H */
diff --git a/tests/include/test/helpers.h b/tests/include/test/helpers.h
index 3658868..d08100f 100644
--- a/tests/include/test/helpers.h
+++ b/tests/include/test/helpers.h
@@ -40,6 +40,11 @@
 #endif
 
 #include "test/threading_helpers.h"
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+#include "mbedtls/threading.h"
+#endif
+
 #include "mbedtls/platform.h"
 
 #include <stddef.h>
@@ -61,20 +66,128 @@
     MBEDTLS_TEST_RESULT_SKIPPED
 } mbedtls_test_result_t;
 
+#define MBEDTLS_TEST_LINE_LENGTH 76
+
 typedef struct {
     mbedtls_test_result_t result;
     const char *test;
     const char *filename;
     int line_no;
     unsigned long step;
-    char line1[76];
-    char line2[76];
+    char line1[MBEDTLS_TEST_LINE_LENGTH];
+    char line2[MBEDTLS_TEST_LINE_LENGTH];
 #if defined(MBEDTLS_TEST_MUTEX_USAGE)
     const char *mutex_usage_error;
 #endif
+#if defined(MBEDTLS_BIGNUM_C)
+    unsigned case_uses_negative_0;
+#endif
 }
 mbedtls_test_info_t;
-extern mbedtls_test_info_t mbedtls_test_info;
+
+/**
+ * \brief           Get the current test result status
+ *
+ * \return          The current test result status
+ */
+mbedtls_test_result_t mbedtls_test_get_result(void);
+
+/**
+ * \brief           Get the current test name/description
+ *
+ * \return          The current test name/description
+ */
+const char *mbedtls_test_get_test(void);
+
+/**
+ * \brief           Get the current test filename
+ *
+ * \return          The current test filename
+ */
+const char *mbedtls_get_test_filename(void);
+
+/**
+ * \brief           Get the current test file line number (for failure / skip)
+ *
+ * \return          The current test file line number (for failure / skip)
+ */
+int mbedtls_test_get_line_no(void);
+
+/**
+ * \brief           Increment the current test step.
+ *
+ * \note            It is not recommended for multiple threads to call this
+ *                  function concurrently - whilst it is entirely thread safe,
+ *                  the order of calls to this function can obviously not be
+ *                  ensured, so unexpected results may occur.
+ */
+void mbedtls_test_increment_step(void);
+
+/**
+ * \brief           Get the current test step
+ *
+ * \return          The current test step
+ */
+unsigned long mbedtls_test_get_step(void);
+
+/**
+ * \brief           Get the current test line buffer 1
+ *
+ * \param line      Buffer of minimum size \c MBEDTLS_TEST_LINE_LENGTH,
+ *                  which will have line buffer 1 copied to it.
+ */
+void mbedtls_test_get_line1(char *line);
+
+/**
+ * \brief           Get the current test line buffer 2
+ *
+ * \param line      Buffer of minimum size \c MBEDTLS_TEST_LINE_LENGTH,
+ *                  which will have line buffer 1 copied to it.
+ */
+void mbedtls_test_get_line2(char *line);
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+/**
+ * \brief           Get the current mutex usage error message
+ *
+ * \return          The current mutex error message (may be NULL if no error)
+ */
+const char *mbedtls_test_get_mutex_usage_error(void);
+
+/**
+ * \brief           Set the current mutex usage error message
+ *
+ * \note            This will only set the mutex error message if one has not
+ *                  already been set, or if we are clearing the message (msg is
+ *                  NULL)
+ *
+ * \param msg       Error message to set (can be NULL to clear)
+ */
+void mbedtls_test_set_mutex_usage_error(const char *msg);
+#endif
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+/**
+ * \brief           Get whether the current test is a bignum test that uses
+ *                  negative zero.
+ *
+ * \return          non zero if the current test uses bignum negative zero.
+ */
+unsigned mbedtls_test_get_case_uses_negative_0(void);
+
+/**
+ * \brief           Indicate that the current test uses bignum negative zero.
+ *
+ * \note            This function is called if the current test case had an
+ *                  input parsed with mbedtls_test_read_mpi() that is a negative
+ *                  0 (`"-"`, `"-0"`, `"-00"`, etc., constructing a result with
+ *                  the sign bit set to -1 and the value being all-limbs-0,
+ *                  which is not a valid representation in #mbedtls_mpi but is
+ *                  tested for robustness). *
+ */
+void  mbedtls_test_increment_case_uses_negative_0(void);
+#endif
 
 int mbedtls_test_platform_setup(void);
 void mbedtls_test_platform_teardown(void);
@@ -111,24 +224,42 @@
 void mbedtls_test_skip(const char *test, int line_no, const char *filename);
 
 /**
- * \brief       Set the test step number for failure reports.
+ * \brief           Set the test step number for failure reports.
  *
- *              Call this function to display "step NNN" in addition to the
- *              line number and file name if a test fails. Typically the "step
- *              number" is the index of a for loop but it can be whatever you
- *              want.
+ *                  Call this function to display "step NNN" in addition to the
+ *                  line number and file name if a test fails. Typically the
+ *                  "step number" is the index of a for loop but it can be
+ *                  whatever you want.
+ *
+ * \note            It is not recommended for multiple threads to call this
+ *                  function concurrently - whilst it is entirely thread safe,
+ *                  the order of calls to this function can obviously not be
+ *                  ensured, so unexpected results may occur.
  *
  * \param step  The step number to report.
  */
 void mbedtls_test_set_step(unsigned long step);
 
 /**
- * \brief       Reset mbedtls_test_info to a ready/starting state.
+ * \brief           Reset mbedtls_test_info to a ready/starting state.
  */
 void mbedtls_test_info_reset(void);
 
+#ifdef MBEDTLS_TEST_MUTEX_USAGE
 /**
- * \brief           Record the current test case as a failure if two integers
+ * \brief           Get the test info data mutex.
+ *
+ * \note            This is designed only to be used by threading_helpers to
+ *                  avoid a deadlock, not for general access to this mutex.
+ *
+ * \return          The test info data mutex.
+ */
+mbedtls_threading_mutex_t *mbedtls_test_get_info_mutex(void);
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
+
+/**
+ * \brief Record the current test case as a failure if two integers
  *                  have a different value.
  *
  *                  This function is usually called via the macro
diff --git a/tests/src/bignum_helpers.c b/tests/src/bignum_helpers.c
index c85e2ca..913f5e3 100644
--- a/tests/src/bignum_helpers.c
+++ b/tests/src/bignum_helpers.c
@@ -135,7 +135,7 @@
     }
     if (negative) {
         if (mbedtls_mpi_cmp_int(X, 0) == 0) {
-            ++mbedtls_test_case_uses_negative_0;
+            mbedtls_test_increment_case_uses_negative_0();
         }
         X->s = -1;
     }
diff --git a/tests/src/helpers.c b/tests/src/helpers.c
index eb28919..da0b54a 100644
--- a/tests/src/helpers.c
+++ b/tests/src/helpers.c
@@ -13,6 +13,10 @@
 #include <test/psa_crypto_helpers.h>
 #endif
 
+#if defined(MBEDTLS_THREADING_C)
+#include "mbedtls/threading.h"
+#endif
+
 /*----------------------------------------------------------------------------*/
 /* Static global variables */
 
@@ -20,7 +24,267 @@
 static mbedtls_platform_context platform_ctx;
 #endif
 
-mbedtls_test_info_t mbedtls_test_info;
+static mbedtls_test_info_t mbedtls_test_info;
+
+#ifdef MBEDTLS_THREADING_C
+mbedtls_threading_mutex_t mbedtls_test_info_mutex;
+#endif /* MBEDTLS_THREADING_C */
+
+/*----------------------------------------------------------------------------*/
+/* Mbedtls Test Info accessors */
+
+mbedtls_test_result_t mbedtls_test_get_result(void)
+{
+    mbedtls_test_result_t result;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    result =  mbedtls_test_info.result;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return result;
+}
+
+void mbedtls_test_set_result(mbedtls_test_result_t result, const char *test,
+                             int line_no, const char *filename)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.result = result;
+    mbedtls_test_info.test = test;
+    mbedtls_test_info.line_no = line_no;
+    mbedtls_test_info.filename = filename;
+}
+
+const char *mbedtls_test_get_test(void)
+{
+    const char *test;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    test = mbedtls_test_info.test;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return test;
+}
+const char *mbedtls_get_test_filename(void)
+{
+    const char *filename;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* It should be ok just to pass back the pointer here, as it is going to
+     * be a pointer into non changing data. */
+    filename = mbedtls_test_info.filename;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return filename;
+}
+
+int mbedtls_test_get_line_no(void)
+{
+    int line_no;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    line_no = mbedtls_test_info.line_no;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return line_no;
+}
+
+void mbedtls_test_increment_step(void)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    ++mbedtls_test_info.step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+unsigned long mbedtls_test_get_step(void)
+{
+    unsigned long step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    step = mbedtls_test_info.step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return step;
+}
+
+void mbedtls_test_reset_step(void)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.step = (unsigned long) (-1);
+}
+
+void mbedtls_test_set_step(unsigned long step)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_info.step = step;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_get_line1(char *line)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    memcpy(line, mbedtls_test_info.line1, MBEDTLS_TEST_LINE_LENGTH);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_set_line1(const char *line)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    if (line == NULL) {
+        memset(mbedtls_test_info.line1, 0, MBEDTLS_TEST_LINE_LENGTH);
+    } else {
+        memcpy(mbedtls_test_info.line1, line, MBEDTLS_TEST_LINE_LENGTH);
+    }
+}
+
+void mbedtls_test_get_line2(char *line)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    memcpy(line, mbedtls_test_info.line2, MBEDTLS_TEST_LINE_LENGTH);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+void mbedtls_test_set_line2(const char *line)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    if (line == NULL) {
+        memset(mbedtls_test_info.line2, 0, MBEDTLS_TEST_LINE_LENGTH);
+    } else {
+        memcpy(mbedtls_test_info.line2, line, MBEDTLS_TEST_LINE_LENGTH);
+    }
+}
+
+
+#if defined(MBEDTLS_TEST_MUTEX_USAGE)
+const char *mbedtls_test_get_mutex_usage_error(void)
+{
+    return mbedtls_test_info.mutex_usage_error;
+}
+
+void mbedtls_test_set_mutex_usage_error(const char *msg)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    if (mbedtls_test_info.mutex_usage_error == NULL || msg == NULL) {
+        mbedtls_test_info.mutex_usage_error = msg;
+    }
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+#endif // #if defined(MBEDTLS_TEST_MUTEX_USAGE)
+
+#if defined(MBEDTLS_BIGNUM_C)
+
+unsigned mbedtls_test_get_case_uses_negative_0(void)
+{
+    unsigned test_case_uses_negative_0 = 0;
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+    test_case_uses_negative_0 = mbedtls_test_info.case_uses_negative_0;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    return test_case_uses_negative_0;
+}
+
+void mbedtls_test_set_case_uses_negative_0(unsigned uses)
+{
+    /* Internal function only - mbedtls_test_info_mutex should be held prior
+     * to calling this function. */
+
+    mbedtls_test_info.case_uses_negative_0 = uses;
+}
+
+void mbedtls_test_increment_case_uses_negative_0(void)
+{
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    ++mbedtls_test_info.case_uses_negative_0;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
+
+#endif /* MBEDTLS_BIGNUM_C */
+
+#ifdef MBEDTLS_TEST_MUTEX_USAGE
+mbedtls_threading_mutex_t *mbedtls_test_get_info_mutex(void)
+{
+    return &mbedtls_test_info_mutex;
+}
+
+#endif /* MBEDTLS_TEST_MUTEX_USAGE */
 
 /*----------------------------------------------------------------------------*/
 /* Helper Functions */
@@ -44,11 +308,19 @@
     ret = mbedtls_platform_setup(&platform_ctx);
 #endif /* MBEDTLS_PLATFORM_C */
 
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_init(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
     return ret;
 }
 
 void mbedtls_test_platform_teardown(void)
 {
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_free(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
 #if defined(MBEDTLS_PLATFORM_C)
     mbedtls_platform_teardown(&platform_ctx);
 #endif /* MBEDTLS_PLATFORM_C */
@@ -71,46 +343,53 @@
 
 void mbedtls_test_fail(const char *test, int line_no, const char *filename)
 {
-    if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_FAILED) {
-        /* We've already recorded the test as having failed. Don't
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we have already recorded the test as having failed then don't
          * overwrite any previous information about the failure. */
-        return;
+        mbedtls_test_set_result(MBEDTLS_TEST_RESULT_FAILED, test, line_no, filename);
     }
-    mbedtls_test_info.result = MBEDTLS_TEST_RESULT_FAILED;
-    mbedtls_test_info.test = test;
-    mbedtls_test_info.line_no = line_no;
-    mbedtls_test_info.filename = filename;
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
 }
 
 void mbedtls_test_skip(const char *test, int line_no, const char *filename)
 {
-    mbedtls_test_info.result = MBEDTLS_TEST_RESULT_SKIPPED;
-    mbedtls_test_info.test = test;
-    mbedtls_test_info.line_no = line_no;
-    mbedtls_test_info.filename = filename;
-}
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
 
-void mbedtls_test_set_step(unsigned long step)
-{
-    mbedtls_test_info.step = step;
-}
+    mbedtls_test_set_result(MBEDTLS_TEST_RESULT_SKIPPED, test, line_no, filename);
 
-#if defined(MBEDTLS_BIGNUM_C)
-unsigned mbedtls_test_case_uses_negative_0 = 0;
-#endif
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+}
 
 void mbedtls_test_info_reset(void)
 {
-    mbedtls_test_info.result = MBEDTLS_TEST_RESULT_SUCCESS;
-    mbedtls_test_info.step = (unsigned long) (-1);
-    mbedtls_test_info.test = 0;
-    mbedtls_test_info.line_no = 0;
-    mbedtls_test_info.filename = 0;
-    memset(mbedtls_test_info.line1, 0, sizeof(mbedtls_test_info.line1));
-    memset(mbedtls_test_info.line2, 0, sizeof(mbedtls_test_info.line2));
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    mbedtls_test_set_result(MBEDTLS_TEST_RESULT_SUCCESS, 0, 0, 0);
+    mbedtls_test_reset_step();
+    mbedtls_test_set_line1(NULL);
+    mbedtls_test_set_line2(NULL);
+
 #if defined(MBEDTLS_BIGNUM_C)
-    mbedtls_test_case_uses_negative_0 = 0;
+    mbedtls_test_set_case_uses_negative_0(0);
 #endif
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
 }
 
 int mbedtls_test_equal(const char *test, int line_no, const char *filename,
@@ -123,20 +402,31 @@
         return 1;
     }
 
-    if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_FAILED) {
-        /* We've already recorded the test as having failed. Don't
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, as we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
          * overwrite any previous information about the failure. */
-        return 0;
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %lld",
+                                value1, (long long) value1);
+        mbedtls_test_set_line1(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %lld",
+                                value2, (long long) value2);
+        mbedtls_test_set_line2(buf);
     }
-    mbedtls_test_fail(test, line_no, filename);
-    (void) mbedtls_snprintf(mbedtls_test_info.line1,
-                            sizeof(mbedtls_test_info.line1),
-                            "lhs = 0x%016llx = %lld",
-                            value1, (long long) value1);
-    (void) mbedtls_snprintf(mbedtls_test_info.line2,
-                            sizeof(mbedtls_test_info.line2),
-                            "rhs = 0x%016llx = %lld",
-                            value2, (long long) value2);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
     return 0;
 }
 
@@ -150,20 +440,31 @@
         return 1;
     }
 
-    if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_FAILED) {
-        /* We've already recorded the test as having failed. Don't
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
          * overwrite any previous information about the failure. */
-        return 0;
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %llu",
+                                value1, value1);
+        mbedtls_test_set_line1(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %llu",
+                                value2, value2);
+        mbedtls_test_set_line2(buf);
     }
-    mbedtls_test_fail(test, line_no, filename);
-    (void) mbedtls_snprintf(mbedtls_test_info.line1,
-                            sizeof(mbedtls_test_info.line1),
-                            "lhs = 0x%016llx = %llu",
-                            value1, value1);
-    (void) mbedtls_snprintf(mbedtls_test_info.line2,
-                            sizeof(mbedtls_test_info.line2),
-                            "rhs = 0x%016llx = %llu",
-                            value2, value2);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
     return 0;
 }
 
@@ -177,20 +478,31 @@
         return 1;
     }
 
-    if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_FAILED) {
-        /* We've already recorded the test as having failed. Don't
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_lock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
+    /* Don't use accessor, we already hold mutex. */
+    if (mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+        /* If we've already recorded the test as having failed then don't
          * overwrite any previous information about the failure. */
-        return 0;
+
+        char buf[MBEDTLS_TEST_LINE_LENGTH];
+        mbedtls_test_fail(test, line_no, filename);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "lhs = 0x%016llx = %lld",
+                                (unsigned long long) value1, value1);
+        mbedtls_test_set_line1(buf);
+        (void) mbedtls_snprintf(buf, sizeof(buf),
+                                "rhs = 0x%016llx = %lld",
+                                (unsigned long long) value2, value2);
+        mbedtls_test_set_line2(buf);
     }
-    mbedtls_test_fail(test, line_no, filename);
-    (void) mbedtls_snprintf(mbedtls_test_info.line1,
-                            sizeof(mbedtls_test_info.line1),
-                            "lhs = 0x%016llx = %lld",
-                            (unsigned long long) value1, value1);
-    (void) mbedtls_snprintf(mbedtls_test_info.line2,
-                            sizeof(mbedtls_test_info.line2),
-                            "rhs = 0x%016llx = %lld",
-                            (unsigned long long) value2, value2);
+
+#ifdef MBEDTLS_THREADING_C
+    mbedtls_mutex_unlock(&mbedtls_test_info_mutex);
+#endif /* MBEDTLS_THREADING_C */
+
     return 0;
 }
 
diff --git a/tests/src/threading_helpers.c b/tests/src/threading_helpers.c
index 5a871e1..ff0c712 100644
--- a/tests/src/threading_helpers.c
+++ b/tests/src/threading_helpers.c
@@ -175,9 +175,7 @@
 {
     (void) mutex;
 
-    if (mbedtls_test_info.mutex_usage_error == NULL) {
-        mbedtls_test_info.mutex_usage_error = msg;
-    }
+    mbedtls_test_set_mutex_usage_error(msg);
     mbedtls_fprintf(stdout, "[mutex: %s] ", msg);
     /* Don't mark the test as failed yet. This way, if the test fails later
      * for a functional reason, the test framework will report the message
@@ -185,40 +183,60 @@
      * mbedtls_test_mutex_usage_check() will mark it as failed. */
 }
 
+static int mbedtls_test_mutex_can_test(mbedtls_threading_mutex_t *mutex)
+{
+    /* If we attempt to run tests on this mutex then we are going to run into a
+     * couple of problems:
+     * 1. If any test on this mutex fails, we are going to deadlock when
+     * reporting that failure, as we already hold the mutex at that point.
+     * 2. Given the 'global' position of the initialization and free of this
+     * mutex, it will be shown as leaked on the first test run. */
+    if (mutex == mbedtls_test_get_info_mutex()) {
+        return 0;
+    }
+
+    return 1;
+}
+
 static void mbedtls_test_wrap_mutex_init(mbedtls_threading_mutex_t *mutex)
 {
     mutex_functions.init(mutex);
 
-    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
-        mutex->state = MUTEX_IDLE;
-        ++live_mutexes;
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            mutex->state = MUTEX_IDLE;
+            ++live_mutexes;
 
-        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
     }
 }
 
 static void mbedtls_test_wrap_mutex_free(mbedtls_threading_mutex_t *mutex)
 {
-    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
 
-        switch (mutex->state) {
-            case MUTEX_FREED:
-                mbedtls_test_mutex_usage_error(mutex, "free without init or double free");
-                break;
-            case MUTEX_IDLE:
-                mutex->state = MUTEX_FREED;
-                --live_mutexes;
-                break;
-            case MUTEX_LOCKED:
-                mbedtls_test_mutex_usage_error(mutex, "free without unlock");
-                break;
-            default:
-                mbedtls_test_mutex_usage_error(mutex, "corrupted state");
-                break;
+            switch (mutex->state) {
+                case MUTEX_FREED:
+                    mbedtls_test_mutex_usage_error(mutex, "free without init or double free");
+                    break;
+                case MUTEX_IDLE:
+                    mutex->state = MUTEX_FREED;
+                    --live_mutexes;
+                    break;
+                case MUTEX_LOCKED:
+                    mbedtls_test_mutex_usage_error(mutex, "free without unlock");
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
         }
-
-        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
     }
+
     mutex_functions.free(mutex);
 }
 
@@ -228,26 +246,30 @@
      * is to hold the passed in and internal mutex - otherwise we create a race
      * condition. */
     int ret = mutex_functions.lock(mutex);
-    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
-        switch (mutex->state) {
-            case MUTEX_FREED:
-                mbedtls_test_mutex_usage_error(mutex, "lock without init");
-                break;
-            case MUTEX_IDLE:
-                if (ret == 0) {
-                    mutex->state = MUTEX_LOCKED;
-                }
-                break;
-            case MUTEX_LOCKED:
-                mbedtls_test_mutex_usage_error(mutex, "double lock");
-                break;
-            default:
-                mbedtls_test_mutex_usage_error(mutex, "corrupted state");
-                break;
-        }
 
-        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            switch (mutex->state) {
+                case MUTEX_FREED:
+                    mbedtls_test_mutex_usage_error(mutex, "lock without init");
+                    break;
+                case MUTEX_IDLE:
+                    if (ret == 0) {
+                        mutex->state = MUTEX_LOCKED;
+                    }
+                    break;
+                case MUTEX_LOCKED:
+                    mbedtls_test_mutex_usage_error(mutex, "double lock");
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
+        }
     }
+
     return ret;
 }
 
@@ -256,23 +278,26 @@
     /* Lock the internal mutex first and change state, so that the only way to
      * change the state is to hold the passed in and internal mutex - otherwise
      * we create a race condition. */
-    if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
-        switch (mutex->state) {
-            case MUTEX_FREED:
-                mbedtls_test_mutex_usage_error(mutex, "unlock without init");
-                break;
-            case MUTEX_IDLE:
-                mbedtls_test_mutex_usage_error(mutex, "unlock without lock");
-                break;
-            case MUTEX_LOCKED:
-                mutex->state = MUTEX_IDLE;
-                break;
-            default:
-                mbedtls_test_mutex_usage_error(mutex, "corrupted state");
-                break;
+    if (mbedtls_test_mutex_can_test(mutex)) {
+        if (mutex_functions.lock(&mbedtls_test_mutex_mutex) == 0) {
+            switch (mutex->state) {
+                case MUTEX_FREED:
+                    mbedtls_test_mutex_usage_error(mutex, "unlock without init");
+                    break;
+                case MUTEX_IDLE:
+                    mbedtls_test_mutex_usage_error(mutex, "unlock without lock");
+                    break;
+                case MUTEX_LOCKED:
+                    mutex->state = MUTEX_IDLE;
+                    break;
+                default:
+                    mbedtls_test_mutex_usage_error(mutex, "corrupted state");
+                    break;
+            }
+            mutex_functions.unlock(&mbedtls_test_mutex_mutex);
         }
-        mutex_functions.unlock(&mbedtls_test_mutex_mutex);
     }
+
     return mutex_functions.unlock(mutex);
 }
 
@@ -299,17 +324,15 @@
          * negative number means a missing init somewhere. */
         mbedtls_fprintf(stdout, "[mutex: %d leaked] ", live_mutexes);
         live_mutexes = 0;
-        if (mbedtls_test_info.mutex_usage_error == NULL) {
-            mbedtls_test_info.mutex_usage_error = "missing free";
-        }
+        mbedtls_test_set_mutex_usage_error("missing free");
     }
-    if (mbedtls_test_info.mutex_usage_error != NULL &&
-        mbedtls_test_info.result != MBEDTLS_TEST_RESULT_FAILED) {
+    if (mbedtls_test_get_mutex_usage_error() != NULL &&
+        mbedtls_test_get_result() != MBEDTLS_TEST_RESULT_FAILED) {
         /* Functionally, the test passed. But there was a mutex usage error,
          * so mark the test as failed after all. */
         mbedtls_test_fail("Mutex usage error", __LINE__, __FILE__);
     }
-    mbedtls_test_info.mutex_usage_error = NULL;
+    mbedtls_test_set_mutex_usage_error(NULL);
 }
 
 void mbedtls_test_mutex_usage_end(void)
diff --git a/tests/suites/host_test.function b/tests/suites/host_test.function
index cc28697..eb42a07 100644
--- a/tests/suites/host_test.function
+++ b/tests/suites/host_test.function
@@ -371,14 +371,12 @@
  * \param missing_unmet_dependencies Non-zero if there was a problem tracking
  *                                   all unmet dependencies, 0 otherwise.
  * \param ret                        The test dispatch status (DISPATCH_xxx).
- * \param info                       A pointer to the test info structure.
  */
 static void write_outcome_result(FILE *outcome_file,
                                  size_t unmet_dep_count,
                                  int unmet_dependencies[],
                                  int missing_unmet_dependencies,
-                                 int ret,
-                                 const mbedtls_test_info_t *info)
+                                 int ret)
 {
     if (outcome_file == NULL) {
         return;
@@ -401,7 +399,7 @@
                 }
                 break;
             }
-            switch (info->result) {
+            switch (mbedtls_test_get_result()) {
                 case MBEDTLS_TEST_RESULT_SUCCESS:
                     mbedtls_fprintf(outcome_file, "PASS;");
                     break;
@@ -410,8 +408,9 @@
                     break;
                 default:
                     mbedtls_fprintf(outcome_file, "FAIL;%s:%d:%s",
-                                    info->filename, info->line_no,
-                                    info->test);
+                                    mbedtls_get_test_filename(),
+                                    mbedtls_test_get_line_no(),
+                                    mbedtls_test_get_test());
                     break;
             }
             break;
@@ -614,7 +613,7 @@
                 break;
             }
             mbedtls_fprintf(stdout, "%s%.66s",
-                            mbedtls_test_info.result == MBEDTLS_TEST_RESULT_FAILED ?
+                            mbedtls_test_get_result() == MBEDTLS_TEST_RESULT_FAILED ?
                             "\n" : "", buf);
             mbedtls_fprintf(stdout, " ");
             for (i = strlen(buf) + 1; i < 67; i++) {
@@ -690,7 +689,7 @@
             write_outcome_result(outcome_file,
                                  unmet_dep_count, unmet_dependencies,
                                  missing_unmet_dependencies,
-                                 ret, &mbedtls_test_info);
+                                 ret);
             if (unmet_dep_count > 0 || ret == DISPATCH_UNSUPPORTED_SUITE) {
                 total_skipped++;
                 mbedtls_fprintf(stdout, "----");
@@ -715,30 +714,33 @@
                 unmet_dep_count = 0;
                 missing_unmet_dependencies = 0;
             } else if (ret == DISPATCH_TEST_SUCCESS) {
-                if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_SUCCESS) {
+                if (mbedtls_test_get_result() == MBEDTLS_TEST_RESULT_SUCCESS) {
                     mbedtls_fprintf(stdout, "PASS\n");
-                } else if (mbedtls_test_info.result == MBEDTLS_TEST_RESULT_SKIPPED) {
+                } else if (mbedtls_test_get_result() == MBEDTLS_TEST_RESULT_SKIPPED) {
                     mbedtls_fprintf(stdout, "----\n");
                     total_skipped++;
                 } else {
+                    char line_buffer[MBEDTLS_TEST_LINE_LENGTH];
+
                     total_errors++;
                     mbedtls_fprintf(stdout, "FAILED\n");
                     mbedtls_fprintf(stdout, "  %s\n  at ",
-                                    mbedtls_test_info.test);
-                    if (mbedtls_test_info.step != (unsigned long) (-1)) {
+                                    mbedtls_test_get_test());
+                    if (mbedtls_test_get_step() != (unsigned long) (-1)) {
                         mbedtls_fprintf(stdout, "step %lu, ",
-                                        mbedtls_test_info.step);
+                                        mbedtls_test_get_step());
                     }
                     mbedtls_fprintf(stdout, "line %d, %s",
-                                    mbedtls_test_info.line_no,
-                                    mbedtls_test_info.filename);
-                    if (mbedtls_test_info.line1[0] != 0) {
-                        mbedtls_fprintf(stdout, "\n  %s",
-                                        mbedtls_test_info.line1);
+                                    mbedtls_test_get_line_no(),
+                                    mbedtls_get_test_filename());
+
+                    mbedtls_test_get_line1(line_buffer);
+                    if (line_buffer[0] != 0) {
+                        mbedtls_fprintf(stdout, "\n  %s", line_buffer);
                     }
-                    if (mbedtls_test_info.line2[0] != 0) {
-                        mbedtls_fprintf(stdout, "\n  %s",
-                                        mbedtls_test_info.line2);
+                    mbedtls_test_get_line2(line_buffer);
+                    if (line_buffer[0] != 0) {
+                        mbedtls_fprintf(stdout, "\n  %s", line_buffer);
                     }
                 }
                 fflush(stdout);
diff --git a/tests/suites/test_suite_bignum.function b/tests/suites/test_suite_bignum.function
index 2305f48..50be2d2 100644
--- a/tests/suites/test_suite_bignum.function
+++ b/tests/suites/test_suite_bignum.function
@@ -24,7 +24,7 @@
      * we sometimes test the robustness of library functions when given
      * a negative zero input. If a test case has a negative zero as input,
      * we don't mind if the function has a negative zero output. */
-    if (!mbedtls_test_case_uses_negative_0 &&
+    if (!mbedtls_test_get_case_uses_negative_0() &&
         mbedtls_mpi_bitlen(X) == 0 && X->s != 1) {
         return 0;
     }
diff --git a/tests/suites/test_suite_dhm.function b/tests/suites/test_suite_dhm.function
index e6f75de..2090594 100644
--- a/tests/suites/test_suite_dhm.function
+++ b/tests/suites/test_suite_dhm.function
@@ -31,7 +31,7 @@
     int ok = 0;
     mbedtls_mpi_init(&actual);
 
-    ++mbedtls_test_info.step;
+    mbedtls_test_increment_step();
 
     TEST_ASSERT(size >= *offset + 2);
     n = (buffer[*offset] << 8) | buffer[*offset + 1];