https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70387
Bug ID: 70387
Summary: -fnon-call-exceptions has no effect
Product: gcc
Version: 5.3.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: c++
Assignee: unassigned at gcc dot gnu.org
Reporter: jwjagersma at gmail dot com
Target Milestone: ---
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; }
}