Emacs Abnormal Termination
A few months ago I filed a bug report for Emacs (upstream) when I stumbled across Emacs aborting under very specific circumstances. I was editing in markdown-mode and a regular expression replacement on lists would reliably, and frustratingly, cause Emacs to crash.
Through a sort-of binary search I only loaded only half of
markdown-mode to see in which half it would trigger, then I cut that
half in half again and repeated recursively until I had it down to a
small expression that causes a
-q) Emacs to
abort. It almost looks like I found it through fuzz testing. Change or
remove anything even slightly and it no longer triggers the abort.
To trigger it, there’s an
after-change-functions hook that performs
a regular expression search immediately after a
peek at the backtrace with gdb shows that this somehow causes the
point to leave the bounds of the buffer. Emacs detects this as an
assertion before dereferencing anything, and it aborts, thus
preventing a buffer overflow vulnerability. This is important for
my Emacs web server because if there’s a way to
trigger this bug in the web server I’d much rather have it abort than
run arbitrary shellcode injected in by a malicious HTTP request.
My bug report has seen no activity since I posted it. I can understand why. The circumstances to trigger it are unlikely and it’s a very old bug, so it’s low priority. It’s also a huge pain to debug. Hacking on Emacs from Lisp is pleasant but hacking on Emacs from C is not. The bug likely sits in the bowels of the complicated regular expression engine, making it even more unpleasant. I personally have no interest in trying to fix it myself.
So, since it looks like it’s here for the long haul it’s kind of fun
to implement an
abort function on top of it, allowing Elisp programs
to terminate Emacs abnormally — you know, in case
(defun abort () "Ask Emacs to abnormally terminate itself (bug#12077)." (interactive) (with-temp-buffer (insert "#\n*\n") (goto-char (point-min)) (add-hook 'after-change-functions (lambda (a b c) (re-search-forward ""))) (replace-regexp "^\\*" " *")))
It’s interactive so you could even bind a key to it.