UnitTestFrameworkPkg: Use /MTd and enable Address Sanitizers

* Update host based unit test VS20xx builds to use /MTd instead of
  /MT to enable use of debug libraries for host based unit tests.
* Enable /fsanitize=address for host based unit test VS2019 builds
* Enable /fsanitize=address for host based unit test VS2022 builds
* Enable -fsanitize=address for host based unit test GCC builds
* Add UNIT_TESTING_ADDRESS_SANITIZER_ENABLE define that is set to
  TRUE by default so it is always enabled, but can be set to FALSE
  to temporarily disable during development/debug of unit tests.
* Add address sanitizer information to ReadMe.md

Enabling the Address Sanitizer can detect double frees, buffer
overflow, buffer underflow, access to invalid addresses, and
various exceptions. These can be detected in both the unit test
case sources as well as the code under test.

Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
This commit is contained in:
Michael D Kinney 2024-10-22 00:28:19 -07:00 committed by mergify[bot]
parent 8d0e23d998
commit de06288019
4 changed files with 71 additions and 9 deletions

View File

@ -28,6 +28,6 @@
UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
[BuildOptions]
MSFT:*_*_*_CC_FLAGS == /c /EHs /Zi /Od /MT
MSFT:*_*_*_CC_FLAGS == /c /EHs /Zi /Od /MTd
GCC:*_*_IA32_CC_FLAGS == -g -c -fshort-wchar -fexceptions -O0 -m32 -malign-double -fno-pie
GCC:*_*_X64_CC_FLAGS == -g -c -fshort-wchar -fexceptions -O0 -m64 -fno-pie "-DEFIAPI=__attribute__((ms_abi))"

View File

@ -31,6 +31,6 @@
UnitTestLib
[BuildOptions]
MSFT:*_*_*_CC_FLAGS == /c /EHs /Zi /Od /MT
MSFT:*_*_*_CC_FLAGS == /c /EHs /Zi /Od /MTd
GCC:*_*_IA32_CC_FLAGS == -g -c -fshort-wchar -fexceptions -O0 -m32 -malign-double -fno-pie
GCC:*_*_X64_CC_FLAGS == -g -c -fshort-wchar -fexceptions -O0 -m64 -fno-pie "-DEFIAPI=__attribute__((ms_abi))"

View File

@ -34,7 +34,22 @@ GoogleTest requires less overhead to register test suites and test cases compare
There are also a number of tools that layer on top of GoogleTest that improve developer productivity.
One example is the VS Code extension
[C++ TestMate](https://marketplace.visualstudio.com/items?itemName=matepek.vscode-catch2-test-adapter)
that may be used to implement, run, and debug unit tests implemented using GoogleTest.
that may be used to implement, run, and debug unit tests implemented using GoogleTest. The following
is an example of the C++ TestMate JSON configuration to find unit tests and configure the environment
for unit test execution.
```
"testMate.cpp.test.advancedExecutables": [
{
"pattern": "Build/**/*Test*",
"cwd": "${absDirpath}",
"env": {
"GTEST_CATCH_EXCEPTIONS": "0",
"ASAN_OPTIONS": "detect_leaks=0",
}
}
],
```
If a component can be tested with host-based unit tests, then GoogleTest is recommended. The MdePkg
contains a port of the BaseSafeIntLib unit tests in the GoogleTest style so the differences between
@ -69,6 +84,7 @@ reviewed. The paths to the SecureBootVariableLib unit tests are:
| JUNIT XML Reports | YES | YES |
| Execute subset of tests | NO | YES |
| VS Code Extensions | NO | YES |
| Address Sanitizer | Cmocka | YES |
## Framework Libraries
@ -1007,12 +1023,14 @@ See this example in `UnitTestFrameworkPkgHostTest.dsc`...
Also, based on the type of tests that are being created, the associated DSC include file from the
UnitTestFrameworkPkg for Host or Target based tests should also be included at the top of the DSC
file.
file. This provides the default defines and library class mappings requires for unit testing.
```
!include UnitTestFrameworkPkg/UnitTestFrameworkPkgHost.dsc.inc
```
> **NOTE**: DSC files for host based unit tests must **not** include default mappings from packages such as `MdePkg/MdeLibs.dsc.inc`. This DSC files provides default defines and library mappings for firmware builds that may not be compatible with host based unit test builds. Instead, the DSC file for host based unit tests must provide all the settings required for host based unit tests.
Lastly, in the case that the test build has specific dependent libraries associated with it,
they should be added in the \<LibraryClasses\> sub-section for the INF file in the
`[Components]` section of the DSC file. Note that it is within this sub-section where you can
@ -1373,6 +1391,15 @@ stuart_update -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022
stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg
```
#### Disabling Address Sanitizer
By default, the address sanitizer feature is enabled for all host based unit test builds. It can be disabled for
development/debug purposes by setting the DSC define `UNIT_TESTING_ADDRESS_SANITIZER_ENABLE` to `FALSE`.
```
stuart_ci_build -c ./.pytool/CISettings.py TOOL_CHAIN_TAG=VS2022 -t NOOPT -p MdePkg BLD_*_UNIT_TESTING_ADDRESS_SANITIZER_ENABLE=FALSE
```
### Evaluating the Results
In your immediate output, any build failures will be highlighted. You can see these below as "WARNING" and "ERROR" messages.
@ -1463,6 +1490,26 @@ c:\_uefi\MdePkg\Test\UnitTest\Library\BaseSafeIntLib\TestBaseSafeIntLib.c:35: er
</testcase>
```
### Manually Running Unit Test Executables
The host based unit test executed using `stuart_ci_build` sets up the environment to run host based unit tests
including environment variable settings. If host based unit test executable are run manually either from a
shell or using VS Code extensions such as `C++ TestMate`, then the environment must be setup correctly.
#### Windows Environment Variable Settings
```
set GTEST_CATCH_EXCEPTIONS=0
set ASAN_OPTIONS=detect_leaks=0
```
#### Linux Environment Variable Settings
```
export GTEST_CATCH_EXCEPTIONS=0
export ASAN_OPTIONS=detect_leaks=0
```
### XML Reporting Mode
Unit test applications using Framework are built using Cmocka that requires the

View File

@ -8,6 +8,9 @@
!include UnitTestFrameworkPkg/UnitTestFrameworkPkgCommon.dsc.inc
[Defines]
UNIT_TESTING_ADDRESS_SANITIZER_ENABLE = TRUE
[LibraryClasses.common.HOST_APPLICATION]
BaseLib|MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf
UnitTestHostBaseLib|MdePkg/Library/BaseLib/UnitTestHostBaseLib.inf
@ -26,10 +29,18 @@
NULL|MdePkg/Library/StackCheckLibNull/StackCheckLibNullHostApplication.inf
[BuildOptions]
MSFT:*_*_*_CC_FLAGS = /MT
MSFT:*_*_*_CC_FLAGS = /MTd
GCC:*_*_*_CC_FLAGS = -fno-pie
!if $(UNIT_TESTING_ADDRESS_SANITIZER_ENABLE)
#
# Enable Address Sanitizer for VS2019, VS2022, and GCC
#
MSFT:*_VS2019_*_CC_FLAGS = /fsanitize=address
MSFT:*_VS2022_*_CC_FLAGS = /fsanitize=address
GCC:*_*_*_CC_FLAGS = -fsanitize=address
!endif
!ifdef $(UNIT_TESTING_DEBUG)
MSFT:*_*_*_CC_FLAGS = /MTd -D UNIT_TESTING_DEBUG=1
MSFT:*_*_*_CC_FLAGS = -D UNIT_TESTING_DEBUG=1
GCC:*_*_*_CC_FLAGS = -D UNIT_TESTING_DEBUG=1
XCODE:*_*_*_CC_FLAGS = -D UNIT_TESTING_DEBUG=1
!endif
@ -41,9 +52,7 @@
# MSFT
#
MSFT:*_*_*_CC_FLAGS = /EHs
MSFT:*_*_*_DLINK_FLAGS == /out:"$(BIN_DIR)\$(MODULE_NAME_GUID).exe" /pdb:"$(BIN_DIR)\$(MODULE_NAME_GUID).pdb" /IGNORE:4001 /NOLOGO /SUBSYSTEM:CONSOLE /DEBUG /STACK:0x40000,0x40000 /WHOLEARCHIVE
MSFT:*_*_IA32_DLINK_FLAGS = /MACHINE:I386
MSFT:*_*_X64_DLINK_FLAGS = /MACHINE:AMD64
MSFT:*_*_*_DLINK_FLAGS == /nologo /SUBSYSTEM:CONSOLE /DEBUG /out:"$(BIN_DIR)\$(MODULE_NAME_GUID).exe" /pdb:"$(BIN_DIR)\$(MODULE_NAME_GUID).pdb"
MSFT:*_VS2015_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86"
MSFT:*_VS2015x86_IA32_DLINK_FLAGS = /LIBPATH:"%VS2015_PREFIX%Lib" /LIBPATH:"%VS2015_PREFIX%VC\Lib" /LIBPATH:"%UniversalCRTSdkDir%lib\%UCRTVersion%\ucrt\x86" /LIBPATH:"%WindowsSdkDir%lib\%WindowsSDKLibVersion%\um\x86"
@ -68,6 +77,12 @@
#
GCC:*_*_*_DLINK_FLAGS = -Wl,--whole-archive
GCC:*_*_*_DLINK2_FLAGS == -Wl,--no-whole-archive -lgcov -lpthread -lstdc++ -lm
!if $(UNIT_TESTING_ADDRESS_SANITIZER_ENABLE)
#
# Enable Address Sanitizer for GCC for HOST_APPLICATION
#
GCC:*_*_*_DLINK_FLAGS = -fsanitize=address
!endif
#
# Need to do this link via gcc and not ld as the pathing to libraries changes from OS version to OS version