I have this following C++ code:
#include <Windows.h>
#include <type_traits>
class Sample
{
decltype(&ActivateActCtx) ActivateActCtx;
decltype(&ReadFile) ReadFile;
decltype(&WriteFile) WriteFile;
template <typename F>
static void ResolveFunction(F& output, const char* name)
{
static auto handle{ GetModuleHandleW(L"kernel32.dll") };
if (!((output = reinterpret_cast<F>(GetProcAddress(handle, name)))))
throw name;
}
public:
Sample()
{
ResolveFunction(ActivateActCtx, "ActivateActCtx");
ResolveFunction(ReadFile, "ReadFile");
ResolveFunction(WriteFile, "WriteFile");
}
template <typename T>
constexpr T Get()
{
if constexpr (std::is_same_v < T, decltype(&::ReadFile)>)
return ReadFile;
if constexpr (std::is_same_v < T, decltype(&::WriteFile)>)
return WriteFile;
if constexpr (std::is_same_v < T, decltype(&::ActivateActCtx)>)
return ActivateActCtx;
return {};
}
};
int main()
{
Sample s;
s.Get<decltype(&ReadFile)>()(nullptr, nullptr, 0, nullptr, nullptr);
s.Get<decltype(&WriteFile)>()(nullptr, nullptr, 0, nullptr, nullptr);
s.Get<decltype(&ActivateActCtx)>()(nullptr, nullptr);
return 0;
}
As you can see auto handle{ GetModuleHandleW(L"kernel32.dll") };
is static and should be assigned with the return value of GetModuleHandleW
just once. However, upon disassembly of the program it seems to be assigned three times, for each call in the constructor. I know that an implicit inline
is before ResolveFunction
, but I don't think that should literally inline so aggressively so that the definition of static
is violated.
I am using Microsoft Visual C++ 19.32.31329. Optimization settings: /O2 /Oi /GL
I also tried maximum optimization for size and got the same result. Everything is compiled as Release
of course.