diff --git a/programs/ssl/ssl_test_lib.c b/programs/ssl/ssl_test_lib.c index 7616b69efb..a65332ae13 100644 --- a/programs/ssl/ssl_test_lib.c +++ b/programs/ssl/ssl_test_lib.c @@ -427,7 +427,7 @@ int test_hooks_failure_detected(void) 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 82ecf953b1..8e798cd4cd 100644 --- a/programs/test/metatest.c +++ b/programs/test/metatest.c @@ -344,9 +344,11 @@ int main(int argc, char *argv[]) #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 2f6bf89317..a5e49cbe57 100644 --- a/tests/include/test/bignum_helpers.h +++ b/tests/include/test/bignum_helpers.h @@ -77,14 +77,14 @@ void mbedtls_test_mpi_mod_modulus_free_with_limbs(mbedtls_mpi_mod_modulus *N); * * - 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 @@ void mbedtls_test_mpi_mod_modulus_free_with_limbs(mbedtls_mpi_mod_modulus *N); */ 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 36588681c8..d08100f158 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 @@ -61,20 +66,128 @@ typedef enum { 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_fail(const char *test, int line_no, const char *filename); 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 c85e2caafa..913f5e3870 100644 --- a/tests/src/bignum_helpers.c +++ b/tests/src/bignum_helpers.c @@ -135,7 +135,7 @@ int mbedtls_test_read_mpi(mbedtls_mpi *X, const char *s) } 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 eb28919b8d..da0b54a00a 100644 --- a/tests/src/helpers.c +++ b/tests/src/helpers.c @@ -13,6 +13,10 @@ #include #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 @@ int mbedtls_test_platform_setup(void) 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 @@ int mbedtls_test_ascii2uc(const char c, unsigned char *uc) 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 @@ int mbedtls_test_equal(const char *test, int line_no, const char *filename, 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 @@ int mbedtls_test_le_u(const char *test, int line_no, const char *filename, 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 @@ int mbedtls_test_le_s(const char *test, int line_no, const char *filename, 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 5a871e102d..ff0c712faf 100644 --- a/tests/src/threading_helpers.c +++ b/tests/src/threading_helpers.c @@ -175,9 +175,7 @@ static void mbedtls_test_mutex_usage_error(mbedtls_threading_mutex_t *mutex, { (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 @@ static void mbedtls_test_mutex_usage_error(mbedtls_threading_mutex_t *mutex, * 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 @@ static int mbedtls_test_wrap_mutex_lock(mbedtls_threading_mutex_t *mutex) * 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 @@ static int mbedtls_test_wrap_mutex_unlock(mbedtls_threading_mutex_t *mutex) /* 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 @@ void mbedtls_test_mutex_usage_check(void) * 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 cc286973cf..eb42a07eba 100644 --- a/tests/suites/host_test.function +++ b/tests/suites/host_test.function @@ -371,14 +371,12 @@ static void write_outcome_entry(FILE *outcome_file, * \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 @@ static void write_outcome_result(FILE *outcome_file, } break; } - switch (info->result) { + switch (mbedtls_test_get_result()) { case MBEDTLS_TEST_RESULT_SUCCESS: mbedtls_fprintf(outcome_file, "PASS;"); break; @@ -410,8 +408,9 @@ static void write_outcome_result(FILE *outcome_file, 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 @@ int execute_tests(int argc, const char **argv) 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 @@ int execute_tests(int argc, const char **argv) 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 @@ int execute_tests(int argc, const char **argv) 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 2305f488cd..50be2d2f17 100644 --- a/tests/suites/test_suite_bignum.function +++ b/tests/suites/test_suite_bignum.function @@ -24,7 +24,7 @@ static int sign_is_valid(const mbedtls_mpi *X) * 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 e6f75de777..20905940ba 100644 --- a/tests/suites/test_suite_dhm.function +++ b/tests/suites/test_suite_dhm.function @@ -31,7 +31,7 @@ static int check_dhm_param_output(const mbedtls_mpi *expected, 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];