org-capture freezes emacs on OpenBSD

I've switch recently to OpenBSD and I noticed that org-capture no longer worked. Worst, it freezes my emacs session, which is something that should never happen. So, time to do a little Emacs Debugging Session !

Update 2021-07-14: We fixed this issue with jca@: https://marc.info/?l=openbsd-ports&m=162628497223780&w=2

By the way, if your emacs freezes, you can often recover it by sending the USR2 signal. When it receives this signal, Emacs will drop in the debugger.

The first thing to do, was to figure out whether the bug was caused by my setup, or not. To do that, I start emacs with the -Q option :

$ emacs -Q

Then I add a little capture template :

(setq org-capture-templates
      '(("t" "Task" entry
         (file+headline "/tmp/test.org" "Task"))))

And finally, run M-x org-capture RET t. The command freezes, meaning the bug comes from my version of emacs and org-mode. I'm using emacs-25.1p1-gtk3 with org-mode-release_8.2.10 on OpenBSD. And I know that Emacs with the Gtk3 toolkit has been a little buggy on OpenBSD… Could it be a part of the problem? Let's try again, but in a terminal this time!

$ emacs -Q -nw

Add the template and then run M-x org-capture RET t. It works! So the problem do come from some interactions with the X Window System.

We can now use the wonderful Emacs Debugger named Edebug! First, I've to find out which function freezes. C-h f org-capture RET displays the *Help* buffer for the org-capture function and a link to the source code. I follow it to jump at org-capture definition in lisp/org-capture.el. I use C-u C-M-x to evaluate the definition and instrument it with Edebug. Then M-x org-capture RET and use n to go through the function step by step.

Emacs freezes on the condition-case, right after evaluating org-capture-set-target-location.

             (or org-overriding-default-time
                 (org-current-time)))
    (org-capture-set-target-location)
    (condition-case error                   ;; <---- FREEZE
        (org-capture-put :template (org-capture-fill-template))
      ((error quit)
       (if (get-buffer "*Capture*") (kill-buffer "*Capture*"))
       (error "Capture abort: %s" error)))

Edebug isn't always capable of walking every emacs-lisp forms, here it looks like it doesn't know how to walk into condition-case. It doesn't matter, I can use M-. on org-capture-fill-template to jump to its definition, and instrument it again with C-u C-M-x. It freezes on the clipboard stuff :

     (v-x (or (org-get-x-clipboard 'PRIMARY)
          (org-get-x-clipboard 'CLIPBOARD)
          (org-get-x-clipboard 'SECONDARY)))

AHA, I did encounter sometimes ago weird freezes with Emacs when I was trying to paste stuff. It happened randomly, then stopped. But I know that it can happen.

After a few more M-. and C-u C-M-x, I find out that the problem happens when Org Mode tries to read the SECONDARY clipboard using the iso-8859-1 encoding. I'm not sure why, but as a quick fix, I set x-selection-timeout to 10 miliseconds. Now Emacs freezes for 10 miliseconds instead of 5000 miliseconds (the default).

Recap

  • Emacs version : emacs-25.1p1-gtk3
  • Org Mode version : org-mode-release_8.2.10
  • Operating System : OpenBSD (6.0+snapshot)
  • Fix : (setq x-selection-timeout 10)