On Thu, Jun 12, 2025 at 7:19 PM Eli Zaretskii wrote: > > From: Jimmy Yuen Ho Wong > > Date: Thu, 12 Jun 2025 17:58:34 +0100 > > > > > > When investigating https://github.com/emacs-lsp/lsp-mode/issues/4782 and > > https://github.com/purcell/emacs-reformatter/issues/63, I've discovered > > the following bug in insert-file-contents. > > > > Reproduction: > > > > 1. echo "hello world" > ~/test.txt > > 2. emacs -q ~/test.txt > > 3. M-x eval-expression RET (add-hook 'after-change-functions (lambda > (&rest _) (message "buffer-file-name: %s, current-buffer: %s" > (buffer-file-name) (current-buffer))) nil t) RET > > 4. Type something into the buffer > > 5. M-x eval-expression RET (insert-file-contents (buffer-file-name) nil > nil nil t) RET > > 6. Switch to the *Messages* buffer and observe the buffer file name is > nil. > > > > Expectation: > > > > insert-file-contents should not set buffer-file-name to nil > > I don't think it does. (buffer-file-name) returns nil when the call > is evaluated in the minibuffer, and I thin that's what you see. After > performing the above recipe the buffer-filename of the buffer that > visits test.txt remains to be "test.txt", at least in my testing. So > the only evidence that it's set to nil are the messages logged in > *Messages*, and they are about a different buffer. > When a lisp expression is evaluated in the minibuffer, the current buffer is the file buffer, not the minibuffer. You can easily verify this with M-x eval-expression RET (current-buffer) RET. The crux of the matter is the lambda added to after-change-function. `insert-file-contents` calls `signals_after_change` (fileio.c line 5007 on master), which will run the after-change-functions. It is at this moment the buffer-file-name is nil. In addition, the following will NOT result in insert-file-contents temporarily setting the buffer-file-name of the current buffer to nil: (let ((coding-system-for-read 'no-conversion) (coding-system-for-write 'no-conversion)) (insert-file-contents (buffer-file-name) nil nil nil t)) Which suggests some of the code conversion logic in the C function is erroneously setting the current buffer's file-name to nil, and then running the after-change-functions before resetting it.