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

Make test data thread safe
This commit is contained in:
Paul Elliott 2024-02-09 19:43:09 +00:00 committed by GitHub
commit 53ddf420c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 642 additions and 180 deletions

View file

@ -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;

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 @@ 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

View file

@ -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;
}

View file

@ -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 @@ 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;
}

View file

@ -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)

View file

@ -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);

View file

@ -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;
}

View file

@ -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];