mirror of
https://github.com/matrix-construct/construct
synced 2024-09-27 19:28:52 +02:00
ircd::fpe: Add experimental exception-throwing SIGFPE w/ -fnon-call-exceptions.
This commit is contained in:
parent
5d36bdf476
commit
47732a0075
3 changed files with 122 additions and 0 deletions
|
@ -411,6 +411,14 @@ dnl CXXFLAGS+=" -fcheck-pointer-bounds"
|
||||||
CXXFLAGS+=" -fchkp-instrument-marked-only"
|
CXXFLAGS+=" -fchkp-instrument-marked-only"
|
||||||
CXXFLAGS+=" -fstack-protector-explicit"
|
CXXFLAGS+=" -fstack-protector-explicit"
|
||||||
|
|
||||||
|
dnl !!! Experimental !!!
|
||||||
|
dnl Allows a signal handler to throw a C++ exception if the signal is from
|
||||||
|
dnl a CPU trap on an instruction (ex. SIGFPE from a floating point divide
|
||||||
|
dnl by zero). This allows the signal handler to transfer control to the
|
||||||
|
dnl catch block wrapping the area which errored, thereby aborting any further
|
||||||
|
dnl execution after the SIGFPE was received which would have to manually check
|
||||||
|
dnl for such an error after each floating point operation and throw.
|
||||||
|
CXXFLAGS+=" -fnon-call-exceptions"
|
||||||
|
|
||||||
dnl -ffriend-injection allows us to deduplicate declarations of friend
|
dnl -ffriend-injection allows us to deduplicate declarations of friend
|
||||||
dnl functions in both the friend class and the enclosing namespace
|
dnl functions in both the friend class and the enclosing namespace
|
||||||
|
|
|
@ -11,10 +11,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#define HAVE_IRCD_FPE_H
|
#define HAVE_IRCD_FPE_H
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
struct sigaction;
|
||||||
|
};
|
||||||
|
|
||||||
namespace ircd::fpe
|
namespace ircd::fpe
|
||||||
{
|
{
|
||||||
struct errors_handle;
|
struct errors_handle;
|
||||||
|
struct errors_throw;
|
||||||
|
|
||||||
|
string_view reflect_sicode(const int &);
|
||||||
string_view reflect(const ushort &flag);
|
string_view reflect(const ushort &flag);
|
||||||
string_view reflect(const mutable_buffer &, const ushort &flags);
|
string_view reflect(const mutable_buffer &, const ushort &flags);
|
||||||
void throw_errors(const ushort &flags);
|
void throw_errors(const ushort &flags);
|
||||||
|
@ -32,3 +39,14 @@ struct ircd::fpe::errors_handle
|
||||||
errors_handle();
|
errors_handle();
|
||||||
~errors_handle() noexcept(false);
|
~errors_handle() noexcept(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ircd::fpe::errors_throw
|
||||||
|
{
|
||||||
|
custom_ptr<struct sigaction> their_sa;
|
||||||
|
long their_fenabled;
|
||||||
|
fexcept_t their_fe;
|
||||||
|
|
||||||
|
public:
|
||||||
|
errors_throw();
|
||||||
|
~errors_throw() noexcept;
|
||||||
|
};
|
||||||
|
|
96
ircd/fpe.cc
96
ircd/fpe.cc
|
@ -8,10 +8,88 @@
|
||||||
// copyright notice and this permission notice is present in all copies. The
|
// copyright notice and this permission notice is present in all copies. The
|
||||||
// full license for this software is available in the LICENSE file.
|
// full license for this software is available in the LICENSE file.
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
#pragma STDC FENV_ACCESS on
|
#pragma STDC FENV_ACCESS on
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// errors_throw
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace ircd::fpe
|
||||||
|
{
|
||||||
|
constexpr const size_t &SA_HEAP_MAX {64};
|
||||||
|
thread_local allocator::fixed<struct sigaction, SA_HEAP_MAX> sa_heap;
|
||||||
|
|
||||||
|
extern const std::exception_ptr sigfpe_eptr;
|
||||||
|
extern "C" void ircd_fpe_handle_sigfpe(int signum, siginfo_t *const si, void *const uctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
decltype(ircd::fpe::sigfpe_eptr)
|
||||||
|
ircd::fpe::sigfpe_eptr
|
||||||
|
{
|
||||||
|
std::make_exception_ptr(std::domain_error
|
||||||
|
{
|
||||||
|
"Floating Point Exception"
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
__attribute__((noreturn))
|
||||||
|
void
|
||||||
|
ircd::fpe::ircd_fpe_handle_sigfpe(int signum,
|
||||||
|
siginfo_t *const si,
|
||||||
|
void *const uctx)
|
||||||
|
{
|
||||||
|
assert(si);
|
||||||
|
assert(signum == SIGFPE);
|
||||||
|
std::rethrow_exception(sigfpe_eptr); //TODO: still malloc()'s :/
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// errors_throw::errors_throw
|
||||||
|
//
|
||||||
|
|
||||||
|
ircd::fpe::errors_throw::errors_throw()
|
||||||
|
:their_sa
|
||||||
|
{
|
||||||
|
new (sa_heap().allocate(1)) struct sigaction,
|
||||||
|
[](auto *const ptr)
|
||||||
|
{
|
||||||
|
sa_heap().deallocate(ptr, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
,their_fenabled
|
||||||
|
{
|
||||||
|
syscall(::fegetexcept)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
struct sigaction ours {0};
|
||||||
|
ours.sa_sigaction = ircd_fpe_handle_sigfpe;
|
||||||
|
ours.sa_flags |= SA_SIGINFO;
|
||||||
|
ours.sa_flags |= SA_NODEFER; // Required to throw out of the handler
|
||||||
|
|
||||||
|
syscall(std::fegetexceptflag, &their_fe, FE_ALL_EXCEPT);
|
||||||
|
syscall(std::feclearexcept, FE_ALL_EXCEPT);
|
||||||
|
syscall(::sigaction, SIGFPE, &ours, their_sa.get());
|
||||||
|
syscall(::feenableexcept, FE_ALL_EXCEPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
ircd::fpe::errors_throw::~errors_throw()
|
||||||
|
noexcept
|
||||||
|
{
|
||||||
|
syscall(::fedisableexcept, FE_ALL_EXCEPT);
|
||||||
|
syscall(::sigaction, SIGFPE, their_sa.get(), nullptr);
|
||||||
|
syscall(::feenableexcept, their_fenabled);
|
||||||
|
syscall(std::fesetexceptflag, &their_fe, FE_ALL_EXCEPT);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// errors_handle
|
||||||
|
//
|
||||||
|
|
||||||
ircd::fpe::errors_handle::errors_handle()
|
ircd::fpe::errors_handle::errors_handle()
|
||||||
{
|
{
|
||||||
syscall(std::fegetexceptflag, &theirs, FE_ALL_EXCEPT);
|
syscall(std::fegetexceptflag, &theirs, FE_ALL_EXCEPT);
|
||||||
|
@ -98,3 +176,21 @@ ircd::fpe::reflect(const ushort &flag)
|
||||||
|
|
||||||
return "?????";
|
return "?????";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ircd::string_view
|
||||||
|
ircd::fpe::reflect_sicode(const int &code)
|
||||||
|
{
|
||||||
|
switch(code)
|
||||||
|
{
|
||||||
|
case FPE_INTDIV: return "INTDIV";
|
||||||
|
case FPE_INTOVF: return "INTOVF";
|
||||||
|
case FPE_FLTDIV: return "FLTDIV";
|
||||||
|
case FPE_FLTOVF: return "FLTOVF";
|
||||||
|
case FPE_FLTUND: return "FLTUND";
|
||||||
|
case FPE_FLTRES: return "FLTRES";
|
||||||
|
case FPE_FLTINV: return "FLTINV";
|
||||||
|
case FPE_FLTSUB: return "FLTSUB";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "?????";
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue