Add a new RunWithFaultHandler utility

This avoids the need for a global `afterspeculation` label.

Use to rewrite the Meltdown example.
diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt
index 79a10a7..0ce95d9 100644
--- a/demos/CMakeLists.txt
+++ b/demos/CMakeLists.txt
@@ -50,6 +50,10 @@
     utils.cc
 )
 
+if(UNIX)
+  target_sources(safeside PRIVATE faults.cc)
+endif()
+
 # Configure the assembler. Set ASM_EXT (extension for assembly files) and
 # ASM_PLATFORM (target CPU), which we'll use to add the right assembly
 # implementation.
diff --git a/demos/faults.cc b/demos/faults.cc
new file mode 100644
index 0000000..78b621f
--- /dev/null
+++ b/demos/faults.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under both the 3-Clause BSD License and the GPLv2, found in the
+ * LICENSE and LICENSE.GPL-2.0 files, respectively, in the root directory.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ */
+
+#include "faults.h"
+
+#include <setjmp.h>
+
+#include <cstring>
+
+namespace {
+
+// The fault handler that should be called from the signal handler, and the
+// sigjmp context that should be jumped to after that.
+//
+// Declaring these thread-local might be a bit aspirational -- they definitely
+// *shouldn't* be shared across threads, but the current implementation doesn't
+// necessarily guarantee it's safe to use RunWithFaultHandler on two threads
+// without external synchronization.
+thread_local PosixFaultHandler fault_handler;
+thread_local sigjmp_buf signal_handler_jmpbuf;
+
+void SignalHandler(int signal, siginfo_t *info, void *ucontext) {
+  fault_handler(signal, info, ucontext);
+  siglongjmp(signal_handler_jmpbuf, 1);
+}
+
+}  // namespace
+
+bool RunWithFaultHandler(std::function<void()> inner,
+                         PosixFaultHandler handler) {
+  struct sigaction sa = {};
+  sa.sa_sigaction = SignalHandler;
+
+  struct sigaction oldsa;
+  // This sets the signal handler for the entire process.
+  sigaction(SIGSEGV, &sa, &oldsa);
+
+  fault_handler = handler;
+  bool handled_fault = true;
+
+  // Use sigsetjmp/siglongjmp to save and restore signal mask. Otherwise we
+  // will jump out of the signal handler and leave the currently-being-handled
+  // signal blocked. The result of a SIGSEGV being raised while blocked is
+  // "undefined"[1], but in practice leads to killing the process.
+  //
+  // [1] https://www.man7.org/linux/man-pages/man2/sigprocmask.2.html#NOTES
+  if (sigsetjmp(signal_handler_jmpbuf, 1) == 0) {
+    inner();
+    handled_fault = false;
+  }
+
+  sigaction(SIGSEGV, &oldsa, nullptr);
+  fault_handler = {};
+
+  return handled_fault;
+}
diff --git a/demos/faults.h b/demos/faults.h
new file mode 100644
index 0000000..c7bcfdd
--- /dev/null
+++ b/demos/faults.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2020 Google LLC
+ *
+ * Licensed under both the 3-Clause BSD License and the GPLv2, found in the
+ * LICENSE and LICENSE.GPL-2.0 files, respectively, in the root directory.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
+ */
+
+#ifndef DEMOS_FAULTS_H_
+#define DEMOS_FAULTS_H_
+
+#include <signal.h>
+
+#include <functional>
+
+// See "The siginfo_t argument to a SA_SIGINFO handler"
+// at https://www.man7.org/linux/man-pages/man2/sigaction.2.html
+using PosixFaultHandler = std::function<void(int, siginfo_t*, void*)>;
+
+// Run `inner` with a signal handler installed to catch failure signals,
+// currently defined as `SIGSEGV`. If such a signal is raised, the signal
+// handler calls `handler` and then returns from RunWithFaultHandler.
+//
+// Returns true iff a signal was handled.
+bool RunWithFaultHandler(std::function<void()> inner,
+                         PosixFaultHandler handler);
+
+// Convenience adapter for callers that don't need signal details.
+inline bool RunWithFaultHandler(std::function<void()> inner,
+                                std::function<void()> handler) {
+  return RunWithFaultHandler(inner,
+                             [handler](int, siginfo_t*, void*) { handler(); });
+}
+
+#endif  // DEMOS_FAULTS_H_
diff --git a/demos/meltdown.cc b/demos/meltdown.cc
index e9832f1..9b357b2 100644
--- a/demos/meltdown.cc
+++ b/demos/meltdown.cc
@@ -22,8 +22,6 @@
 #include <fstream>
 #include <iostream>
 
-#include <signal.h>
-
 #include "cache_sidechannel.h"
 #include "instr.h"
 #include "faults.h"
@@ -55,14 +53,19 @@
     // value of the in-bounds access is usually different from the secret value
     // we want to leak via out-of-bounds speculative access.
     size_t safe_offset = run % strlen(public_data);
-    ForceRead(oracle.data() + static_cast<size_t>(data[safe_offset]));
 
-    // Access attempt to the kernel memory. This does not succeed
-    // architecturally and kernel sends SIGSEGV instead.
-    ForceRead(oracle.data() + static_cast<size_t>(data[offset]));
+    bool handled_fault = RunWithFaultHandler([&]() {
+      ForceRead(oracle.data() + static_cast<size_t>(data[safe_offset]));
 
-    // SIGSEGV signal handler moves the instruction pointer to this label.
-    asm volatile("afterspeculation:");
+      // Access attempt to the kernel memory. This does not succeed
+      // architecturally and kernel sends SIGSEGV instead.
+      ForceRead(oracle.data() + static_cast<size_t>(data[offset]));
+    }, [](){});
+
+    if (!handled_fault) {
+      std::cerr << "Read didn't yield expected fault" << std::endl;
+      exit(EXIT_FAILURE);
+    }
 
     std::pair<bool, char> result =
         sidechannel.RecomputeScores(data[safe_offset]);
@@ -92,7 +95,6 @@
   in >> std::dec >> private_length;
   in.close();
 
-  OnSignalMoveRipToAfterspeculation(SIGSEGV);
   std::cout << "Leaking the string: ";
   std::cout.flush();
   const size_t private_offset =