Files
EDK2-fork/UnitTestFrameworkPkg/Test/GoogleTest/Sample/SampleGoogleTest/SampleGoogleTest.cpp
Michael D Kinney 1c73f0e71d UnitTestFrameworkPkg: Add failing unit tests cases for sanitizer
Add GoogleTest and Framework based unit tests that are expected
to fail and be caught by Address Sanitizer. These unit tests
verify that an address sanitizer is enabled and detecting the
following conditions. It also provide examples of the expected
output when an Address Sanitizer detected these types of issues.

* double free
* buffer overflow
* buffer underflow
* null ptr
* invalid address
* divide by zero

Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
2025-01-21 05:02:38 +00:00

445 lines
11 KiB
C++

/** @file
This is a sample to demonstrates the use of GoogleTest that supports host
execution environments.
Copyright (c) 2022, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include <Library/GoogleTestLib.h>
extern "C" {
#include <Uefi.h>
#include <Library/BaseLib.h>
#include <Library/DebugLib.h>
#include <Library/MemoryAllocationLib.h>
}
/**
Sample unit test that verifies the expected result of an unsigned integer
addition operation.
**/
TEST (SimpleMathTests, OnePlusOneShouldEqualTwo) {
UINTN A;
UINTN B;
UINTN C;
A = 1;
B = 1;
C = A + B;
ASSERT_EQ (C, (UINTN)2);
}
/**
Sample unit test that verifies that a global BOOLEAN is updatable.
**/
class GlobalBooleanVarTests : public ::testing::Test {
public:
BOOLEAN SampleGlobalTestBoolean = FALSE;
};
TEST_F (GlobalBooleanVarTests, GlobalBooleanShouldBeChangeable) {
SampleGlobalTestBoolean = TRUE;
ASSERT_TRUE (SampleGlobalTestBoolean);
SampleGlobalTestBoolean = FALSE;
ASSERT_FALSE (SampleGlobalTestBoolean);
}
/**
Sample unit test that logs a warning message and verifies that a global
pointer is updatable.
**/
class GlobalVarTests : public ::testing::Test {
public:
VOID *SampleGlobalTestPointer = NULL;
protected:
void
SetUp (
) override
{
ASSERT_EQ ((UINTN)SampleGlobalTestPointer, (UINTN)NULL);
}
void
TearDown (
)
{
SampleGlobalTestPointer = NULL;
}
};
TEST_F (GlobalVarTests, GlobalPointerShouldBeChangeable) {
SampleGlobalTestPointer = (VOID *)-1;
ASSERT_EQ ((UINTN)SampleGlobalTestPointer, (UINTN)((VOID *)-1));
}
/**
Set PcdDebugPropertyMask for each MacroTestsAssertsEnabledDisabled test
**/
class MacroTestsAssertsEnabledDisabled : public testing::TestWithParam<UINT8> {
void
SetUp (
)
{
PatchPcdSet8 (PcdDebugPropertyMask, GetParam ());
}
};
/**
Sample unit test using the ASSERT_TRUE() macro.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertTrue) {
UINT64 Result;
//
// This test passes because expression always evaluated to TRUE.
//
ASSERT_TRUE (TRUE);
//
// This test passes because expression always evaluates to TRUE.
//
Result = LShiftU64 (BIT0, 1);
ASSERT_TRUE (Result == BIT1);
}
/**
Sample unit test using the ASSERT_FALSE() macro.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertFalse) {
UINT64 Result;
//
// This test passes because expression always evaluated to FALSE.
//
ASSERT_FALSE (FALSE);
//
// This test passes because expression always evaluates to FALSE.
//
Result = LShiftU64 (BIT0, 1);
ASSERT_FALSE (Result == BIT0);
}
/**
Sample unit test using the ASSERT_EQ() macro.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertEqual) {
UINT64 Result;
//
// This test passes because both values are always equal.
//
ASSERT_EQ (1, 1);
//
// This test passes because both values are always equal.
//
Result = LShiftU64 (BIT0, 1);
ASSERT_EQ (Result, (UINT64)BIT1);
}
/**
Sample unit test using the ASSERT_STREQ() macro.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertMemEqual) {
CHAR8 *String1;
CHAR8 *String2;
//
// This test passes because String1 and String2 are the same.
//
String1 = (CHAR8 *)"Hello";
String2 = (CHAR8 *)"Hello";
ASSERT_STREQ (String1, String2);
}
/**
Sample unit test using the ASSERT_NE() macro.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertNotEqual) {
UINT64 Result;
//
// This test passes because both values are never equal.
//
ASSERT_NE (0, 1);
//
// This test passes because both values are never equal.
//
Result = LShiftU64 (BIT0, 1);
ASSERT_NE (Result, (UINT64)BIT0);
}
/**
Sample unit test using the ASSERT_TRUE() and ASSERT(FALSE)
and EFI_EFFOR() macros to check status
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertNotEfiError) {
//
// This test passes because the status is not an EFI error.
//
ASSERT_FALSE (EFI_ERROR (EFI_SUCCESS));
//
// This test passes because the status is not an EFI error.
//
ASSERT_FALSE (EFI_ERROR (EFI_WARN_BUFFER_TOO_SMALL));
}
/**
Sample unit test using the ASSERT_EQ() macro to compare EFI_STATUS values.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertStatusEqual) {
//
// This test passes because the status value are always equal.
//
ASSERT_EQ (EFI_SUCCESS, EFI_SUCCESS);
}
/**
Sample unit test using ASSERT_NE() macro to make sure a pointer is not NULL.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroAssertNotNull) {
UINT64 Result;
//
// This test passes because the pointer is never NULL.
//
ASSERT_NE (&Result, (UINT64 *)NULL);
}
/**
Sample unit test using that should not generate any ASSERTs()
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroExpectNoAssertFailure) {
//
// This test passes because it never triggers an ASSERT().
//
ASSERT (TRUE);
//
// This test passes because DecimalToBcd() does not ASSERT() if the
// value passed in is <= 99.
//
DecimalToBcd8 (99);
}
/**
Sample unit test using the EXPECT_ANY_THROW() macro to test expected ASSERT()s.
**/
TEST_P (MacroTestsAssertsEnabledDisabled, MacroExpectAssertFailure) {
//
// Skip tests that verify an ASSERT() is triggered if ASSERT()s are disabled.
//
if ((PcdGet8 (PcdDebugPropertyMask) & BIT0) == 0x00) {
return;
}
//
// This test passes because it directly triggers an ASSERT().
//
EXPECT_ANY_THROW (ASSERT (FALSE));
//
// This test passes because DecimalToBcd() generates an ASSERT() if the
// value passed in is >= 100. The expected ASSERT() is caught by the unit
// test framework and EXPECT_ANY_THROW() returns without an error.
//
EXPECT_ANY_THROW (DecimalToBcd8 (101));
//
// This test passes because DecimalToBcd() generates an ASSERT() if the
// value passed in is >= 100. The expected ASSERT() is caught by the unit
// test framework and throws the C++ exception of type std::runtime_error.
// EXPECT_THROW() returns without an error.
//
EXPECT_THROW (DecimalToBcd8 (101), std::runtime_error);
//
// This test passes because DecimalToBcd() generates an ASSERT() if the
// value passed in is >= 100. The expected ASSERT() is caught by the unit
// test framework and throws the C++ exception of type std::runtime_error with
// a message that includes the filename, linenumber, and the expression that
// triggered the ASSERT().
//
// EXPECT_THROW_MESSAGE() calls DecimalToBcd() expecting DecimalToBds() to
// throw a C++ exception of type std::runtime_error with a message that
// includes the expression of "Value < 100" that triggered the ASSERT().
//
EXPECT_THROW_MESSAGE (DecimalToBcd8 (101), "Value < 100");
}
INSTANTIATE_TEST_SUITE_P (
ValidInput,
MacroTestsAssertsEnabledDisabled,
::testing::Values (PcdGet8 (PcdDebugPropertyMask) | BIT0, PcdGet8 (PcdDebugPropertyMask) & (~BIT0))
);
/**
Sample unit test using the SCOPED_TRACE() macro for trace messages.
**/
TEST (MacroTestsMessages, MacroTraceMessage) {
//
// Example of logging.
//
SCOPED_TRACE ("SCOPED_TRACE message\n");
//
// Always pass
//
ASSERT_TRUE (TRUE);
}
/**
Sample unit test that performs double free
**/
TEST (SanitizerTests, DoubleFreeDeathTest) {
UINT8 *Pointer;
Pointer = (UINT8 *)AllocatePool (100);
ASSERT_NE (Pointer, (UINT8 *)NULL);
FreePool (Pointer);
//
// Second free that should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (FreePool (Pointer), "ERROR: AddressSanitizer: heap-use-after-free");
}
/**
Sample unit test that performs read past end of allocated buffer
**/
TEST (SanitizerTests, BufferOverflowReadDeathTest) {
UINT8 *Pointer;
UINT8 Value;
Pointer = (UINT8 *)AllocatePool (100);
ASSERT_NE (Pointer, (UINT8 *)NULL);
//
// Read past end of allocated buffer that should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (Value = Pointer[110], "ERROR: AddressSanitizer: heap-buffer-overflow");
ASSERT_EQ (Value, Value);
FreePool (Pointer);
}
/**
Sample unit test that performs write past end of allocated buffer
**/
TEST (SanitizerTests, BufferOverflowWriteDeathTest) {
UINT8 *Pointer;
Pointer = (UINT8 *)AllocatePool (100);
ASSERT_NE (Pointer, (UINT8 *)NULL);
//
// Write past end of allocated buffer that should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (Pointer[110] = 0, "ERROR: AddressSanitizer: heap-buffer-overflow");
FreePool (Pointer);
}
/**
Sample unit test that performs read before beginning of allocated buffer
**/
TEST (SanitizerTests, BufferUnderflowReadDeathTest) {
UINT8 *Pointer;
UINT8 Value;
Pointer = (UINT8 *)AllocatePool (100);
ASSERT_NE (Pointer, (UINT8 *)NULL);
//
// Read past end of allocated buffer that should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (Value = Pointer[-10], "ERROR: AddressSanitizer: heap-buffer-overflow");
ASSERT_EQ (Value, Value);
FreePool (Pointer);
}
/**
Sample unit test that performs read from address 0 (NULL)
**/
TEST (SanitizerTests, NullPointerReadDeathTest) {
UINT8 Value;
//
// Read from address 0 should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (Value = *(volatile UINT8 *)(NULL), "ERROR: AddressSanitizer: ");
ASSERT_EQ (Value, Value);
}
/**
Sample unit test that performs write to address 0 (NULL)
**/
TEST (SanitizerTests, NullPointerWriteDeathTest) {
//
// Write to address 0 should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (*(volatile UINT8 *)(NULL) = 0, "ERROR: AddressSanitizer: ");
}
/**
Sample unit test that performs read from invalid address -1
**/
TEST (SanitizerTests, InvalidPointerReadDeathTest) {
UINT8 Value;
//
// Read from address -1 should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (Value = *(volatile UINT8 *)(-1), "ERROR: AddressSanitizer: ");
ASSERT_EQ (Value, Value);
}
/**
Sample unit test that performs write to invalid address -1
**/
TEST (SanitizerTests, InvalidPointerWriteDeathTest) {
//
// Write to address -1 should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (*(volatile UINT8 *)(-1) = 0, "ERROR: AddressSanitizer: ");
}
UINTN
DivideWithNoParameterChecking (
UINTN Dividend,
UINTN Divisor
)
{
//
// Perform integer division with no check for divide by zero
//
return (Dividend / Divisor);
}
/**
Sample unit test that performs a divide by 0
**/
TEST (SanitizerTests, DivideByZeroDeathTest) {
//
// Divide by 0 should be caught by address sanitizer, log details, and exit
//
EXPECT_DEATH (DivideWithNoParameterChecking (10, 0), "ERROR: AddressSanitizer: ");
}
int
main (
int argc,
char *argv[]
)
{
testing::InitGoogleTest (&argc, argv);
return RUN_ALL_TESTS ();
}