Skip to content

Commit

Permalink
Merge pull request #11 from Alex0vSky/deadlock
Browse files Browse the repository at this point in the history
After merging minor changes
  • Loading branch information
Alex0vSky committed Oct 2, 2023
2 parents 34ba7a7 + 20c351f commit b71057d
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 19 deletions.
25 changes: 19 additions & 6 deletions include/gmock-win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -861,18 +861,31 @@ struct mock_module_##func \
#define MOCK_MODULE_FUNC_OVERLOAD(name, ...) MOCK_MODULE_UNITE(MOCK_MODULE_OVERLOAD(name, MOCK_MODULE_NBARG(__VA_ARGS__)), (__VA_ARGS__))
#define MOCK_MODULE_FUNC(r, m, ...) MOCK_MODULE_OVERLOAD(MOCK_MODULE_FUNC, MOCK_MODULE_NBARG(__VA_ARGS__))##(m, r(__VA_ARGS__))

#define MOCK_STDCALL_FUNC(r, m, ...) MOCK_MODULE_OVERLOAD(MOCK_MODULE_FUNC, MOCK_MODULE_NBARG(__VA_ARGS__)##_STDCALL_CONV)##(m, r(__VA_ARGS__))
#define MOCK_STDCALL_FUNC(r, m, ...) \
MOCK_MODULE_OVERLOAD(MOCK_MODULE_FUNC, MOCK_MODULE_NBARG(__VA_ARGS__)##_STDCALL_CONV)##(m, r(__VA_ARGS__)) \
__pragma(optimize("", on)) \
static void patchModuleFunc_##m() { \
::patchModuleFunc_( mock_module_##m::oldFn_, &::m, mock_module_##m::stub ); \
} \
__pragma(optimize("", off))

// Hidden from optimizer
template <typename TFunc, typename TStub>
void patchModuleFunc_(void* mock_module_func_oldFn, TFunc func, TStub stub) {
if (!mock_module_func_oldFn)
mockModule_patchModuleFunc(
func
, reinterpret_cast< void* >( stub )
, &mock_module_func_oldFn);
}

#define MOCK_CDECL_FUNC(r, m, ...) MOCK_MODULE_OVERLOAD(MOCK_MODULE_FUNC, MOCK_MODULE_NBARG(__VA_ARGS__)##__CDECL_CONV)##(m, r(__VA_ARGS__))

void mockModule_patchModuleFunc (void*, void*, void**);
void mockModule_restoreModuleFunc (void*, void*, void**);

#define EXPECT_MODULE_FUNC_CALL(func, ...) \
if (!mock_module_##func::oldFn_) \
{ \
::mockModule_patchModuleFunc(&func, reinterpret_cast< void* >( \
&mock_module_##func::stub), &mock_module_##func::oldFn_); \
} \
patchModuleFunc_##func( ); \
++gmock_win32::detail::lock; \
static_cast< decltype(EXPECT_CALL(mock_module_##func::instance(), \
func(__VA_ARGS__)))& >(gmock_win32::detail::make_proxy( \
Expand Down
81 changes: 68 additions & 13 deletions src/gmock-win32.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,56 @@ do { \

namespace {

typedef DWORD (WINAPI *pfnGetLastError_t)( VOID );
pfnGetLastError_t g_pfnGetLastError = nullptr;

typedef HANDLE (WINAPI *pfnGetCurrentProcess_t)( VOID );
pfnGetCurrentProcess_t g_pfnGetCurrentProcess = nullptr;

typedef BOOL (WINAPI *pfnWriteProcessMemory_t)(HANDLE hProcess, LPVOID lpBaseAddress, LPCVOID lpBuffer, SIZE_T nSize, SIZE_T* lpNumberOfBytesWritten);
pfnWriteProcessMemory_t g_pfnWriteProcessMemory = nullptr;

typedef BOOL (WINAPI *pfnVirtualProtect_t)(LPVOID lpAddress, SIZE_T dwSize, DWORD flNewProtect, PDWORD lpflOldProtect);
pfnVirtualProtect_t g_pfnVirtualProtect = nullptr;

typedef HMODULE (WINAPI *pfnGetModuleHandleA_t)(LPCSTR lpModuleName);
pfnGetModuleHandleA_t g_pfnGetModuleHandleA = nullptr;

typedef PVOID(__stdcall *pfnImageDirectoryEntryToDataEx_t)(PVOID Base, BOOLEAN MappedAsImage, USHORT DirectoryEntry, PULONG Size, PIMAGE_SECTION_HEADER *FoundHeader);
pfnImageDirectoryEntryToDataEx_t g_pfnImageDirectoryEntryToDataEx = nullptr;

static bool g_bInit = false;
bool init() {
HMODULE module;
module = LoadLibraryA( "kernel32.dll" );
if ( !module )
return false;
g_pfnGetLastError = (pfnGetLastError_t)GetProcAddress( module, "GetLastError" );
if ( !g_pfnGetLastError )
return false;
g_pfnGetCurrentProcess = (pfnGetCurrentProcess_t)GetProcAddress( module, "GetCurrentProcess" );
if ( !g_pfnGetCurrentProcess )
return false;
g_pfnWriteProcessMemory = (pfnWriteProcessMemory_t)GetProcAddress( module, "WriteProcessMemory" );
if ( !g_pfnWriteProcessMemory )
return false;
g_pfnVirtualProtect = (pfnVirtualProtect_t)GetProcAddress( module, "VirtualProtect" );
if ( !g_pfnVirtualProtect )
return false;
// Doesnt matter wchar_t or char, GetModuleHandleW or GetModuleHandleA
g_pfnGetModuleHandleA = (pfnGetModuleHandleA_t)GetProcAddress( module, "GetModuleHandleA" );
if ( !g_pfnGetModuleHandleA )
return false;
module = LoadLibraryA( "dbghelp.dll" );
if ( !module )
return false;
g_pfnImageDirectoryEntryToDataEx = (pfnImageDirectoryEntryToDataEx_t)GetProcAddress( module, "ImageDirectoryEntryToDataEx" );
if ( !g_pfnImageDirectoryEntryToDataEx )
return false;
g_bInit = true;
return true;
}

LONG WINAPI InvalidReadExceptionFilter(PEXCEPTION_POINTERS /*pep*/)
{
return EXCEPTION_EXECUTE_HANDLER;
Expand All @@ -40,7 +90,7 @@ namespace {
__try
{
*resultDescriptor = reinterpret_cast< PIMAGE_IMPORT_DESCRIPTOR >(
::ImageDirectoryEntryToDataEx(
g_pfnImageDirectoryEntryToDataEx(
base, TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ulSize, &pFoundHeader));
}
__except (InvalidReadExceptionFilter(GetExceptionInformation()))
Expand All @@ -50,7 +100,7 @@ namespace {
}

return *resultDescriptor ?
S_OK : HRESULT_FROM_WIN32(::GetLastError());
S_OK : HRESULT_FROM_WIN32(g_pfnGetLastError());
}

HRESULT writeProcessMemory(
Expand All @@ -59,26 +109,26 @@ namespace {
if (!address || !buffer)
return E_INVALIDARG;

const auto processHandle = ::GetCurrentProcess();
const auto processHandle = g_pfnGetCurrentProcess();

if (::WriteProcessMemory(processHandle, address, buffer, size, nullptr) == 0
&& (ERROR_NOACCESS == ::GetLastError()))
if (g_pfnWriteProcessMemory(processHandle, address, buffer, size, nullptr) == 0
&& (ERROR_NOACCESS == g_pfnGetLastError()))
{
DWORD oldProtect{ };
if (::VirtualProtect(address, size, PAGE_WRITECOPY, &oldProtect))
{
if (g_pfnVirtualProtect(address, size, PAGE_WRITECOPY, &oldProtect))
{
std::shared_ptr< void > finalAction(nullptr, [&](auto&&...) {
::VirtualProtect(address, size, oldProtect, &oldProtect);
g_pfnVirtualProtect(address, size, oldProtect, &oldProtect);
});

if (!::WriteProcessMemory(processHandle, address, buffer, size, nullptr))
return HRESULT_FROM_WIN32(::GetLastError());
if (!g_pfnWriteProcessMemory(processHandle, address, buffer, size, nullptr))
return HRESULT_FROM_WIN32(g_pfnGetLastError());

return S_OK;
}
else
{
return HRESULT_FROM_WIN32(::GetLastError());
return HRESULT_FROM_WIN32(g_pfnGetLastError());
}
}
else
Expand Down Expand Up @@ -134,7 +184,7 @@ namespace {

LPVOID* ppfn = nullptr;
RETURN_IF_FAILED(
findImportProc(::GetModuleHandle(nullptr), funcAddr, &ppfn));
findImportProc(g_pfnGetModuleHandleA(nullptr), funcAddr, &ppfn));

RETURN_IF_FAILED(
writeProcessMemory(ppfn, &newFunc, sizeof(ppfn)));
Expand All @@ -152,7 +202,7 @@ namespace {

LPVOID* ppfn = nullptr;
RETURN_IF_FAILED(
findImportProc(::GetModuleHandle(nullptr), stubFunc, &ppfn));
findImportProc(g_pfnGetModuleHandleA(nullptr), stubFunc, &ppfn));

return writeProcessMemory(ppfn, &origFunc, sizeof(ppfn));
}
Expand All @@ -162,13 +212,18 @@ namespace {
void mockModule_patchModuleFunc(
void* funcAddr, void* newFunc, void** oldFunc)
{
if ( !g_bInit )
if ( !init( ) )
throw std::runtime_error{ "failed to initialize patcher" };
if (FAILED(patchImportFunc(funcAddr, newFunc, oldFunc)))
throw std::runtime_error{ "failed to patch module function" };
}

void mockModule_restoreModuleFunc(
void* origFunc, void* stubFunc, void** oldFunc)
{
if ( !g_bInit )
throw std::runtime_error{ "failed in initialization order" };
if (FAILED(restoreImportFunc(origFunc, stubFunc)))
throw std::runtime_error{ "failed to restore module function" };

Expand Down

0 comments on commit b71057d

Please sign in to comment.