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; }
}

Reply via email to