aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoão Távora2022-12-15 15:26:13 +0000
committerJoão Távora2022-12-16 08:53:10 +0000
commit8bf4cdcf79bc3254a9169f28f68922ab83bd4e78 (patch)
tree57f6f26873857115ea80828b58d8aa0e10ed8630
parent033071692c7cd1cd550d25170d4b3168668567ac (diff)
downloademacs-8bf4cdcf79bc3254a9169f28f68922ab83bd4e78.tar.gz
emacs-8bf4cdcf79bc3254a9169f28f68922ab83bd4e78.zip
Avoid recursive process filters in lisp/jsonrpc.el (bug#60088)
jsonrpc.el may lose JSON-RPC messages because of recursive process filters. The problem happens in jsonrpc.el's jsonrpc--process-filter. The code of the process filter didn't expect to be called recursively and fails in that case. But that can happen if the three conditions are verified. 1. the client code invoked by its jsonrpc--connection-receive inside the process filter callee immediately sends follow-up input to process within the same Lisp stack. This is a common scenario, especially during LSP initialiation sequence used by Eglot, a jsonrpc.el client. 2. that follow-up message is large enough for process-send-string to send the input in bunches (output from processes can arrive in between bunches). 3. the process happens to have already some more output ready The fix in this commit detects recursive invocations and immediately re-schedules them as non-recursive calls to the jsonrpc--process-filter (but started from timers). * lisp/jsonrpc.el (jsonrpc--process-filter): Rework. (Version): Bump to 1.0.16.
-rw-r--r--lisp/jsonrpc.el19
1 files changed, 17 insertions, 2 deletions
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 90833e1c1d7..2d562610b3f 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -4,7 +4,7 @@
4 4
5;; Author: João Távora <joaotavora@gmail.com> 5;; Author: João Távora <joaotavora@gmail.com>
6;; Keywords: processes, languages, extensions 6;; Keywords: processes, languages, extensions
7;; Version: 1.0.15 7;; Version: 1.0.16
8;; Package-Requires: ((emacs "25.2")) 8;; Package-Requires: ((emacs "25.2"))
9 9
10;; This is a GNU ELPA :core package. Avoid functionality that is not 10;; This is a GNU ELPA :core package. Avoid functionality that is not
@@ -548,11 +548,26 @@ With optional CLEANUP, kill any associated buffers."
548 (delete-process proc) 548 (delete-process proc)
549 (funcall (jsonrpc--on-shutdown connection) connection))))) 549 (funcall (jsonrpc--on-shutdown connection) connection)))))
550 550
551(defun jsonrpc--process-filter (proc string) 551(defvar jsonrpc--in-process-filter nil
552 "Non-nil if inside `jsonrpc--process-filter'.")
553
554(cl-defun jsonrpc--process-filter (proc string)
552 "Called when new data STRING has arrived for PROC." 555 "Called when new data STRING has arrived for PROC."
556 (when jsonrpc--in-process-filter
557 ;; Problematic recursive process filters may happen if
558 ;; `jsonrpc--connection-receive', called by us, eventually calls
559 ;; client code which calls `process-send-string' (which see) to,
560 ;; say send a follow-up message. If that happens to writes enough
561 ;; bytes for pending output to be received, we will lose JSONRPC
562 ;; messages. In that case, remove recursiveness by re-scheduling
563 ;; ourselves to run from within a timer as soon as possible
564 ;; (bug#60088)
565 (run-at-time 0 nil #'jsonrpc--process-filter proc string)
566 (cl-return-from jsonrpc--process-filter))
553 (when (buffer-live-p (process-buffer proc)) 567 (when (buffer-live-p (process-buffer proc))
554 (with-current-buffer (process-buffer proc) 568 (with-current-buffer (process-buffer proc)
555 (let* ((inhibit-read-only t) 569 (let* ((inhibit-read-only t)
570 (jsonrpc--in-process-filter t)
556 (connection (process-get proc 'jsonrpc-connection)) 571 (connection (process-get proc 'jsonrpc-connection))
557 (expected-bytes (jsonrpc--expected-bytes connection))) 572 (expected-bytes (jsonrpc--expected-bytes connection)))
558 ;; Insert the text, advancing the process marker. 573 ;; Insert the text, advancing the process marker.