I was asking on IRC the other day about SEH and __try / __except. I was
told that it does work if you use __try1 and __except1. I've been
experimenting and that's "sort of" true. But there are a lot of caveats,
so I thought I'd write up a brief report on what I found.
TLDR: __try1 is totally incompatible with MSVC (see #1-3), fragile (see
#7), and has serious instances of unexpected behavior (see #5).
Strictly speaking it "works," but I certainly wouldn't use this in
production code unless I absolutely had to.
BTW, I'm not asking for someone to 'fix' anything here. I'm not sure
it's possible to fix the __try1 or __except macros. In order for this
to work, it's going to take compiler changes, and I'm told there has
been some resistance to adding this to the compiler (something about the
Borland patents?).
IAC, if you are interested in experimenting, there are some things to
know. Here's what I found.
/* Some code using __try1 / __except1. If run with no arguments,
it will raise an exception. Otherwise not. */
#include <stdio.h>
#include <errhandlingapi.h>
int foo1(int i)
{
int j = (i - 1) * 7;
if (j < 1)
RaiseException(2, 1, 0, NULL);
return j;
}
extern "C" int exc(_In_ EXCEPTION_POINTERS *lpEP);
int exc(_In_ EXCEPTION_POINTERS *lpEP)
{
printf("Exception code: %u Flags: %u\n",
lpEP->ExceptionRecord->ExceptionCode, lpEP->ExceptionRecord->ExceptionFlags);
return EXCEPTION_EXECUTE_HANDLER;
}
int main(int argc, char *argv[])
{
printf("Using: %d\n", argc);
__try1(exc) {
int m = foo1(argc);
printf("main %d\n", m);
}
__except1
{
printf("Exception\n");
}
}
Reading the code:
1) In MSVC, the __try has no argument and the except does (the reverse
of __try1 / __except1). Therefor this implementation is not compatible
with existing code designed for MSVC.
2) In MSVC, the __except takes a C code fragment that determines whether
the exception is handled by this __except or not. The handler that is
passed to __try1 must be a function. This means that unlike the MSVC
implementation, you cannot use any of the variables from main() while
determining whether to handle the exception.
3) Given #2, several of the MSVC macros make little sense (like
GetExceptionInformation). In fact, some of these currently reference
undefined functions (like GetExceptionCode()).
4) If an exception is thrown, this code works as expected:
printf("main") does not get executed and printf("Exception code") and
the printf("Exception") both do.
5) If the exception is not thrown, the printf("Exception") still gets
executed (very unexpected!).
6) Using a c++ try/catch in conjunction with __try1 results in the SE
not being caught at all.
7) Optimization can make a real hash of this. For example if foo1()
gets inlined, it is no longer 'between' __try1 and __except1, so the
exception is no longer passed to the handler.
8) Looking at the implementation of __try1:
#define __try1(pHandler) \
__asm__ __volatile__ ("\t.l_startw:\n" \
"\t.seh_handler __C_specific_handler, @except\n" \
"\t.seh_handlerdata\n" \
"\t.long 1\n" \
"\t.rva .l_startw, .l_endw, "
__MINGW64_STRINGIFY(__MINGW_USYMBOL(pHandler)) " ,.l_endw\n" \
"\t.text" \
);
The .l_startw symbol name is hard-coded. This means you cannot use more
than one __try1 in a function. Using ".text" causes problems with some
build options (-ffunction-sections). Using ".seh_code" should resolve
this, but requires a fairly new gas
(https://sourceware.org/ml/binutils/2014-03/msg00260.html).
That's my experience anyway. FWIW.
dw
------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are
consuming the most bandwidth. Provides multi-vendor support for NetFlow,
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports.http://sdm.link/zohodev2dev
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public