I wrote some code to trap a hardware exception, and transfer control to a signal handler which throws a C++ exception. From the documentation, I believe '-fnon-call-exceptions' (and/or '-fasynchronous-unwind-tables') should allow me to do this, but it doesn't work. It appears that gcc doesn't consider that non-call instructions may throw, and silently omits the try/catch block around it. The exception is only caught when the trapped instruction appears in a (non-inlined) function, or inbetween two function calls. --- Output from 'gcc -v': Using built-in specs. COLLECT_GCC=D:\msys64\usr\local\djgpp\i586-pc-msdosdjgpp\bin\gcc.exe COLLECT_LTO_WRAPPER=D:/msys64/usr/local/djgpp/lib/gcc/../../libexec/gcc/i586-pc-msdosdjgpp/5.3.0/lto-wrapper.exe Target: i586-pc-msdosdjgpp Configured with: ../gnu/gcc-5.30/configure --host= --build=x86_64-w64-mingw32 --target=i586-pc-msdosdjgpp --program-prefix=i586-pc-msdosdjgpp- --prefix=/usr/local/djgpp --disable-nls --disable-plugin --disable-lto --enable-lto --enable-libquadmath-support --with-gmp=/home/JW/build-djgpp/build/djcross-gcc-5.3.0/tmpinst --with-mpfr=/home/JW/build-djgpp/build/djcross-gcc-5.3.0/tmpinst --with-mpc=/home/JW/build-djgpp/build/djcross-gcc-5.3.0/tmpinst --enable-version-specific-runtime-libs --enable-languages=c,c++ Thread model: single gcc version 5.3.0 (GCC) --- Example code: (implementation details omitted) void throw_exception() { throw std::runtime_error("Division by zero!"); } __attribute__((noinline)) void try_div0() { cout << 1 / 0 << endl; } void nop() { asm(""); } int main() { // this class traps a hardware exception (division by zero, in this case) and calls the supplied lambda function. exception_wrapper div0_exc { 0, [] (exception_frame* frame, bool) { // only handle exceptions that occured in our own code if (frame->address.segment != get_cs()) return false; // sub <fault esp>, 4; frame->stack.offset -= 4; // get pointer to [<fault esp>] auto* stack = reinterpret_cast<std::uintptr_t *>(frame->stack.offset); // mov [<fault esp>], <fault address>; *stack = frame->address.offset; // resume at throw_exception() frame->address.offset = reinterpret_cast<std::uintptr_t>(throw_exception); return true; } }; try { // thrown from inside a function, this exception is caught. try_div0(); } catch (std::exception& e) { cout << "oops: " << e.what() << endl; } try { // thrown inbetween two function calls, this exception is caught. nop(); cout << 1 / 0 << endl; nop(); } catch (std::exception& e) { cout << "oops: " << e.what() << endl; } try { // throws, but is NOT CAUGHT! cout << 1 / 0 << endl; } catch (std::exception& e) { cout << "oops: " << e.what() << endl; } }
We need a complete testcase ("implementation details omitted" doesn't help). The EH info is present as far as I can see
Created attachment 38077 [details] Test case I reduced my code to the bare minimum required to reproduce this issue. Compile with djgpp: "g++ -std=gnu++14 -fnon-call-exceptions -fasynchronous-unwind-tables -o traptest.exe traptest.cpp"
Possibly interesting observation; the exception can be caught when using a pointer as divisor: int i = 0; int* volatile p = &i; try { std::cout << 1 / *p << std::endl; } catch (std::exception& e) { std::cout << "oops: " << e.what() << std::endl; }
Created attachment 38096 [details] Test case 2 Generic test case, which doesn't require djgpp or a DOS machine. (Assuming throwing from inline asm is similar enough) compile with: "g++ -std=gnu++14 -fnon-call-exceptions throw_from_asm.cpp"
Bumping this, I hope it will be resolved someday. I found a reference to the same issue, with another test case using posix signal handlers: https://cygwin.com/ml/cygwin/2010-07/msg00195.html This claims it used to work on 3.3.4, and failed from 4.3.4 on.
(In reply to jwjagersma from comment #4) > Created attachment 38096 [details] > Test case 2 > > Generic test case, which doesn't require djgpp or a DOS machine. (Assuming > throwing from inline asm is similar enough) > > compile with: > "g++ -std=gnu++14 -fnon-call-exceptions throw_from_asm.cpp" Yes GCC adds no unwind info and it is hard to do from an inline-asm since GCC has no information on what the inline-asm could do. So that part is more of a documentation rather than anything else there. As far as the other one, throwing from an interrupt in DOS requires you have to have a MD_FALLBACK_FRAME_STATE_FOR defined which is not done for djgpp and would need to be custom for your interrupt handler. I don't know the best way forward for this really except to say there is not much to be done here unless someone steps up and adds interrupt handler support to djgpp and then adds throwing through the interrupt handler support too.