Partially mitigate quadratic-time malloc tests in unit tests
Malloc failure testing is quadratic in the number of allocations. To test a failure at allocation N, we must first run the previous N-1 allocations. Now that we have combined GTest binaries, this does not work very well. Use the test listener to reset the counter across independent tests. We assume failures in a previous test won't interfere in the next one and run each test's counter in parallel. The assumption isn't *quite* true because we have a lot of internal init-once machinery that is reused across otherwise "independent" tests, but it's close enough that I was able to find some bugs, fixed in the next commit. That said, the tests still take too long to run to completion. Bug: 127 Change-Id: I6836793448fbdc740a8cc424361e6b3dd66fb8a6 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/56926 Reviewed-by: Bob Beck <bbe@google.com> Commit-Queue: David Benjamin <davidben@google.com>
This commit is contained in:
parent
a9ce915318
commit
5e356a8a9a
@ -225,6 +225,16 @@ typedef __uint128_t uint128_t;
|
||||
#define OPENSSL_SSE2
|
||||
#endif
|
||||
|
||||
#if defined(BORINGSSL_MALLOC_FAILURE_TESTING)
|
||||
// OPENSSL_reset_malloc_counter_for_testing, when malloc testing is enabled,
|
||||
// resets the internal malloc counter, to simulate further malloc failures. This
|
||||
// should be called in between independent tests, at a point where failure from
|
||||
// a previous test will not impact subsequent ones.
|
||||
OPENSSL_EXPORT void OPENSSL_reset_malloc_counter_for_testing(void);
|
||||
#else
|
||||
OPENSSL_INLINE void OPENSSL_reset_malloc_counter_for_testing(void) {}
|
||||
#endif
|
||||
|
||||
|
||||
// Pointer utility functions.
|
||||
|
||||
|
14
crypto/mem.c
14
crypto/mem.c
@ -146,11 +146,14 @@ static struct CRYPTO_STATIC_MUTEX malloc_failure_lock =
|
||||
CRYPTO_STATIC_MUTEX_INIT;
|
||||
static uint64_t current_malloc_count = 0;
|
||||
static uint64_t malloc_number_to_fail = 0;
|
||||
static int malloc_failure_enabled = 0, break_on_malloc_fail = 0;
|
||||
static int malloc_failure_enabled = 0, break_on_malloc_fail = 0,
|
||||
any_malloc_failed = 0;
|
||||
|
||||
static void malloc_exit_handler(void) {
|
||||
CRYPTO_STATIC_MUTEX_lock_read(&malloc_failure_lock);
|
||||
if (malloc_failure_enabled && current_malloc_count > malloc_number_to_fail) {
|
||||
if (any_malloc_failed) {
|
||||
// Signal to the test driver that some allocation failed, so it knows to
|
||||
// increment the counter and continue.
|
||||
_exit(88);
|
||||
}
|
||||
CRYPTO_STATIC_MUTEX_unlock_read(&malloc_failure_lock);
|
||||
@ -183,6 +186,7 @@ static int should_fail_allocation() {
|
||||
CRYPTO_STATIC_MUTEX_lock_write(&malloc_failure_lock);
|
||||
int should_fail = current_malloc_count == malloc_number_to_fail;
|
||||
current_malloc_count++;
|
||||
any_malloc_failed = any_malloc_failed || should_fail;
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(&malloc_failure_lock);
|
||||
|
||||
if (should_fail && break_on_malloc_fail) {
|
||||
@ -194,6 +198,12 @@ static int should_fail_allocation() {
|
||||
return should_fail;
|
||||
}
|
||||
|
||||
void OPENSSL_reset_malloc_counter_for_testing(void) {
|
||||
CRYPTO_STATIC_MUTEX_lock_write(&malloc_failure_lock);
|
||||
current_malloc_count = 0;
|
||||
CRYPTO_STATIC_MUTEX_unlock_write(&malloc_failure_lock);
|
||||
}
|
||||
|
||||
#else
|
||||
static int should_fail_allocation(void) { return 0; }
|
||||
#endif
|
||||
|
@ -31,13 +31,15 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#include "../internal.h"
|
||||
|
||||
|
||||
BSSL_NAMESPACE_BEGIN
|
||||
|
||||
class ErrorTestEventListener : public testing::EmptyTestEventListener {
|
||||
class TestEventListener : public testing::EmptyTestEventListener {
|
||||
public:
|
||||
ErrorTestEventListener() {}
|
||||
~ErrorTestEventListener() override {}
|
||||
TestEventListener() {}
|
||||
~TestEventListener() override {}
|
||||
|
||||
void OnTestEnd(const testing::TestInfo &test_info) override {
|
||||
if (test_info.result()->Failed()) {
|
||||
@ -48,6 +50,13 @@ class ErrorTestEventListener : public testing::EmptyTestEventListener {
|
||||
// error queue without printing.
|
||||
ERR_clear_error();
|
||||
}
|
||||
|
||||
// Malloc failure testing is quadratic in the number of mallocs. Running
|
||||
// multiple tests sequentially thus scales badly. Reset the malloc counter
|
||||
// between tests. This way we will test, each test with the first allocation
|
||||
// failing, then the second, and so on, until the test with the most
|
||||
// allocations runs out.
|
||||
OPENSSL_reset_malloc_counter_for_testing();
|
||||
}
|
||||
};
|
||||
|
||||
@ -75,8 +84,7 @@ inline void SetupGoogleTest() {
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
testing::UnitTest::GetInstance()->listeners().Append(
|
||||
new ErrorTestEventListener);
|
||||
testing::UnitTest::GetInstance()->listeners().Append(new TestEventListener);
|
||||
}
|
||||
|
||||
BSSL_NAMESPACE_END
|
||||
|
Loading…
x
Reference in New Issue
Block a user