unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
From: Felix Dietrich <felix.dietrich@sperrhaken.name>
To: help-gnu-emacs@gnu.org
Cc: Michael Albinus <michael.albinus@gmx.de>
Subject: Re: Error with tramp-archive-autoload-file-name-handler
Date: Wed, 06 Apr 2022 10:49:42 +0200	[thread overview]
Message-ID: <87lewiy4t5.fsf@sperrhaken.name> (raw)
In-Reply-To: <87v8vre7y6.fsf@gmx.de> (Michael Albinus's message of "Sat, 02 Apr 2022 19:00:49 +0200")

[-- Attachment #1: Type: text/plain, Size: 1685 bytes --]

Michael Albinus <michael.albinus@gmx.de> writes:

> Felix Dietrich <felix.dietrich@sperrhaken.name> writes:
>
>>> Anyway, when `tramp-archive-autoload-file-name-handler' is present after
>>> tramp-archive-enabled has become nil, it is used and called but doesn't
>>> handle the request (i.e. returns nil).  AFAIU, that was what I have been
>>> seeing.
>>
>> Could the tramp error handler provide a more helpful error message

Oh, I meant “tramp file handler” here instead of “tramp error handler” –
although I had made wrong assumptions; therefore, this is irrelevant.

> Since this bug is fixed now, I don't believe it is worthful to invest
> more code there.

I am *not* convinced that the reason for this bug has been correctly
identified.  After spending some more time with it, I have come up with
the following test case with which I am now able to produce the error
reliably with revision a5841b196f [1] (that is your patch):

  #+begin_src emacs-lisp
	(let* ((emacs-repo "~/src/emacs/")
		   (foo.iso (concat (file-name-as-directory emacs-repo)
							"test/lisp/net/tramp-archive-resources/foo.iso/")))
	  (load "tramp-archive")
	  (let ((file-name-handler-alist
			 (list (cons (tramp-archive-autoload-file-name-regexp)
						 #'tramp-archive-autoload-file-name-handler)))
			(tramp-archive-enabled nil))
		(file-directory-p foo.iso))))
  #+end_src

With Emacs 27.1, however, I was not able to reproduce the issue.
Therefore, I used “git bisect” between the tag “emacs-27.1” and your
commit a5841b196f with the attached script to find the offending commit
introducing the issue: 4db69b32b8 (“Fix bug#48476”) [2].


[-- Attachment #2: Bisection Script --]
[-- Type: text/x-sh, Size: 2839 bytes --]

#!/bin/sh

# Usage: this_script [recompile [JOBS]]
#
# Without “recompile” this script only removes
# “lisp/net/tramp-archive.elc” to ensure that Emacs uses the
# “tramp-archive” version of the current revision; you have to have
# built Emacs yourself before running this script.
#
# With “recompile” the repository is cleaned, the build configured,
# and then Emacs build, before the test is run.  JOBS is bassed to the
# “-j” switch of “make”, that is: it “specifies the number of jobs to
# run simultaneously”.


# Emacs executable to use
emacs=src/emacs

skip_commit () { exit 125; }
# Can “git bisect” really be properly and reliably
# interupted this way?
interrupt_bisect () { exit 255; }
mark_good () { exit 0; }
mark_bad () { exit 1; }


if [ "$1" = "recompile" ]
then
    jobs=${2:+-j$2}
    {
      git clean -dxf \
      && ./autogen.sh \
      && ./configure --without-x --without-gnutls \
      && make $jobs src
    } || interrupt_bisect
else
    # Ensure that “tramp-archive” from the current revision is used.
    # The byte-compiled version is from the revision where the
    # bisection started and would be preferred by Emacs.
    rm -f lisp/net/tramp-archive.elc
fi

# Restore “build-aux/install-sh” to the version in the current HEAD.
# Otherwise, “git bisect” would abort after the script has finished
# (at least at some revisions) as the checkout of the next revision
# would fail because of changes to this file.
git checkout -- build-aux/install-sh



# \f
##################################################
# The actual Test.
##################################################

"$emacs" -Q --batch --eval \
"
(let ((ret 1))
  (unwind-protect
      (progn
        (load \"tramp-archive\")
        (let ((file-name-handler-alist
               (list (cons (tramp-archive-autoload-file-name-regexp)
                           #'tramp-archive-autoload-file-name-handler)))
              (tramp-archive-enabled nil))
          (file-directory-p
           \"~/emacs/test/lisp/net/tramp-archive-resources/foo.iso/\")
          ;; No error during ‘file-directory-p’
          (setq ret 0)))
    (kill-emacs ret)))
"

ret=$?
case $ret in
    0) mark_good
       ;;
    1) mark_bad
       ;;
    255) # For some revisions the ‘kill-emacs’ in the unwind-form does
         # not work as expected and Emacs instead exits with 255, or
         # maybe that is -1, (as it does on erros in batch mode).
         # Using ‘condition-case’ would proberly fix that (and make a
         # more robust test), but this is quicker and good enough.
        mark_bad
        ;;
    *)
        printf "Unexpected return code by Emacs: %i\n" $ret >&2
        interrupt_bisect
        ;;
esac

[-- Attachment #3: Type: text/plain, Size: 817 bytes --]



At a quick glance, this commit changed the implementation of
‘tramp-archive-autload-file-name-handler’ and might be missing an
else-form.  This causes the autoload handler to return nil when
‘tramp-archive-enabled’ is nil, and, at a slightly longer glance, for
some file name handlers this is wrong and an error.  The attached patch
changes ‘tramp-archive-autoload-file-name-handler’ to always call
‘tramp-autoload-file-name-handler’, setting ‘tramp-archive-autoload’
appropriately.  This may cause a regression, though, of bug #48476 [3]
(“Emacs hangs with 100% cpu if started within a current directory that
has a name ending with ".tar"”).  I have not tested that or spent time
on understanding that bug.  Maybe you still remember enough details of
the bug to judge this.


[-- Attachment #4: Patch to always call ‘tramp-autoload-file-name-handler’ --]
[-- Type: text/x-diff, Size: 2340 bytes --]

From 282fe5b2af1422236b213732d31a176fdea904ed Mon Sep 17 00:00:00 2001
From: Felix Dietrich <felix.dietrich@sperrhaken.name>
Date: Mon, 4 Apr 2022 18:45:17 +0200
Subject: [PATCH] =?UTF-8?q?tramp-archive:=20Always=20call=20=E2=80=98tramp?=
 =?UTF-8?q?-autoload-file-name-handler=E2=80=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Otherwise, not calling ‘tramp-autoload-file-name-handler’ in
‘tramp-archive-autoload-file-name-handler’ when
‘tramp-archive-enabled’ is nil and
‘tramp-archive-autoload-file-name-handler’ is in the
‘file-name-handler-alist’ results in an error “Invalid handler in
‘file-name-handler-alist” once Emacs calls
‘tramp-archive-autoload-file-name-handler’ with a handler that does
not expect nil.  Always returning nil is also false in general.
---
 lisp/net/tramp-archive.el | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index 890c8dbb75..e7ffe2d4f4 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -360,14 +360,13 @@ arguments to pass to the OPERATION."
 (progn (defun tramp-archive-autoload-file-name-handler (operation &rest args)
   "Load Tramp archive file name handler, and perform OPERATION."
   (defvar tramp-archive-autoload)
-  (when tramp-archive-enabled
-    ;; We cannot use `tramp-compat-temporary-file-directory' here due
-    ;; to autoload.  When installing Tramp's GNU ELPA package, there
-    ;; might be an older, incompatible version active.  We try to
-    ;; overload this.
-    (let ((default-directory temporary-file-directory)
-          (tramp-archive-autoload t))
-      (apply #'tramp-autoload-file-name-handler operation args)))))
+  (let (;; We cannot use `tramp-compat-temporary-file-directory' here due
+        ;; to autoload.  When installing Tramp's GNU ELPA package, there
+        ;; might be an older, incompatible version active.  We try to
+        ;; overload this.
+        (default-directory temporary-file-directory)
+        (tramp-archive-autoload tramp-archive-enabled))
+    (apply #'tramp-autoload-file-name-handler operation args))))
 
 (put #'tramp-archive-autoload-file-name-handler 'tramp-autoload t)
 
-- 
2.35.1


[-- Attachment #5: Type: text/plain, Size: 7197 bytes --]



At a much longer glance, in this particular case it is not actually
‘Ffile_directory_p’ (the C function in fileio.c) directly that has an
issue with nil, but, instead, the error is signalled in
‘Fexpand_file_name’, called indirectly by ‘Ffile_directory_p’:

    - Ffile_directory_p
      - expand_and_dir_to_file
        - Fexpand_file_name

‘expand_file_name’ expects a string as the return value from a magic
file name handler; nil, and everything else, is an error.

Now, why is it a problem to add
‘tramp-archive-autoload-file-name-handler’ to ‘file-name-handler-alist’
if ‘tramp-archive-file-name-handler’ is already there?  Why does the
following snipped still fail even though
‘tramp-archive-file-name-handler’ comes first in the handler alist?

   #+begin_src emacs-lisp
     (let* ((emacs-repo "~/src/emacs/")
            (foo.iso
             (concat (file-name-as-directory emacs-repo)
                     "test/lisp/net/tramp-archive-resources/foo.iso/")))
       (load "tramp-archive")
       (let ((tramp-archive-enabled nil)
             (file-name-handler-alist
              (list (cons tramp-archive-file-name-regexp
                          #'tramp-archive-file-name-handler)
                    (cons (tramp-archive-autoload-file-name-regexp)
                          #'tramp-archive-autoload-file-name-handler))))
         (file-directory-p foo.iso)))
   #+end_src

The answer is that the real file handler
‘tramp-archive-file-name-handler’ has its ‘operations’ property set,
which does not include ‘expand-file-name’; the autoload handler has not,
and so, when ‘file-directory-p’ is called, ‘find-file-name-handler’
picks for the ‘expand-file-name’ operation initiated by
‘file-directory-p’ the autoload handler, because the operations property
of ‘tramp-archive-file-name-handler’ indicates that
‘tramp-archive-file-name-handler’ is not applicable.  With
‘tramp-archive-enabled’ bound to nil, the autoload handler then returns
nil and, by that, causes ‘Fexpand_file_name’ to signal the error.  (As
my test above shows, having multiple entries is not significant, it is
the autoload handler that causes the error.)

The erroneous autoload handler:

  #+begin_src emacs-lisp
    (defun tramp-archive-autoload-file-name-handler (operation &rest args)
      "Load Tramp archive file name handler, and perform OPERATION."
      (defvar tramp-archive-autoload)
      (when tramp-archive-enabled
        ;; We cannot use `tramp-compat-temporary-file-directory' here due
        ;; to autoload.  When installing Tramp's GNU ELPA package, there
        ;; might be an older, incompatible version active.  We try to
        ;; overload this.
        (let ((default-directory temporary-file-directory)
              (tramp-archive-autoload t))
          (apply #'tramp-autoload-file-name-handler operation args))))
  #+end_src


I guess other Michael was on the right track:

Michael Heerdegen <michael_heerdegen@web.de> writes:

> Anyway, when `tramp-archive-autoload-file-name-handler' is present after
> tramp-archive-enabled has become nil, it is used and called but doesn't
> handle the request (i.e. returns nil).  AFAIU, that was what I have been
> seeing.

Now, to explain this part and especially the “TWICE”:

> But evaluating this TWICE (the `add-to-list' form is from
> `tramp-register-archive-file-name-handler') does:
> 
>  #+begin_src emacs-lisp
> (add-to-list 'file-name-handler-alist
> 	         (cons (tramp-archive-autoload-file-name-regexp)
> 		       #'tramp-archive-autoload-file-name-handler))
> (file-directory-p
>  "/home/micha/software/emacs/test/lisp/net/tramp-archive-resources/foo.iso/")
>   |--> (error "Invalid handler in ‘file-name-handler-alist’")
> #+end_src
> 
> I think that adding `tramp-archive-autoload-file-name-handler'
> multiple times could be related.

For the first time:

When ‘tramp-archive-enabled’ is initially set to t:

  #+begin_src emacs-lisp
    ;;;###autoload
    (defvar tramp-archive-enabled (featurep 'dbusbind)
      "Non-nil when file archive support is available.")
  #+end_src

then ‘tramp-archive-autoload-file-name-handler’ will initialise tramp by
calling ‘tramp-autoload-file-name-handler’ which will first load
“tramp-archive”, because ‘tramp-archive-enabled’ is t; this can
potentially set ‘tramp-archive-enabled’ to nil:

  #+begin_src emacs-lisp
    ;; In tramp-archive.el,
    ;; right after the (defvar tramp-archive-enabled…
    (setq tramp-archive-enabled tramp-gvfs-enabled)
  #+end_src

  #+begin_src emacs-lisp
    (defconst tramp-gvfs-enabled
    (ignore-errors
      (and (featurep 'dbusbind)
       (autoload 'zeroconf-init "zeroconf")
       (tramp-compat-funcall 'dbus-get-unique-name :system)
       (tramp-compat-funcall 'dbus-get-unique-name :session)
       (or (tramp-process-running-p "gvfs-fuse-daemon")
           (tramp-process-running-p "gvfsd-fuse"))))
    "Non-nil when GVFS is available.")
  #+end_src

After loading “tramp-archive”, ‘tramp-autoload-file-name-handler’
continues with loading “tramp”; this will call, via the
‘tramp--startup-hook’ ‘tramp-register-file-name-handlers’.  This
function will, depending on the value of ‘tramp-archive-enabled’, also
add the ‘tramp-archive-file-name-handler’ to the
‘file-name-handler-alist’.

For the second time:

If ‘tramp-archive-enabled’ is nil now, and you add
‘tramp-archive-autoload-file-name-handler’ again to
‘file-name-handler-alist’, you arrive at the above described problem:
‘Fexpand_file_name’ called from ‘Ffile_directory_p’ will signal an error
because the autoload handler returns nil.

If ‘tramp-archive-enabled’ is t after the first time, the registration
process is simply done a second time; no error occurs.



Footnotes:
[1] commit a5841b196f12894df4c1bb073f28ddadb6faa3cf
    Author: Michael Albinus <michael.albinus@gmx.de>
    Date:   Mon Mar 28 12:02:23 2022 +0200
    Subject:  Do not register Tramp file name handlers twice

    * lisp/net/tramp.el (tramp-register-autoload-file-name-handlers):
    * lisp/net/tramp-archive.el (tramp-register-archive-file-name-handler):
    Check, whether the real file name handler is already registered.


[2] commit 4db69b32b835a833168982b0f11a43d7f62ba8b2
    Author: Michael Albinus <michael.albinus@gmx.de>
    Date:   Sat May 22 17:51:07 2021 +0200
    Subject: Fix bug#48476

    * lisp/net/tramp-archive.el (tramp-archive-autoload-file-name-handler):
    Add implementation.
    
    * lisp/net/tramp-integration.el (tramp-rename-files)
    (tramp-rename-these-files): Declare them.
    
    * lisp/net/tramp.el (tramp-autoload-file-name-handler):
    Load tramp-archive.el if needed.  (Bug#48476)
    
    * test/lisp/net/tramp-archive-tests.el (tramp-archive-test45-auto-load):
    Extend test.
    
    Use #' syntax for function symbols.


[3]  <https://debbugs.gnu.org/cgi/bugreport.cgi?bug=48476>

-- 
Felix Dietrich

  reply	other threads:[~2022-04-06  8:49 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-03-25 23:44 Error with tramp-archive-autoload-file-name-handler Michael Heerdegen
2022-03-26  8:39 ` Michael Albinus
2022-03-26 19:01   ` Michael Heerdegen
2022-03-27  0:06     ` Michael Heerdegen
2022-03-27  8:33       ` Michael Albinus
2022-03-28  2:20         ` Michael Heerdegen
2022-03-28  6:08           ` Felix Dietrich
2022-03-28 10:25             ` Michael Albinus
2022-03-29  0:17               ` Michael Heerdegen
2022-03-29  7:30                 ` Michael Albinus
2022-04-01  1:53                   ` Michael Heerdegen
2022-04-02 12:00                     ` Felix Dietrich
2022-04-02 17:00                       ` Michael Albinus
2022-04-06  8:49                         ` Felix Dietrich [this message]
2022-04-06 18:13                           ` Michael Albinus
2022-04-07 10:14                             ` Michael Albinus
2022-04-07 17:54                               ` Felix Dietrich
2022-04-08  9:41                                 ` Michael Albinus
2022-04-13  2:03                                 ` Michael Heerdegen
2022-04-03  1:26                       ` Michael Heerdegen
2022-04-03 15:57                         ` Michael Albinus
2022-04-04  0:58                           ` Michael Heerdegen
2022-04-04  7:40                             ` Michael Albinus
2022-03-29  0:09             ` Michael Heerdegen
2022-03-27  8:16     ` Michael Albinus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=87lewiy4t5.fsf@sperrhaken.name \
    --to=felix.dietrich@sperrhaken.name \
    --cc=help-gnu-emacs@gnu.org \
    --cc=michael.albinus@gmx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).