Skip to content

Forbidden reentrant call of Tramp #859

@xor-xor

Description

@xor-xor

Steps to reproduce:

  1. Log into some remote Linux machine with clangd installed (but this may be server-agnostic).
  2. Create a simple foobar "project" with the snippet below:
mkdir -p foobar/foo foobar/bar
echo "int main(){}" > foobar/foo/foo.cc
echo "int main(){}" > foobar/bar/bar.cc
git init foobar
  1. From within Emacs running on your local machine, C-x C-f to foo.cc via TRAMP, e.g. /ssh:my-remote-machine:foobar/foo/foo.cc.
  2. Wait until [eglot] Connected! Server `clangd' now managing `c++-mode' buffers in project `foobar'.
  3. C-x C-f to bar.cc.
  4. Observe the error Forbidden reentrant call of Tramp.

BTW, this doesn't happen when files foo.cc and bar.cc are in the same dir, e.g. foobar/foo.cc and foobar/bar.cc.

Details:

  • Server used: clangd
  • Emacs version: 27.1 (with TRAMP 2.5.2.2 installed from ELPA via package.el)
  • Operating system: macOS (locally), Linux (remotely)
  • Eglot version: current master @ 8dc5180
  • Eglot installation method: git
  • Using Doom: No

LSP transcript - M-x eglot-events-buffer (mandatory unless Emacs inoperable)

[internal] Thu Mar  3 19:34:41 2022:
(:message "Running language server: (sh -c stty raw > /dev/null; clangd --clang-tidy\\=0)")
[stderr] I[18:34:41.402] Ubuntu clangd version 13.0.0-2
[stderr] I[18:34:41.403] Features: linux
[stderr] I[18:34:41.403] PID: 2073
[stderr] I[18:34:41.403] Working directory: /home/xor-xor/foobar
[stderr] I[18:34:41.403] argv[0]: clangd
[stderr] I[18:34:41.403] argv[1]: --clang-tidy=0
[stderr] I[18:34:41.403] Starting LSP over stdin/stdout
[client-request] (id:1) Thu Mar  3 19:34:41 2022:
(:jsonrpc "2.0" :id 1 :method "initialize" :params
	  (:processId nil :rootPath "/home/xor-xor/foobar/" :rootUri "file:///home/xor-xor/foobar" :initializationOptions #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
																			      ())
		      :capabilities
		      (:workspace
		       (:applyEdit t :executeCommand
				   (:dynamicRegistration :json-false)
				   :workspaceEdit
				   (:documentChanges :json-false)
				   :didChangeWatchedFiles
				   (:dynamicRegistration t)
				   :symbol
				   (:dynamicRegistration :json-false)
				   :configuration t)
		       :textDocument
		       (:synchronization
			(:dynamicRegistration :json-false :willSave t :willSaveWaitUntil t :didSave t)
			:completion
			(:dynamicRegistration :json-false :completionItem
					      (:snippetSupport :json-false :deprecatedSupport t :tagSupport
							       (:valueSet
								[1]))
					      :contextSupport t)
			:hover
			(:dynamicRegistration :json-false :contentFormat
					      ["markdown" "plaintext"])
			:signatureHelp
			(:dynamicRegistration :json-false :signatureInformation
					      (:parameterInformation
					       (:labelOffsetSupport t)
					       :activeParameterSupport t))
			:references
			(:dynamicRegistration :json-false)
			:definition
			(:dynamicRegistration :json-false :linkSupport t)
			:declaration
			(:dynamicRegistration :json-false :linkSupport t)
			:implementation
			(:dynamicRegistration :json-false :linkSupport t)
			:typeDefinition
			(:dynamicRegistration :json-false :linkSupport t)
			:documentSymbol
			(:dynamicRegistration :json-false :hierarchicalDocumentSymbolSupport t :symbolKind
					      (:valueSet
					       [1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26]))
			:documentHighlight
			(:dynamicRegistration :json-false)
			:codeAction
			(:dynamicRegistration :json-false :codeActionLiteralSupport
					      (:codeActionKind
					       (:valueSet
						["quickfix" "refactor" "refactor.extract" "refactor.inline" "refactor.rewrite" "source" "source.organizeImports"]))
					      :isPreferredSupport t)
			:formatting
			(:dynamicRegistration :json-false)
			:rangeFormatting
			(:dynamicRegistration :json-false)
			:rename
			(:dynamicRegistration :json-false)
			:publishDiagnostics
			(:relatedInformation :json-false :codeDescriptionSupport :json-false :tagSupport
					     (:valueSet
					      [1 2])))
		       :experimental #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
						   ()))))
[stderr] I[18:34:41.448] <-- initialize(1)
[stderr] I[18:34:41.449] --> reply:initialize(1) 0 ms
[server-reply] (id:1) Thu Mar  3 19:34:41 2022:
(:id 1 :jsonrpc "2.0" :result
     (:capabilities
      (:astProvider t :callHierarchyProvider t :codeActionProvider
		    (:codeActionKinds
		     ["quickfix" "refactor" "info"])
		    :compilationDatabase
		    (:automaticReload t)
		    :completionProvider
		    (:allCommitCharacters
		     [" " "	" "(" ")" "[" "]" "{" "}" "<" ">" ":" ";" "," "+" "-" "/" "*" "%" "^" "&" "#" "?" "." "=" "\"" "'" "|"]
		     :resolveProvider :json-false :triggerCharacters
		     ["." "<" ">" ":" "\"" "/"])
		    :declarationProvider t :definitionProvider t :documentFormattingProvider t :documentHighlightProvider t :documentLinkProvider
		    (:resolveProvider :json-false)
		    :documentOnTypeFormattingProvider
		    (:firstTriggerCharacter "\n" :moreTriggerCharacter
					    [])
		    :documentRangeFormattingProvider t :documentSymbolProvider t :executeCommandProvider
		    (:commands
		     ["clangd.applyFix" "clangd.applyTweak"])
		    :hoverProvider t :implementationProvider t :memoryUsageProvider t :referencesProvider t :renameProvider t :selectionRangeProvider t :semanticTokensProvider
		    (:full
		     (:delta t)
		     :legend
		     (:tokenModifiers
		      ["declaration" "deprecated" "deduced" "readonly" "static" "abstract" "dependentName" "defaultLibrary" "functionScope" "classScope" "fileScope" "globalScope"]
		      :tokenTypes
		      ["variable" "variable" "parameter" "function" "method" "function" "property" "variable" "class" "interface" "enum" "enumMember" "type" "type" "unknown" "namespace" "typeParameter" "concept" "type" "macro" "comment"])
		     :range :json-false)
		    :signatureHelpProvider
		    (:triggerCharacters
		     ["(" ","])
		    :textDocumentSync
		    (:change 2 :openClose t :save t)
		    :typeHierarchyProvider t :workspaceSymbolProvider t)
      :serverInfo
      (:name "clangd" :version "Ubuntu clangd version 13.0.0-2 linux x86_64-pc-linux-gnu")))
[client-notification] Thu Mar  3 19:34:41 2022:
(:jsonrpc "2.0" :method "initialized" :params #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8125 data
							    ()))
[client-notification] Thu Mar  3 19:34:41 2022:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
	  (:textDocument
	   (:uri "file:///home/xor-xor/foobar/foo/foo.cc" :version 0 :languageId "c++" :text "int main(){}\n")))
[client-notification] Thu Mar  3 19:34:41 2022:
(:jsonrpc "2.0" :method "workspace/didChangeConfiguration" :params
	  (:settings nil))
[stderr] I[18:34:41.466] <-- initialized
[stderr] I[18:34:41.658] <-- textDocument/didOpen
[stderr] I[18:34:41.659] Failed to find compilation database for /home/xor-xor/foobar/foo/foo.cc
[stderr] I[18:34:41.660] ASTWorker building file /home/xor-xor/foobar/foo/foo.cc version 0 with command clangd fallback
[stderr] [/home/xor-xor/foobar/foo]
[stderr] /usr/lib/llvm-13/bin/clang -resource-dir=/usr/lib/llvm-13/lib/clang/13.0.0 -- /home/xor-xor/foobar/foo/foo.cc
[stderr] I[18:34:41.661] <-- workspace/didChangeConfiguration
[stderr] I[18:34:41.674] --> textDocument/publishDiagnostics
[server-notification] Thu Mar  3 19:34:41 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
	  (:diagnostics
	   []
	   :uri "file:///home/xor-xor/foobar/foo/foo.cc" :version 0))
[client-notification] Thu Mar  3 19:34:56 2022:
(:jsonrpc "2.0" :method "textDocument/didOpen" :params
	  (:textDocument
	   (:uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0 :languageId "c++" :text "int main(){}\n")))
[stderr] I[18:34:56.902] <-- textDocument/didOpen
[stderr] I[18:34:56.902] Failed to find compilation database for /home/xor-xor/foobar/bar/bar.cc
[stderr] I[18:34:56.902] ASTWorker building file /home/xor-xor/foobar/bar/bar.cc version 0 with command clangd fallback
[stderr] [/home/xor-xor/foobar/bar]
[stderr] /usr/lib/llvm-13/bin/clang -resource-dir=/usr/lib/llvm-13/lib/clang/13.0.0 -- /home/xor-xor/foobar/bar/bar.cc
[stderr] I[18:34:56.915] --> textDocument/publishDiagnostics
[server-notification] Thu Mar  3 19:34:57 2022:
(:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params
	  (:diagnostics
	   []
	   :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0))

Backtrace (mandatory, unless no error message seen or heard):

(hostname redacted out)

Debugger entered--Lisp error: (remote-file-error "Forbidden reentrant call of Tramp")
  signal(remote-file-error ("Forbidden reentrant call of Tramp"))
  tramp-error(#<process *tramp/ssh my-host.somewhere*> remote-file-error "Forbidden reentrant call of Tramp")
  tramp-send-string((tramp-file-name "ssh" nil nil "my-host.somewhere..." nil "/home/xor-xor/foobar/bar/bar.cc" nil) "\\readlink --canonicalize-missing /home/xor-xor...")
  tramp-send-command((tramp-file-name "ssh" nil nil "my-host.somewhere..." nil "/home/xor-xor/foobar/bar/bar.cc" nil) "\\readlink --canonicalize-missing /home/xor-xor...")
  tramp-send-command-and-check((tramp-file-name "ssh" nil nil "my-host.somewhere..." nil "/home/xor-xor/foobar/bar/bar.cc" nil) "\\readlink --canonicalize-missing /home/xor-xor...")
  tramp-sh-handle-file-truename("/ssh:my-host.somewhere...")
  apply(tramp-sh-handle-file-truename "/ssh:my-host.somewhere...")
  tramp-vc-file-name-handler(file-truename "/ssh:my-host.somewhere...")
  file-truename("/ssh:my-host.somewhere...")
  find-buffer-visiting("/ssh:my-host.somewhere...")
  (and t (find-buffer-visiting (eglot--uri-to-path uri)))
  (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< (setq --cl-idx-- (1+ --cl-idx--)) (length --cl-vec--)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list ...)))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics (cons t diags)))) nil)) (let* ((path (expand-file-name (eglot--uri-to-path uri))) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< (setq --cl-idx-- (1+ --cl-idx--)) (length --cl-vec--)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list (let ... ...))))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil)))
  (progn (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< (setq --cl-idx-- ...) (length --cl-vec--)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags ...))) (cond (eglot--current-flymake-report-fn (eglot--report-to-flymake diags)) (t (setq eglot--unreported-diagnostics ...))) nil)) (let* ((path (expand-file-name (eglot--uri-to-path uri))) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< (setq --cl-idx-- (1+ --cl-idx--)) (length --cl-vec--)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags (list ...)))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil))))
  (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond ((null sev) 'eglot-error) ((<= sev 1) 'eglot-error) ((= sev 2) 'eglot-warning) (t 'eglot-note))))) (progn (let* ((buffer (and t (find-buffer-visiting (eglot--uri-to-path uri))))) (if buffer (save-current-buffer (set-buffer buffer) (let* ((--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< ... ...) (setq diag-spec ...) (setq diags ...)) (cond (eglot--current-flymake-report-fn ...) (t ...)) nil)) (let* ((path (expand-file-name ...)) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< (setq --cl-idx-- ...) (length --cl-vec--)) (setq diag-spec (aref --cl-vec-- --cl-idx--)) (setq diags (nconc diags ...))) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics #'string=)) (setq flymake-list-only-diagnostics (cons (cons path diags) flymake-list-only-diagnostics)) nil)))))
  (let* ((uri (car (cdr (plist-member --cl-rest-- ':uri)))) (diagnostics (car (cdr (plist-member --cl-rest-- ':diagnostics))))) (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond (... ...) (... ...) (... ...) (t ...))))) (progn (let* ((buffer (and t (find-buffer-visiting ...)))) (if buffer (save-current-buffer (set-buffer buffer) (let* (... ... ... ...) (while ... ... ...) (cond ... ...) nil)) (let* ((path ...) (--cl-vec-- diagnostics) (--cl-idx-- -1) (diag-spec nil) (diags nil)) (while (< ... ...) (setq diag-spec ...) (setq diags ...)) (setq flymake-list-only-diagnostics (assoc-delete-all path flymake-list-only-diagnostics ...)) (setq flymake-list-only-diagnostics (cons ... flymake-list-only-diagnostics)) nil))))))
  (progn (let* ((uri (car (cdr (plist-member --cl-rest-- ':uri)))) (diagnostics (car (cdr (plist-member --cl-rest-- ':diagnostics))))) (let* ((--cl-eglot--diag-type-- #'(lambda (sev) (cond ... ... ... ...)))) (progn (let* ((buffer (and t ...))) (if buffer (save-current-buffer (set-buffer buffer) (let* ... ... ... nil)) (let* (... ... ... ... ...) (while ... ... ...) (setq flymake-list-only-diagnostics ...) (setq flymake-list-only-diagnostics ...) nil)))))))
  (closure (revert-buffer-preserve-modes eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (_server _method &rest --cl-rest--) "Handle notification publishDiagnostics.\n\n(fn SERVE..." (progn (let* ((uri (car (cdr ...))) (diagnostics (car (cdr ...)))) (let* ((--cl-eglot--diag-type-- #'...)) (progn (let* (...) (if buffer ... ...)))))))(#<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> textDocument/publishDiagnostics :diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0)
  apply((closure (revert-buffer-preserve-modes eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (_server _method &rest --cl-rest--) "Handle notification publishDiagnostics.\n\n(fn SERVE..." (progn (let* ((uri (car (cdr ...))) (diagnostics (car (cdr ...)))) (let* ((--cl-eglot--diag-type-- #'...)) (progn (let* (...) (if buffer ... ...))))))) #<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> textDocument/publishDiagnostics (:diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0))
  eglot-handle-notification(#<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> textDocument/publishDiagnostics :diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0)
  apply(eglot-handle-notification #<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> textDocument/publishDiagnostics (:diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0))
  (let ((eglot--cached-server server)) (apply fn server method (append params nil)))
  (closure ((fn . eglot-handle-notification) (initargs :process (closure ((contact "clangd" "--clang-tidy=0") (server-info "sh" "-c" "stty raw > /dev/null; clangd --clang-tidy\\=0") (autostart-inferior-process) (readable-name . "EGLOT (foobar/c++-mode)") (nickname . "foobar") (language-id . "c++") (contact "clangd" "--clang-tidy=0") (class . eglot-lsp-server) (project vc . "/ssh:my-host.somewhere...") (managed-major-mode . c++-mode) eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) nil (let ((default-directory default-directory)) (make-process :name readable-name :command (setq server-info ...) :connection-type 'pipe :coding 'utf-8-emacs-unix :noquery t :stderr (get-buffer-create ...) :file-handler t)))) (contact "clangd" "--clang-tidy=0") (server-info "sh" "-c" "stty raw > /dev/null; clangd --clang-tidy\\=0") (autostart-inferior-process) (readable-name . "EGLOT (foobar/c++-mode)") (nickname . "foobar") (language-id . "c++") (contact "clangd" "--clang-tidy=0") (class . eglot-lsp-server) (project vc . "/ssh:my-host.somewhere...") (managed-major-mode . c++-mode) eglot--managed-mode eglot-lsp-context company-tooltip-align-annotations company-backends markdown-fontify-code-blocks-natively t) (server method params) (let ((eglot--cached-server server)) (apply fn server method (append params nil))))(#<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> textDocument/publishDiagnostics (:diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0))
  jsonrpc-connection-receive(#<eglot-lsp-server eglot-lsp-server-1fe17809a9a8> (:jsonrpc "2.0" :method "textDocument/publishDiagnostics" :params (:diagnostics [] :uri "file:///home/xor-xor/foobar/bar/bar.cc" :version 0)))
  jsonrpc--process-filter(#<process EGLOT (foobar/c++-mode)> "Content-Length: 158\15\n\15\n{\"jsonrpc\":\"2.0\",\"method\":\"...")
  process-send-string(#<process *tramp/ssh my-host.somewhere*> "tramp_vc_registered_read_file_names <<'cc634870bf3...")
  tramp-send-string((tramp-file-name "ssh" nil nil "my-host.somewhere..." nil "/home/xor-xor/foobar/bar/bar.cc" nil) "tramp_vc_registered_read_file_names <<'cc634870bf3...")
  tramp-send-command((tramp-file-name "ssh" nil nil "my-host.somewhere..." nil "/home/xor-xor/foobar/bar/bar.cc" nil) "tramp_vc_registered_read_file_names <<'cc634870bf3...")
  tramp-sh-handle-vc-registered("/ssh:my-host.somewhere...")
  apply(tramp-sh-handle-vc-registered "/ssh:my-host.somewhere...")
  tramp-sh-file-name-handler(vc-registered "/ssh:my-host.somewhere...")
  apply(tramp-sh-file-name-handler vc-registered "/ssh:my-host.somewhere...")
  tramp-file-name-handler(vc-registered "/ssh:my-host.somewhere...")
  vc-registered("/ssh:my-host.somewhere...")
  vc-backend("/ssh:my-host.somewhere...")
  vc-refresh-state()
  run-hooks(find-file-hook)
  after-find-file(nil t)
  find-file-noselect-1(#<buffer bar.cc> "/ssh:my-host.somewhere..." nil nil "/ssh:my-host.somewhere..." (1299068 (-1 . 1)))
  find-file-noselect("/ssh:my-host.somewhere..." nil nil t)
  find-file("/ssh:my-host.somewhere..." t)
  funcall-interactively(find-file "/ssh:my-host.somewhere..." t)
  call-interactively(find-file nil nil)
  command-execute(find-file)

Minimal configuration (mandatory)

# Emacs started with:

$ emacs -Q -f package-initialize -L /path/to/git-cloned/eglot -l eglot.el 
;;; config evaluated via *scratch*: 
 
(setq debug-on-error t)

(with-eval-after-load 'cc-mode
  (require 'eglot)
  (add-to-list 'eglot-server-programs '((c++-mode) . ("clangd" "--clang-tidy=0")))
  (add-hook 'c++-mode-hook 'eglot-ensure))

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions