[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH] Throw an exception when mutating read-only data
From: |
Andy Wingo |
Subject: |
[PATCH] Throw an exception when mutating read-only data |
Date: |
Sun, 2 Apr 2017 12:11:31 +0200 |
* libguile/init.c (scm_i_init_guile): Install the SIGSEGV handler unless
GUILE_INSTALL_SIGSEGV_HANDLER is 0.
* libguile/loader.c
(scm_maybe_throw_exception_for_mutation_of_read_only_data): New public
function.
(sigsegv_handler): New helper.
(scm_install_sigsegv_handler): New public function.
* libguile/loader.h: Declare new API.
---
libguile/init.c | 7 +++++
libguile/loader.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
libguile/loader.h | 3 +++
3 files changed, 87 insertions(+)
diff --git a/libguile/init.c b/libguile/init.c
index b046685d4..b333e7def 100644
--- a/libguile/init.c
+++ b/libguile/init.c
@@ -530,6 +530,13 @@ scm_i_init_guile (void *base)
scm_init_rw ();
scm_init_extensions ();
+ if (scm_getenv_int ("GUILE_INSTALL_SIGSEGV_HANDLER", 1))
+ {
+ if (scm_install_sigsegv_handler () != 0)
+ perror ("failed to install SIGSEGV handler");
+ /* Continue regardless. */
+ }
+
atexit (cleanup_for_exit);
scm_load_startup_files ();
scm_init_load_should_auto_compile ();
diff --git a/libguile/loader.c b/libguile/loader.c
index 7b1adc9c9..d12137be3 100644
--- a/libguile/loader.c
+++ b/libguile/loader.c
@@ -745,6 +745,83 @@ scm_all_mapped_elf_images (void)
return result;
}
+void
+scm_maybe_throw_exception_for_mutation_of_read_only_data (void *addr)
+{
+ if (!find_mapped_elf_image_unlocked (addr))
+ return;
+
+ /* Assume that a SEGV originating from access to an address in our
+ mapped ELF images is because that part of the image was mapped
+ read-only, and user code is trying to mutate it. Throw an
+ exception instead. */
+ scm_misc_error (NULL, "Attempt to mutate read-only value", SCM_EOL);
+}
+
+static struct sigaction prev_sigsegv_handler;
+
+static void
+sigsegv_handler (int sig, siginfo_t *si, void *unused)
+{
+ scm_maybe_throw_exception_for_mutation_of_read_only_data (si->si_addr);
+
+ /* If we got here, we need to chain up to the previously installed
+ handler. */
+ if (prev_sigsegv_handler.sa_flags & SA_SIGINFO)
+ {
+ if (prev_sigsegv_handler.sa_sigaction == SIG_IGN)
+ /* Although it's not meaningful to continue after ignoring
+ SIGSEGV, that's exactly what the user requested, so just
+ return. */
+ return;
+
+ if (prev_sigsegv_handler.sa_sigaction != SIG_DFL)
+ {
+ prev_sigsegv_handler.sa_sigaction (sig, si, unused);
+ /* The meaning of a program is undefined after returning from
+ SIGSEGV, but that's what the previous handler did; respect
+ its judgment. */
+ return;
+ }
+ }
+ else
+ {
+ if (prev_sigsegv_handler.sa_handler == SIG_IGN)
+ /* See note above. */
+ return;
+
+ if (prev_sigsegv_handler.sa_handler != SIG_DFL)
+ {
+ prev_sigsegv_handler.sa_handler (sig);
+ /* See note above. */
+ return;
+ }
+ }
+
+ /* If we got here, the previous handler was SIG_DFL which will abort
+ the program. Restore SIG_DFL and re-raise the signal. */
+ {
+ struct sigaction sa;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_handler = SIG_DFL;
+ if (sigaction (sig, &sa, NULL) != 0)
+ abort ();
+ raise (sig);
+ /* Unreachable. */
+ abort ();
+ }
+}
+
+int
+scm_install_sigsegv_handler (void)
+{
+ struct sigaction sa;
+ sa.sa_flags = SA_SIGINFO;
+ sigemptyset (&sa.sa_mask);
+ sa.sa_sigaction = sigsegv_handler;
+ return sigaction (SIGSEGV, &sa, &prev_sigsegv_handler);
+}
+
struct frame_map_prefix
{
scm_t_uint32 text_offset;
diff --git a/libguile/loader.h b/libguile/loader.h
index 5c719cbce..f097a6ccc 100644
--- a/libguile/loader.h
+++ b/libguile/loader.h
@@ -27,6 +27,9 @@ SCM_API SCM scm_load_thunk_from_memory (SCM bv);
SCM_INTERNAL const scm_t_uint8 *
scm_find_slot_map_unlocked (const scm_t_uint32 *ip);
+SCM_API int scm_install_sigsegv_handler (void);
+SCM_API void scm_maybe_throw_exception_for_mutation_of_read_only_data (void *);
+
SCM_INTERNAL void scm_bootstrap_loader (void);
SCM_INTERNAL void scm_init_loader (void);
--
2.12.2
- [PATCH] Throw an exception when mutating read-only data,
Andy Wingo <=