Don't use this code
You can use signal handlers to catch failures.
// C header:
typedef void(func_with_ctx_t)(void *ctx);
bool with_signal_handler(int sig, func_with_ctx_t *func, void *ctx);
// C source:
typedef void(c_signal_handler_t)(int);
typedef struct {
int *jb;
} resume_vector_t;
#define SIG_COUNT (SIGUSR2+1)
resume_vector_t resume_vectors[SIG_COUNT];
void signal_handler(int sig) {
resume_vector_t rv = resume_vectors[sig];
longjmp(rv.jb, 1);
}
bool with_signal_handler(int sig, func_with_ctx_t *func, void *ctx) {
c_signal_handler_t *old_handler = signal(sig, signal_handler);
resume_vector_t old_rv = resume_vectors[sig];
jmp_buf jb;
bool success = false;
if (setjmp(jb) == 0) {
resume_vectors[sig].jb = jb;
func(ctx);
success = true;
}
// restore
resume_vectors[sig] = old_rv;
signal(sig, old_handler);
return success;
}
// Swift:
struct SignalReceived: Error {}
struct InternalInconsistency: Error {}
func withSignalHandler<R>(signal: Int32, do body: () throws -> R) throws -> R {
try withoutActuallyEscaping(body) { body in
typealias BodyWrapped = () -> Void
var result: Result<R, Error>?
let bodyWrapped: BodyWrapped = {
result = Result(catching: body)
}
let ctx = Unmanaged.passRetained(bodyWrapped as AnyObject)
let success = with_signal_handler(signal, { ptr in
guard let ptr else {
return
}
let bodyWrappedBoxed = Unmanaged<AnyObject>.fromOpaque(ptr).takeRetainedValue()
let bodyWrapped = bodyWrappedBoxed as! BodyWrapped
bodyWrapped()
}, ctx.toOpaque())
if success {
guard let result else {
assertionFailure()
throw InternalInconsistency()
}
return try result.get()
}
throw SignalReceived()
}
}
@main
struct App {
static func main() {
do {
let r: Int = try withSignalHandler(signal: SIGTRAP) {
_ = [][0]
print("Unreached 1")
return 42
}
print("Unreached 2", r)
} catch {
print(error)
}
print("Resume")
}
}
// Will print:
// Swift/ContiguousArrayBuffer.swift:600: Fatal error: Index out of range
// SignalReceived()
// Resume