How to catch delayed import dll errors (missing dll or symbol) in MinGW (-w64)?
Use dlltool -y
to create import-delay libraries for existing .dll or .def files. This seems to work very well up to the point where the dll is required for systems that do not have a corresponding DLL (as expected for delayed import dlls). However, I could not find any information on how to catch errors (missing module or missing function) generated during lazy loading.
In MSVC you would use __try {} __except (...) {}
SEH exception handling , however this is not available in MinGW (also I don't know which exception mechanism dlltool uses).
Normal try {} catch(...) {}
does not work either (the application crashes the same as without exception handling).
The GDB output isn't particularly helpful either:
gdb: unknown target exception 0xc06d007e at 0x7fefccfaaad
Program received signal ?, Unknown signal.
0x000007fefccfaaad in RaiseException ()
from C:\Windows\system32\KernelBase.dll
That an unknown exception is thrown in a RaiseException seems to indicate an SEH exception, if I'm not mistaken.
So the question is: has anyone successfully dealt with boot delay in MinGW-w64 and how?
EDIT : After a little experiment, I came up with the following solution:
extern "C" __declspec(dllexport) void foo(int);
#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>
thread_local auto do_handler = true;
thread_local jmp_buf env;
LONG CALLBACK handler(PEXCEPTION_POINTERS e)
{
if(do_handler)
{
// this flag is necessary to prevent a recursive call to handler
do_handler = false;
longjmp(env, 1);
}
else
{
return EXCEPTION_CONTINUE_SEARCH;
}
}
struct veh_remover
{
void operator() (void * veh) const
{
RemoveVectoredExceptionHandler(veh);
do_handler = true;
}
};
int main(int, char**)
{
#define CHECKED_DELAY(fn, ...) \
do { \
auto h = std::unique_ptr<void, veh_remover>(AddVectoredExceptionHandler(1, handler)); \
if(!setjmp(env)) fn(__VA_ARGS__); \
else throw std::runtime_error(#fn " not available"); \
} while(0);
try { CHECKED_DELAY(foo, 0); }
catch(std::exception & e) { printf("%s\n", e.what()); }
}
However, I am not sure if the behavior of this code is well defined (I am exiting the handler after all). Also it doesn't seem particularly clean.
EDIT 2 : I tried a different approach by setting __pfnDliFailureHook2
:
extern "C" __declspec(dllimport) void foo(int);
#include <windows.h>
#include <csetjmp>
#include <stdexcept>
#include <memory>
#include <cstdio>
#include <cassert>
#include <delayimp.h>
FARPROC WINAPI delayHook(unsigned dliNotify, PDelayLoadInfo)
{
switch(dliNotify)
{
case dliFailLoadLib: throw std::runtime_error("module could not be loaded");
case dliFailGetProc: throw std::runtime_error("could not find procedure in module");
default: return 0;
};
}
int main(int, char**)
{
__pfnDliFailureHook2 = &delayHook;
try
{
foo(0);
}
catch(std::exception & e)
{
printf("%s\n", e.what());
}
}
This approach fails because the exception is not propagated properly and results in an 0x20474343
SEH exception . Seems like a related GCC bug that should be fixed, but at least using MinGW-w64 g ++ 4.9.2 this still doesn't work (and this is the most recent version available)
source to share
No one has answered this question yet
Check out similar questions: