Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve undefined sanitizer support. #318

Merged
merged 4 commits into from
Apr 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/ci_linux_clang.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,25 @@ jobs:
cc: "clang-14", cxx: "clang++-14",
cxx_standard: 20
}
- {
name: "Ubuntu 22.04 Clang with sanitizers",
os: ubuntu-22.04,
build_type: Debug,
cc: "clang", cxx: "clang++",
enable_sanitizers_in_tests: ON
}
steps:
- uses: actions/checkout@v2
- name: Build project
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DENABLE_TESTING=ON -DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }}
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-DENABLE_TESTING=ON \
-DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }} \
-DENABLE_SANITIZERS_IN_TESTS=${{ matrix.config.enable_sanitizers_in_tests }}
cmake --build build -j
- name: Run tests
run: |
Expand Down
13 changes: 12 additions & 1 deletion .github/workflows/ci_linux_gcc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,25 @@ jobs:
cc: "gcc-12", cxx: "g++-12",
cxx_standard: 20
}
- {
name: "Ubuntu 22.04 GCC with sanitizers",
os: ubuntu-22.04,
build_type: Debug,
cc: "gcc", cxx: "g++",
enable_sanitizers_in_tests: ON
}
steps:
- uses: actions/checkout@v2
- name: Build project
env:
CC: ${{ matrix.config.cc }}
CXX: ${{ matrix.config.cxx }}
run: |
cmake -S . -B build -DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} -DENABLE_TESTING=ON -DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }}
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=${{ matrix.config.build_type }} \
-DENABLE_TESTING=ON \
-DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }} \
-DENABLE_SANITIZERS_IN_TESTS=${{ matrix.config.enable_sanitizers_in_tests }}
cmake --build build -j
- name: Run tests
run: |
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/ci_windows_msvc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ jobs:
- uses: actions/checkout@v2
- name: Build project
run: |
cmake -S . -B build -G "${{ matrix.config.generator }}" -A ${{ matrix.config.architecture }} -DENABLE_TESTING=ON -DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }}
cmake -S . -B build \
-G "${{ matrix.config.generator }}" \
-A ${{ matrix.config.architecture }} \
-DENABLE_TESTING=ON \
-DOVERRIDE_CXX_STANDARD_FOR_TESTS=${{ matrix.config.cxx_standard }}
cmake --build build --config ${{ matrix.config.build_type }} -j
- name: Run tests
run: |
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ cmake_minimum_required(VERSION 3.14)

project(FakeIt VERSION 2.3.2 LANGUAGES CXX)

option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang." OFF)
option(ENABLE_TESTING "Enable build of tests." OFF)
option(OVERRIDE_CXX_STANDARD_FOR_TESTS "Override the C++ standard used for building tests." "")
option(ENABLE_SANITIZERS_IN_TESTS "Enable address / undefined sanitizers in tests." OFF)
option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang." OFF)

# Directory containing main targets of FakeIt.
add_subdirectory(include)
Expand Down
6 changes: 6 additions & 0 deletions include/mockutils/Macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,9 @@
#else
# define FAKEIT_CPLUSPLUS __cplusplus
#endif

#ifdef __GNUG__
# define FAKEIT_DISARM_UBSAN __attribute__((no_sanitize("undefined")))
#else
# define FAKEIT_DISARM_UBSAN
#endif
2 changes: 2 additions & 0 deletions include/mockutils/VTUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include <functional>
#include <type_traits>
#include "mockutils/Macros.hpp"
#include "mockutils/VirtualOffestSelector.hpp"
#include "mockutils/union_cast.hpp"

Expand Down Expand Up @@ -37,6 +38,7 @@ namespace fakeit {
#endif

template<typename C>
FAKEIT_DISARM_UBSAN
static typename std::enable_if<std::has_virtual_destructor<C>::value, unsigned int>::type
getDestructorOffset() {
VirtualOffsetSelector offsetSelctor;
Expand Down
11 changes: 11 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ if(OVERRIDE_CXX_STANDARD_FOR_TESTS)
message(STATUS "Building tests in C++${OVERRIDE_CXX_STANDARD_FOR_TESTS}.")
endif()

if(ENABLE_SANITIZERS_IN_TESTS)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
target_compile_options(FakeIt_tests PRIVATE -fsanitize=address,undefined -fno-sanitize-recover=address,undefined)
target_link_options(FakeIt_tests PRIVATE -fsanitize=address,undefined -fno-sanitize-recover=address,undefined)
target_compile_definitions(FakeIt_tests PRIVATE FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS)
message(STATUS "Sanitizers enabled: address, undefined.")
else()
message(SEND_ERROR "Sanitizers requested but compiler is not compatible.")
endif()
endif()

if(ENABLE_COVERAGE)
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES "^(Apple)?Clang$")
target_compile_options(FakeIt_tests PRIVATE --coverage)
Expand Down
4 changes: 4 additions & 0 deletions tests/default_behaviore_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ struct DefaultBehavioreTests : tpunit::TestFixture {
TEST(DefaultBehavioreTests::DefaultBeaviorOfVoidFunctionsIsToDoNothing), //
TEST(DefaultBehavioreTests::ReturnByValue_ReturnDefaultConstructedObject), //
TEST(DefaultBehavioreTests::ReturnByValue_ThrowExceptionIfNotDefaultConstructible), //
#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
TEST(DefaultBehavioreTests::ReturnByReference_ReturnReferenceToNullIfAbstract), //
#endif
TEST(DefaultBehavioreTests::ReturnByReference_ReturnReferenceToDefaultConstructedObject), //
#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
TEST(DefaultBehavioreTests::ReturnByReference_ReturnReferenceToNullIfNotDefaultConstructible), //
#endif
TEST(DefaultBehavioreTests::ReturnPtr_NullPtrIfPtrToAbstract),
TEST(DefaultBehavioreTests::production_shared_ptr_mock_used_in_invocation)
//TEST(DefaultBehavioreTests::should_survive_delete_of_mock_instance_by_user)
Expand Down
30 changes: 23 additions & 7 deletions tests/referece_types_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,30 +57,41 @@ struct ReferenceTypesTests: tpunit::TestFixture {

void implicitStubbingDefaultReturnValues() {
Mock<ReferenceInterface> mock;
#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
Fake( //
Method(mock,returnIntByRef), //
Method(mock,returnAbstractTypeByRef), //
Method(mock,returnConcreteTypeByRef) //
);
#else
Fake( //
Method(mock,returnIntByRef), //
Method(mock,returnConcreteTypeByRef) //
);
#endif

ReferenceInterface & i = mock.get();

// Fundamental types are initiated to 0.
// Return a reference to the default value.
ASSERT_EQUAL(0, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(ConcreteType(), i.returnConcreteTypeByRef());

#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
// For abstract types return a reference to nullptr.
ASSERT_EQUAL(nullptr, &i.returnAbstractTypeByRef());
#endif
}

void explicitStubbingDefualtReturnValues() {
Mock<ReferenceInterface> mock; //
When(Method(mock,returnIntByRef)).Return(); //
#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
When(Method(mock,returnAbstractTypeByRef)).Return(); //
#endif
When(Method(mock,returnConcreteTypeByRef)).Return(); //

ReferenceInterface & i = mock.get();
Expand All @@ -89,12 +100,14 @@ struct ReferenceTypesTests: tpunit::TestFixture {
// Return a reference to the default value.
ASSERT_EQUAL(0, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(ConcreteType(), i.returnConcreteTypeByRef());

#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
// For abstract types return a reference to nullptr.
ASSERT_EQUAL(nullptr, &i.returnAbstractTypeByRef());
#endif
}

void explicitStubbingReturnValues() {
Expand All @@ -113,7 +126,7 @@ struct ReferenceTypesTests: tpunit::TestFixture {
// Return a reference to the default value.
ASSERT_EQUAL(1, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(&c, &i.returnConcreteTypeByRef());

Expand All @@ -137,7 +150,7 @@ struct ReferenceTypesTests: tpunit::TestFixture {
// Return a reference to the default value.
ASSERT_EQUAL(1, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(&c, &i.returnConcreteTypeByRef());

Expand All @@ -161,7 +174,7 @@ struct ReferenceTypesTests: tpunit::TestFixture {
// Return a reference to the default value.
ASSERT_EQUAL(1, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(&c, &i.returnConcreteTypeByRef());

Expand All @@ -172,7 +185,9 @@ struct ReferenceTypesTests: tpunit::TestFixture {
void explicitStubbingDefualtReturnValues_with_AlwaysReturn() {
Mock<ReferenceInterface> mock;
When(Method(mock,returnIntByRef)).AlwaysReturn();
#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
When(Method(mock,returnAbstractTypeByRef)).AlwaysReturn(); //
#endif
When(Method(mock,returnConcreteTypeByRef)).AlwaysReturn(); //

ReferenceInterface & i = mock.get();
Expand All @@ -181,13 +196,14 @@ struct ReferenceTypesTests: tpunit::TestFixture {
// Return a reference to the default value.
ASSERT_EQUAL(0, i.returnIntByRef());

// Concrete types types are initiated by default ctor.
// Concrete types are initiated by default ctor.
// Return a reference to the default value.
ASSERT_EQUAL(ConcreteType(), i.returnConcreteTypeByRef());

#ifndef FAKEIT_DISABLE_UBSAN_TRIGGERING_TESTS
// For abstract types return a reference to nullptr.
ASSERT_EQUAL(nullptr, &i.returnAbstractTypeByRef());
#endif
}

} __ReferenceTypesTests;

2 changes: 0 additions & 2 deletions tests/stubbing_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#include <string>
#include <queue>

#include "mockutils/Macros.hpp"

#include "tpunit++.hpp"
#include "fakeit.hpp"

Expand Down