Add thread safe import cache
* procedure import module
*
* Copyright (C) 2015 wj32
- * Copyright (C) 2019 dmex
+ * Copyright (C) 2019-2020 dmex
*
* This file is part of Process Hacker.
*
PVOID PhpImportProcedure(
_Inout_ PVOID *Cache,
- _Inout_ PBOOLEAN CacheValid,
_Inout_ PULONG Cookie,
_In_ PWSTR ModuleName,
_In_ PSTR ProcedureName
@@ -34,35 +33,49 @@ PVOID PhpImportProcedure(
{
PVOID module;
PVOID procedure;
+ ULONG cookie;
- if (*CacheValid)
- return (PVOID)((ULONG_PTR)*Cache ^ (ULONG_PTR)*Cookie);
+ cookie = InterlockedCompareExchange(Cookie, 0, 0);
- if (!(module = PhGetLoaderEntryDllBase(ModuleName)))
- module = LoadLibrary(ModuleName);
+ if (!cookie)
+ {
+ ULONG newcookie = NtGetTickCount();
+
+ if (!InterlockedCompareExchange(Cookie, newcookie, 0))
+ cookie = newcookie;
+ }
- if (!module)
+ procedure = InterlockedCompareExchangePointer(Cache, NULL, NULL);
+
+ if (!procedure)
+ {
+ if (!(module = LoadLibrary(ModuleName)))
return NULL;
- procedure = PhGetDllBaseProcedureAddress(module, ProcedureName, 0);
+ if (!(procedure = PhGetDllBaseProcedureAddress(module, ProcedureName, 0)))
+ {
+ FreeLibrary(module);
+ return NULL;
+ }
- if (*Cookie == 0) *Cookie = NtGetTickCount();
- *Cache = (PVOID)((ULONG_PTR)procedure ^ (ULONG_PTR)*Cookie);
+ procedure = (PVOID)((ULONG_PTR)procedure ^ (ULONG_PTR)cookie);
- MemoryBarrier();
- *CacheValid = TRUE;
+ if (InterlockedCompareExchangePointer(Cache, procedure, NULL))
+ {
+ FreeLibrary(module);
+ }
+ }
- return procedure;
+ return (PVOID)((ULONG_PTR)procedure ^ (ULONG_PTR)cookie);
}
#define PH_DEFINE_IMPORT(Module, Name) \
_##Name Name##_Import(VOID) \
{ \
static PVOID cache = NULL; \
- static BOOLEAN cacheValid = FALSE; \
static ULONG cookie = 0; \
\
- return (_##Name)PhpImportProcedure(&cache, &cacheValid, &cookie, Module, #Name); \
+ return (_##Name)PhpImportProcedure(&cache, &cookie, Module, #Name); \
}
PH_DEFINE_IMPORT(L"ntdll.dll", NtQueryInformationEnlistment);
