Subject: bug#61668: Bug in flymake-proc with fix

From: Stefan Kangas <[email-masked]>
Date: Mon, 9 Oct 2023 07:45:59 +0000

Camden Narzt via "Bug reports for GNU Emacs, the Swiss army knife of
text editors" <[email-masked]> writes:

> I’m currently seeing incorrect behaviour from the `flymake-proc--delete-temp-directory` function. The path is parsed and then reassembled incorrectly as the following backtrace extract demonstrates:
>
> flymake-proc--safe-delete-directory("/private/var/folders/p7/03_g5t611499lmjqhwc5tljr0000gn/T/000gn/T/Users/camdennarzt/Developer/Java/getargv.java/src/main/java/cam/narzt/getargv")
> flymake-proc--delete-temp-directory("/private/var/folders/p7/03_g5t611499lmjqhwc5tljr0000gn/T/Users/camdennarzt/Developer/Java/getargv.java/src/main/java/cam/narzt/getargv/“)
>
> As you can see the `000gn/T/` segment of the path gets duplicated when `flymake-proc--safe-delete-directory` gets called.
>
> This is because in `flymake-proc--delete-temp-directory` when the `suffix` variable is declared it is assumed that `(directory-file-name temporary-file-directory)` is a prefix of the `dir-name` argument, however `(directory-file-name temporary-file-directory)` doesn’t seem to resolve symlinks in the path whereas `dir-name` seems to have symlinks already resolved, so they don’t necessarily match. On my system the difference is:
>
> (directory-file-name temporary-file-directory) → "/var/folders/p7/03_g5t611499lmjqhwc5tljr0000gn/T”
> dir-name → "/private/var/folders/p7/03_g5t611499lmjqhwc5tljr0000gn/T/Users/camdennarzt/Developer/Java/getargv.java/src/main/java/cam/narzt/getargv/“
>
> Note the "/private” prefix on the `dir-name` path. That difference in length causes the suffix to be incorrectly determined and then causes a bunch of errors while any subsequent function call tries to work with a path with the `000gn/T/` segment duplicated which obviously doesn’t exist in the fs.
>
> Changing the suffix variable to be computed as follows fixes the bug:
>
> (substring dir-name (1+ (length (file-truename (expand-file-name (directory-file-name temp-dir))))))

Taking a closer look, I'm not yet sure about the proposed fix.  First,
it seems like you're using macOS, which you did not mention in your bug
report.  Which version of macOS are you using?

Reducing the code down to something more minimal, I see this on my
macOS 12.7 machine.  The original code produces something like this:

    (let* ((temp-dir (file-truename temporary-file-directory))
           (dir (directory-file-name temp-dir)))
      (cons dir (length dir)))
    => ("/private/var/folders/pj/rhx0gxy15tv3vx6l3mdy0qvm0000gn/T" . 56)

This is your fix---i.e. (file-truename (expand-file-name ...))---and I
get the exact same result here:

    (let* ((temp-dir (file-truename temporary-file-directory))
           (dir (file-truename (expand-file-name
                                (directory-file-name temp-dir)))))
      (cons dir (length dir)))
    => ("/private/var/folders/pj/rhx0gxy15tv3vx6l3mdy0qvm0000gn/T" . 56)

I'm also seeing the same result if I skip the call to
`expand-file-name':

    (let* ((temp-dir (file-truename temporary-file-directory))
           (dir (file-truename (directory-file-name temp-dir))))
      (cons dir (length dir)))
    => ("/private/var/folders/pj/rhx0gxy15tv3vx6l3mdy0qvm0000gn/T" . 56)

What do the above forms evaluate to on your machine?

Thanks.