boringssl/crypto/abi_self_test.cc
David Benjamin e592d595c4 Add direction flag checking to CHECK_ABI.
Linux and Windows ABIs both require that the direction flag be cleared
on function exit, so that functions can rely on it being cleared on
entry. (Some OpenSSL assembly preserves it, which is stronger, but we
only require what is specified by the ABI so CHECK_ABI works with C
compiler output.)

Change-Id: I1a320aed4371176b4b44fe672f1a90167b84160f
Reviewed-on: https://boringssl-review.googlesource.com/c/34187
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
2019-01-09 03:22:15 +00:00

211 lines
8.4 KiB
C++

/* Copyright (c) 2018, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include <gtest/gtest.h>
#include <gtest/gtest-spi.h>
#include <openssl/rand.h>
#include "test/abi_test.h"
#if defined(OPENSSL_WINDOWS)
#include <windows.h>
#endif
static bool test_function_ok;
static int TestFunction(int a1, int a2, int a3, int a4, int a5, int a6, int a7,
int a8, int a9, int a10) {
test_function_ok = a1 == 1 || a2 == 2 || a3 == 3 || a4 == 4 || a5 == 5 ||
a6 == 6 || a7 == 7 || a8 == 8 || a9 == 9 || a10 == 10;
return 42;
}
TEST(ABITest, SanityCheck) {
EXPECT_NE(0, CHECK_ABI(strcmp, "hello", "world"));
test_function_ok = false;
EXPECT_EQ(42, CHECK_ABI(TestFunction, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
EXPECT_TRUE(test_function_ok);
#if defined(SUPPORTS_ABI_TEST)
abi_test::internal::CallerState state;
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
const char *arg1 = "hello", *arg2 = "world";
crypto_word_t argv[2] = {
reinterpret_cast<crypto_word_t>(arg1),
reinterpret_cast<crypto_word_t>(arg2),
};
CHECK_ABI(abi_test_trampoline, reinterpret_cast<crypto_word_t>(strcmp),
&state, argv, 2, 0 /* no breakpoint */);
if (abi_test::UnwindTestsEnabled()) {
EXPECT_NONFATAL_FAILURE(CHECK_ABI(abi_test_bad_unwind_wrong_register),
"was not recovered unwinding");
EXPECT_NONFATAL_FAILURE(CHECK_ABI(abi_test_bad_unwind_temporary),
"was not recovered unwinding");
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_wrong_register);
CHECK_ABI_NO_UNWIND(abi_test_bad_unwind_temporary);
}
#endif // SUPPORTS_ABI_TEST
}
#if defined(OPENSSL_X86_64) && defined(SUPPORTS_ABI_TEST)
extern "C" {
void abi_test_clobber_rax(void);
void abi_test_clobber_rbx(void);
void abi_test_clobber_rcx(void);
void abi_test_clobber_rdx(void);
void abi_test_clobber_rsi(void);
void abi_test_clobber_rdi(void);
void abi_test_clobber_rbp(void);
void abi_test_clobber_r8(void);
void abi_test_clobber_r9(void);
void abi_test_clobber_r10(void);
void abi_test_clobber_r11(void);
void abi_test_clobber_r12(void);
void abi_test_clobber_r13(void);
void abi_test_clobber_r14(void);
void abi_test_clobber_r15(void);
void abi_test_clobber_xmm0(void);
void abi_test_clobber_xmm1(void);
void abi_test_clobber_xmm2(void);
void abi_test_clobber_xmm3(void);
void abi_test_clobber_xmm4(void);
void abi_test_clobber_xmm5(void);
void abi_test_clobber_xmm6(void);
void abi_test_clobber_xmm7(void);
void abi_test_clobber_xmm8(void);
void abi_test_clobber_xmm9(void);
void abi_test_clobber_xmm10(void);
void abi_test_clobber_xmm11(void);
void abi_test_clobber_xmm12(void);
void abi_test_clobber_xmm13(void);
void abi_test_clobber_xmm14(void);
void abi_test_clobber_xmm15(void);
} // extern "C"
TEST(ABITest, X86_64) {
// abi_test_trampoline hides unsaved registers from the caller, so we can
// safely call the abi_test_clobber_* functions below.
abi_test::internal::CallerState state;
RAND_bytes(reinterpret_cast<uint8_t *>(&state), sizeof(state));
CHECK_ABI_NO_UNWIND(abi_test_trampoline,
reinterpret_cast<crypto_word_t>(abi_test_clobber_rbx),
&state, nullptr, 0, 0 /* no breakpoint */);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rax);
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbx),
"rbx was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_rcx);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdx);
#if defined(OPENSSL_WINDOWS)
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi),
"rdi was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi),
"rsi was not restored after return");
#else
CHECK_ABI_NO_UNWIND(abi_test_clobber_rdi);
CHECK_ABI_NO_UNWIND(abi_test_clobber_rsi);
#endif
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_rbp),
"rbp was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_r8);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r9);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r10);
CHECK_ABI_NO_UNWIND(abi_test_clobber_r11);
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r12),
"r12 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r13),
"r13 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r14),
"r14 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_r15),
"r15 was not restored after return");
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm0);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm1);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm2);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm3);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm4);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm5);
#if defined(OPENSSL_WINDOWS)
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6),
"xmm6 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7),
"xmm7 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8),
"xmm8 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9),
"xmm9 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10),
"xmm10 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11),
"xmm11 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12),
"xmm12 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13),
"xmm13 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14),
"xmm14 was not restored after return");
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15),
"xmm15 was not restored after return");
#else
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm6);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm7);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm8);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm9);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm10);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm11);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm12);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm13);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm14);
CHECK_ABI_NO_UNWIND(abi_test_clobber_xmm15);
#endif
EXPECT_NONFATAL_FAILURE(CHECK_ABI_NO_UNWIND(abi_test_set_direction_flag),
"Direction flag set after return");
EXPECT_EQ(0, abi_test_get_and_clear_direction_flag())
<< "CHECK_ABI did not insulate the caller from direction flag errors";
}
#if defined(OPENSSL_WINDOWS)
static void ThrowWindowsException() {
DebugBreak();
}
static void ExceptionTest() {
bool handled = false;
__try {
CHECK_ABI_NO_UNWIND(ThrowWindowsException);
} __except (GetExceptionCode() == EXCEPTION_BREAKPOINT
? EXCEPTION_EXECUTE_HANDLER
: EXCEPTION_CONTINUE_SEARCH) {
handled = true;
}
EXPECT_TRUE(handled);
}
// Test that the trampoline's SEH metadata works.
TEST(ABITest, TrampolineSEH) {
// Wrap the test in |CHECK_ABI|, to confirm the register-restoring annotations
// were correct.
CHECK_ABI_NO_UNWIND(ExceptionTest);
}
#endif // OPENSSL_WINDOWS
#endif // OPENSSL_X86_64 && SUPPORTS_ABI_TEST