From 5693a7452f6ef8172266afe9a5d54d2e8ee1dcb1 Mon Sep 17 00:00:00 2001 From: otrempe Date: Wed, 9 Nov 2022 13:00:40 -0500 Subject: [PATCH 1/5] Added a test showing up the problem --- tests/all_tests.vcxproj | 3 +++ tests/multiple_translation_units_stub.cpp | 12 ++++++++++ tests/multiple_translation_units_stub.h | 13 ++++++++++ .../multiple_translation_units_stub_test.cpp | 24 +++++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 tests/multiple_translation_units_stub.cpp create mode 100644 tests/multiple_translation_units_stub.h create mode 100644 tests/multiple_translation_units_stub_test.cpp diff --git a/tests/all_tests.vcxproj b/tests/all_tests.vcxproj index 52a71b7b..3e0e0df4 100644 --- a/tests/all_tests.vcxproj +++ b/tests/all_tests.vcxproj @@ -135,6 +135,8 @@ + + @@ -151,6 +153,7 @@ + diff --git a/tests/multiple_translation_units_stub.cpp b/tests/multiple_translation_units_stub.cpp new file mode 100644 index 00000000..6f2dc0bb --- /dev/null +++ b/tests/multiple_translation_units_stub.cpp @@ -0,0 +1,12 @@ +#include "multiple_translation_units_stub.h" + + +void stubFunc2(fakeit::Mock& mock) +{ + fakeit::When(Method(mock, func2)).AlwaysReturn("String"); +} + +void stubFunc(fakeit::Mock& mock) +{ + fakeit::When(Method(mock, func)).AlwaysReturn(3); +} diff --git a/tests/multiple_translation_units_stub.h b/tests/multiple_translation_units_stub.h new file mode 100644 index 00000000..084cf17b --- /dev/null +++ b/tests/multiple_translation_units_stub.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +#include "fakeit.hpp" + +struct SomeInterface { + virtual int func() = 0; + virtual std::string func2() = 0; +}; + +void stubFunc2(fakeit::Mock& mock); +void stubFunc(fakeit::Mock& mock); diff --git a/tests/multiple_translation_units_stub_test.cpp b/tests/multiple_translation_units_stub_test.cpp new file mode 100644 index 00000000..75cf43f4 --- /dev/null +++ b/tests/multiple_translation_units_stub_test.cpp @@ -0,0 +1,24 @@ +#include "tpunit++.hpp" +#include "fakeit.hpp" +#include "multiple_translation_units_stub.h" + +using namespace fakeit; + +struct MultipleTranslationUnitsStub : tpunit::TestFixture { + MultipleTranslationUnitsStub() + : tpunit::TestFixture( + TEST(MultipleTranslationUnitsStub::NoCollidingIds) + ) + {} + + void NoCollidingIds() { + Mock mock; + SomeInterface &i = mock.get(); + + stubFunc2(mock); + When(Method(mock, func)).Return(1); + + mock.get().func2(); // Uncatchable write access violation if ids collide + } + +} __MultipleTranslationUnitsStub; From e34f820cbad8084f1079f84925193dc56b7d9b6c Mon Sep 17 00:00:00 2001 From: otrempe Date: Wed, 9 Nov 2022 09:05:15 -0500 Subject: [PATCH 2/5] Unique MockingContext ids across translation units --- include/fakeit/Mock.hpp | 16 ++++++++-------- include/fakeit/MockImpl.hpp | 6 +++--- include/fakeit/api_macros.hpp | 16 +++++++++++++--- include/mockutils/DynamicProxy.hpp | 14 +++++++------- include/mockutils/MethodProxy.hpp | 6 +++--- include/mockutils/MethodProxyCreator.hpp | 8 ++++---- include/mockutils/VTUtils.hpp | 2 +- include/mockutils/constexpr_hash.hpp | 21 +++++++++++++++++++++ include/mockutils/mscpp/VirtualTable.hpp | 6 +++--- tests/FakeIt.vcxproj | 1 + 10 files changed, 64 insertions(+), 32 deletions(-) create mode 100644 include/mockutils/constexpr_hash.hpp diff --git a/include/fakeit/Mock.hpp b/include/fakeit/Mock.hpp index 30821951..9d94308c 100644 --- a/include/fakeit/Mock.hpp +++ b/include/fakeit/Mock.hpp @@ -57,55 +57,55 @@ namespace fakeit { return impl.stubDataMember(member, ctorargs...); } - template::value && std::is_base_of::value>::type> MockingContext stub(R (T::*vMethod)(arglist...) const) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...)) { return impl.template stubMethod(vMethod); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...) const volatile) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); return impl.template stubMethod(methodWithoutConstVolatile); } - template::value && std::is_base_of::value>::type> MockingContext stub(R(T::*vMethod)(arglist...)) { auto methodWithoutConstVolatile = reinterpret_cast(vMethod); diff --git a/include/fakeit/MockImpl.hpp b/include/fakeit/MockImpl.hpp index 2b8b63a2..bca8c53b 100644 --- a/include/fakeit/MockImpl.hpp +++ b/include/fakeit/MockImpl.hpp @@ -89,7 +89,7 @@ namespace fakeit { return DataMemberStubbingRoot(); } - template::value>::type> + template::value>::type> MockingContext stubMethod(R(T::*vMethod)(arglist...)) { return MockingContext(new UniqueMethodMockingContextImpl < id, R, arglist... > (*this, vMethod)); @@ -212,7 +212,7 @@ namespace fakeit { }; - template + template class UniqueMethodMockingContextImpl : public MethodMockingContextImpl { protected: @@ -304,7 +304,7 @@ namespace fakeit { return origMethodPtr; } - template + template RecordedMethodBody &stubMethodIfNotStubbed(DynamicProxy &proxy, R (C::*vMethod)(arglist...)) { if (!proxy.isMethodStubbed(vMethod)) { diff --git a/include/fakeit/api_macros.hpp b/include/fakeit/api_macros.hpp index 966b47af..e28d6c76 100644 --- a/include/fakeit/api_macros.hpp +++ b/include/fakeit/api_macros.hpp @@ -1,9 +1,19 @@ #pragma once +#include "mockutils/constexpr_hash.hpp" + #ifdef _MSC_VER #define __func__ __FUNCTION__ #endif +#define COUNTER_STRINGIFY( counter ) #counter + +#define STUB_ID_STR( counter ) \ + __FILE__ COUNTER_STRINGIFY(counter) + +#define STUB_ID(counter) \ + fakeit::constExprHash(STUB_ID_STR(counter)) + #define MOCK_TYPE(mock) \ std::remove_reference::type @@ -17,13 +27,13 @@ (mock).dtor().setMethodDetails(#mock,"destructor") #define Method(mock, method) \ - (mock).template stub<__COUNTER__>(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) + (mock).template stub(&MOCK_TYPE(mock)::method).setMethodDetails(#mock,#method) #define OverloadedMethod(mock, method, prototype) \ - (mock).template stub<__COUNTER__>(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub(OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define ConstOverloadedMethod(mock, method, prototype) \ - (mock).template stub<__COUNTER__>(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) + (mock).template stub(CONST_OVERLOADED_METHOD_PTR( mock , method, prototype )).setMethodDetails(#mock,#method) #define Verify(...) \ Verify( __VA_ARGS__ ).setFileInfo(__FILE__, __LINE__, __func__) diff --git a/include/mockutils/DynamicProxy.hpp b/include/mockutils/DynamicProxy.hpp index f1f62844..d0e71a26 100644 --- a/include/mockutils/DynamicProxy.hpp +++ b/include/mockutils/DynamicProxy.hpp @@ -27,9 +27,9 @@ namespace fakeit { class InvocationHandlers : public InvocationHandlerCollection { std::vector> &_methodMocks; - std::vector &_offsets; + std::vector &_offsets; - unsigned int getOffset(unsigned int id) const + unsigned int getOffset(size_t id) const { unsigned int offset = 0; for (; offset < _offsets.size(); offset++) { @@ -43,15 +43,15 @@ namespace fakeit { public: InvocationHandlers( std::vector> &methodMocks, - std::vector &offsets) : + std::vector &offsets) : _methodMocks(methodMocks), _offsets(offsets) { - for (std::vector::iterator it = _offsets.begin(); it != _offsets.end(); ++it) + for (auto it = _offsets.begin(); it != _offsets.end(); ++it) { *it = std::numeric_limits::max(); } } - Destructible *getInvocatoinHandlerPtrById(unsigned int id) override { + Destructible *getInvocatoinHandlerPtrById(size_t id) override { unsigned int offset = getOffset(id); std::shared_ptr ptr = _methodMocks[offset]; return ptr.get(); @@ -100,7 +100,7 @@ namespace fakeit { { } - template + template void stubMethod(R(C::*vMethod)(arglist...), MethodInvocationHandler *methodInvocationHandler) { auto offset = VTUtils::getOffset(vMethod); MethodProxyCreator creator; @@ -189,7 +189,7 @@ namespace fakeit { // std::vector> _methodMocks; std::vector> _members; - std::vector _offsets; + std::vector _offsets; InvocationHandlers _invocationHandlers; FakeObject &getFake() { diff --git a/include/mockutils/MethodProxy.hpp b/include/mockutils/MethodProxy.hpp index b9945c65..66ee39d6 100644 --- a/include/mockutils/MethodProxy.hpp +++ b/include/mockutils/MethodProxy.hpp @@ -6,7 +6,7 @@ namespace fakeit { struct MethodProxy { - MethodProxy(unsigned int id, unsigned int offset, void *vMethod) : + MethodProxy(size_t id, unsigned int offset, void *vMethod) : _id(id), _offset(offset), _vMethod(vMethod) { @@ -16,7 +16,7 @@ namespace fakeit { return _offset; } - unsigned int getId() const { + size_t getId() const { return _id; } @@ -25,7 +25,7 @@ namespace fakeit { } private: - unsigned int _id; + size_t _id; unsigned int _offset; void *_vMethod; }; diff --git a/include/mockutils/MethodProxyCreator.hpp b/include/mockutils/MethodProxyCreator.hpp index 4ae0dfe5..739d9865 100644 --- a/include/mockutils/MethodProxyCreator.hpp +++ b/include/mockutils/MethodProxyCreator.hpp @@ -11,7 +11,7 @@ namespace fakeit { struct InvocationHandlerCollection { static const unsigned int VT_COOKIE_INDEX = 0; - virtual Destructible *getInvocatoinHandlerPtrById(unsigned int index) = 0; + virtual Destructible *getInvocatoinHandlerPtrById(size_t index) = 0; static InvocationHandlerCollection *getInvocationHandlerCollection(void *instance) { VirtualTableBase &vt = VirtualTableBase::getVTable(instance); @@ -29,14 +29,14 @@ namespace fakeit { public: - template + template MethodProxy createMethodProxy(unsigned int offset) { return MethodProxy(id, offset, union_cast(&MethodProxyCreator::methodProxyX < id > )); } protected: - R methodProxy(unsigned int id, const typename fakeit::production_arg::type... args) { + R methodProxy(size_t id, const typename fakeit::production_arg::type... args) { InvocationHandlerCollection *invocationHandlerCollection = InvocationHandlerCollection::getInvocationHandlerCollection( this); MethodInvocationHandler *invocationHandler = @@ -45,7 +45,7 @@ namespace fakeit { return invocationHandler->handleMethodInvocation(std::forward::type>(args)...); } - template + template R methodProxyX(arglist ... args) { return methodProxy(id, std::forward::type>(args)...); } diff --git a/include/mockutils/VTUtils.hpp b/include/mockutils/VTUtils.hpp index 109fcdac..d85ba07f 100644 --- a/include/mockutils/VTUtils.hpp +++ b/include/mockutils/VTUtils.hpp @@ -63,7 +63,7 @@ namespace fakeit { } template - static unsigned int getVTSize() { + static size_t getVTSize() { struct Derrived : public C { virtual void endOfVt() { } diff --git a/include/mockutils/constexpr_hash.hpp b/include/mockutils/constexpr_hash.hpp new file mode 100644 index 00000000..c504afe0 --- /dev/null +++ b/include/mockutils/constexpr_hash.hpp @@ -0,0 +1,21 @@ +#pragma once + +namespace fakeit { + + template + constexpr size_t constExprHash( const char (&str)[N] ) { + size_t _Val = 14695981039346656037ULL; // _FNV_offset_basis + constexpr size_t _FNV_prime = 1099511628211ULL; + + const char* pStr(str); + auto last = pStr + N - 1; + for (; pStr != last; ++pStr) + { + _Val ^= static_cast(*pStr); + _Val *= _FNV_prime; + } + + return _Val; + } + +} \ No newline at end of file diff --git a/include/mockutils/mscpp/VirtualTable.hpp b/include/mockutils/mscpp/VirtualTable.hpp index 029b5834..693a79c0 100644 --- a/include/mockutils/mscpp/VirtualTable.hpp +++ b/include/mockutils/mscpp/VirtualTable.hpp @@ -189,7 +189,7 @@ namespace fakeit { } void copyFrom(VirtualTable &from) { - unsigned int size = VTUtils::getVTSize(); + auto size = VTUtils::getVTSize(); for (unsigned int i = 0; i < size; i++) { _firstMethod[i] = from.getMethod(i); } @@ -233,7 +233,7 @@ namespace fakeit { setCookie(numOfCookies - 1, method); // use the last cookie } - unsigned int getSize() { + size_t getSize() { return VTUtils::getVTSize(); } @@ -259,7 +259,7 @@ namespace fakeit { static const unsigned int numOfCookies = 3; static void **buildVTArray() { - int vtSize = VTUtils::getVTSize(); + auto vtSize = VTUtils::getVTSize(); auto array = new void *[vtSize + numOfCookies + 1]{}; RTTICompleteObjectLocator *objectLocator = new RTTICompleteObjectLocator( typeid(C)); diff --git a/tests/FakeIt.vcxproj b/tests/FakeIt.vcxproj index 449a0568..b7c14392 100644 --- a/tests/FakeIt.vcxproj +++ b/tests/FakeIt.vcxproj @@ -78,6 +78,7 @@ + From 7f40ec6989ba3ae71069dfd792101176da457016 Mon Sep 17 00:00:00 2001 From: otrempe Date: Wed, 9 Nov 2022 14:42:16 -0500 Subject: [PATCH 3/5] C++11 compliant constExprHash --- include/mockutils/constexpr_hash.hpp | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/include/mockutils/constexpr_hash.hpp b/include/mockutils/constexpr_hash.hpp index c504afe0..0a3822c6 100644 --- a/include/mockutils/constexpr_hash.hpp +++ b/include/mockutils/constexpr_hash.hpp @@ -2,20 +2,16 @@ namespace fakeit { - template - constexpr size_t constExprHash( const char (&str)[N] ) { - size_t _Val = 14695981039346656037ULL; // _FNV_offset_basis - constexpr size_t _FNV_prime = 1099511628211ULL; - - const char* pStr(str); - auto last = pStr + N - 1; - for (; pStr != last; ++pStr) - { - _Val ^= static_cast(*pStr); - _Val *= _FNV_prime; - } + constexpr size_t _FNV_prime = sizeof(size_t) == 4 ? 16777619ULL : 1099511628211ULL; + constexpr size_t _FNV_offset_basis = sizeof(size_t) == 4 ? 2166136261ULL : 14695981039346656037ULL; - return _Val; + constexpr size_t _constExprHashImpl(const char* str, size_t count) { + return count ? (_constExprHashImpl(str, count - 1) ^ str[count - 1]) * _FNV_prime : _FNV_offset_basis; + } + + template + constexpr size_t constExprHash(const char(&str)[N]) { + return _constExprHashImpl(str, N); } } \ No newline at end of file From 9811eb73f00ee686d9d65f7be14953a1da6a4778 Mon Sep 17 00:00:00 2001 From: otrempe Date: Wed, 9 Nov 2022 15:49:36 -0500 Subject: [PATCH 4/5] Added new source test file to build/sources.mk --- build/sources.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/build/sources.mk b/build/sources.mk index 45ac736f..9c0f94e0 100644 --- a/build/sources.mk +++ b/build/sources.mk @@ -13,6 +13,7 @@ CPP_SRCS += \ miscellaneous_tests.cpp \ msc_stubbing_multiple_values_tests.cpp \ msc_type_info_tests.cpp \ + multiple_translation_units_stub_test.cpp \ overloadded_methods_tests.cpp \ referece_types_tests.cpp \ remove_const_volatile_tests.cpp \ From 2230a37a81a065cb2c0caf73cfb84ce1d5dc8ff6 Mon Sep 17 00:00:00 2001 From: otrempe Date: Wed, 9 Nov 2022 15:58:22 -0500 Subject: [PATCH 5/5] Helper file needed as well in build/sources.mk --- build/sources.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/build/sources.mk b/build/sources.mk index 9c0f94e0..21add538 100644 --- a/build/sources.mk +++ b/build/sources.mk @@ -13,6 +13,7 @@ CPP_SRCS += \ miscellaneous_tests.cpp \ msc_stubbing_multiple_values_tests.cpp \ msc_type_info_tests.cpp \ + multiple_translation_units_stub.cpp \ multiple_translation_units_stub_test.cpp \ overloadded_methods_tests.cpp \ referece_types_tests.cpp \