all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: JD Smith <jdtsmith@gmail.com>
To: Stefan Kangas <stefankangas@gmail.com>
Cc: Lars Ingebrigtsen <larsi@gnus.org>, 57883-done@debbugs.gnu.org
Subject: bug#57883: compilation-get-file-structure mishandles buffers
Date: Sun, 3 Sep 2023 09:36:16 -0400	[thread overview]
Message-ID: <18051D5E-0D75-410C-A89C-2BF92BD0C471@gmail.com> (raw)
In-Reply-To: <CADwFkmk+ynNCm1BY-nTZyXtCK0Pf2Rh4JPDBd41VSJ=V=B4tJQ@mail.gmail.com>

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

Thanks for the query.  This is still an issue in Emacs 29 with emacs -Q.  

Short summary: `compilation-error-regexp-alist’ explicitly allows returning *buffers* from a specified file-name function .  But parsing errors using such a buffer-returning function fails, since `compilation-get-file-structure’ explicitly assumes that a file name is returned, checking it with `file-name-absolute-p’.  In my code I’ve worked around this bug by cl-letf’ing the `file-name-absolute-p’ function like:

(defun my/traceback--file-name-absolute-p (file-or-buffer)
  "A patch for `file-name-absolute-p' to handle buffer names.
`compilation-get-file-structure' has a bug in which it calls
`file-name-absolute-p' on a file parsed from an error, which
explicitly allows FILE-OR-BUFFER to be a buffer."
  (and (not (bufferp file-or-buffer))
       (funcall #’my/traceback--orig-file-name-absolute-p file-or-buffer)))

Reproducer: The reproduction recipe was in the linked emacs-devel <https://lists.gnu.org/archive/html/emacs-devel/2022-02/msg00496.html> thread.  Here it is again (with Emacs 29 updates in [brackets]):

++++

Reproducing is fairly straightforward.  First, evaluate this simple “error line” pattern:

(defun my/filename-function () (list (get-buffer (match-string 1))))
(defvar my/compilation-error-regexp
  `((,(rx line-start 
	  "Buffer \"" (group (+ (not "\""))) "\", " ; 1: buffer name
	  "line" (+ space) (group (+ digit))	    ; 2: line
	  (* nonl) ?\n)
     my/filename-function
     2
     nil nil 1)))

Then, in a buffer like *compile* put the following fake error for it to match (including a final newline):

Buffer "*scratch*", line 2

In that buffer, evaluate (e.g. via M-:):

(progn (compilation-setup)
       (setq compilation-error-regexp-alist my/compilation-error-regexp)
       (compilation-parse-errors (point-min) (point-max)))

You should see error 1.) pertaining to searching the (nil) filename for /bin/sh (which may have been fixed in Emacs 28 already). [Emacs 29 update: it has]

[Update: This step is unnecessary in emacs 29] Now, let’s eliminate that error by evaluating (again in *compile*):

(setq compilation-transform-file-match-alist nil)

To stop the transform check.  Now evaluate again:

(compilation-parse-errors (point-min) (point-max))

and you will see a different error (2.) from `compilation-get-file-structure', which does not appreciate being handed a buffer instead of a file, despite the documented validity of this input:

Debugger entered--Lisp error: (wrong-type-argument stringp #<buffer *scratch*>)
  #<subr file-name-absolute-p>(#<buffer *scratch*>)
  apply(#<subr file-name-absolute-p> #<buffer *scratch*>)
  #f(compiled-function (body &rest args) #<bytecode 0x1a0bc3925a352795>)(#<subr file-name-absolute-p> #<buffer *scratch*>)
  apply(#f(compiled-function (body &rest args) #<bytecode 0x1a0bc3925a352795>) #<subr file-name-absolute-p> #<buffer *scratch*>)
  file-name-absolute-p(#<buffer *scratch*>)
  compilation-get-file-structure((#<buffer *scratch*>) nil)
  compilation-internal-error-properties((#<buffer *scratch*>) 2 nil nil nil 2 nil nil)
  compilation-error-properties(my/filename-function 2 nil nil nil 2 nil nil)
  (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule))
  (if (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule)) (progn (if file (progn (let ((this-type (if ... ... ...))) (compilation--note-type this-type) (compilation--put-prop file 'font-lock-face (symbol-value (aref ... this-type)))))) (compilation--put-prop line 'font-lock-face compilation-line-face) (compilation--put-prop end-line 'font-lock-face compilation-line-face) (compilation--put-prop col 'font-lock-face compilation-column-face) (compilation--put-prop end-col 'font-lock-face compilation-column-face) (let ((tail (nthcdr 6 item))) (while tail (let ((extra-item (car tail))) (let ((mn ...)) (if (match-beginning mn) (progn ...))) (setq tail (cdr tail))))) (let ((mn (or (nth 5 item) 0))) (if compilation-debug (progn (font-lock-append-text-property (match-beginning 0) (match-end 0) 'compilation-debug (vector 'std item props)))) (add-text-properties (match-beginning mn) (match-end mn) (cdr (cdr props))) (font-lock-append-text-property (match-beginning mn) (match-end mn) 'font-lock-face (car (cdr props))))))
  (while (and pat (re-search-forward pat end t)) (if (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule)) (progn (if file (progn (let ((this-type ...)) (compilation--note-type this-type) (compilation--put-prop file 'font-lock-face (symbol-value ...))))) (compilation--put-prop line 'font-lock-face compilation-line-face) (compilation--put-prop end-line 'font-lock-face compilation-line-face) (compilation--put-prop col 'font-lock-face compilation-column-face) (compilation--put-prop end-col 'font-lock-face compilation-column-face) (let ((tail (nthcdr 6 item))) (while tail (let ((extra-item ...)) (let (...) (if ... ...)) (setq tail (cdr tail))))) (let ((mn (or (nth 5 item) 0))) (if compilation-debug (progn (font-lock-append-text-property (match-beginning 0) (match-end 0) 'compilation-debug (vector ... item props)))) (add-text-properties (match-beginning mn) (match-end mn) (cdr (cdr props))) (font-lock-append-text-property (match-beginning mn) (match-end mn) 'font-lock-face (car (cdr props)))))))
  (let* ((item (if (symbolp rule-item) (cdr (assq rule-item compilation-error-regexp-alist-alist)) rule-item)) (pat (car item)) (file (nth 1 item)) (line (nth 2 item)) (col (nth 3 item)) (type (nth 4 item)) (rule (and (symbolp rule-item) rule-item)) end-line end-col fmt props) (cond ((or (not omake-included) (not pat)) nil) ((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat) nil) (t (setq pat (concat "^\\(?:      \\)?" (substring pat 1))))) (if (and (consp file) (not (functionp file))) (progn (setq fmt (cdr file)) (setq file (car file)))) (if (and (consp line) (not (functionp line))) (progn (setq end-line (cdr line)) (setq line (car line)))) (if (and (consp col) (not (functionp col))) (progn (setq end-col (cdr col)) (setq col (car col)))) (if (or (null (nth 5 item)) (integerp (nth 5 item))) nil (error "HYPERLINK should be an integer: %s" (nth 5 item))) (goto-char start) (while (and pat (re-search-forward pat end t)) (if (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule)) (progn (if file (progn (let (...) (compilation--note-type this-type) (compilation--put-prop file ... ...)))) (compilation--put-prop line 'font-lock-face compilation-line-face) (compilation--put-prop end-line 'font-lock-face compilation-line-face) (compilation--put-prop col 'font-lock-face compilation-column-face) (compilation--put-prop end-col 'font-lock-face compilation-column-face) (let ((tail (nthcdr 6 item))) (while tail (let (...) (let ... ...) (setq tail ...)))) (let ((mn (or ... 0))) (if compilation-debug (progn (font-lock-append-text-property ... ... ... ...))) (add-text-properties (match-beginning mn) (match-end mn) (cdr (cdr props))) (font-lock-append-text-property (match-beginning mn) (match-end mn) 'font-lock-face (car (cdr props))))))))
  (let ((rule-item (car tail))) (let* ((item (if (symbolp rule-item) (cdr (assq rule-item compilation-error-regexp-alist-alist)) rule-item)) (pat (car item)) (file (nth 1 item)) (line (nth 2 item)) (col (nth 3 item)) (type (nth 4 item)) (rule (and (symbolp rule-item) rule-item)) end-line end-col fmt props) (cond ((or (not omake-included) (not pat)) nil) ((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat) nil) (t (setq pat (concat "^\\(?:      \\)?" (substring pat 1))))) (if (and (consp file) (not (functionp file))) (progn (setq fmt (cdr file)) (setq file (car file)))) (if (and (consp line) (not (functionp line))) (progn (setq end-line (cdr line)) (setq line (car line)))) (if (and (consp col) (not (functionp col))) (progn (setq end-col (cdr col)) (setq col (car col)))) (if (or (null (nth 5 item)) (integerp (nth 5 item))) nil (error "HYPERLINK should be an integer: %s" (nth 5 item))) (goto-char start) (while (and pat (re-search-forward pat end t)) (if (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule)) (progn (if file (progn (let ... ... ...))) (compilation--put-prop line 'font-lock-face compilation-line-face) (compilation--put-prop end-line 'font-lock-face compilation-line-face) (compilation--put-prop col 'font-lock-face compilation-column-face) (compilation--put-prop end-col 'font-lock-face compilation-column-face) (let ((tail ...)) (while tail (let ... ... ...))) (let ((mn ...)) (if compilation-debug (progn ...)) (add-text-properties (match-beginning mn) (match-end mn) (cdr ...)) (font-lock-append-text-property (match-beginning mn) (match-end mn) 'font-lock-face (car ...))))))) (setq tail (cdr tail)))
  (while tail (let ((rule-item (car tail))) (let* ((item (if (symbolp rule-item) (cdr (assq rule-item compilation-error-regexp-alist-alist)) rule-item)) (pat (car item)) (file (nth 1 item)) (line (nth 2 item)) (col (nth 3 item)) (type (nth 4 item)) (rule (and (symbolp rule-item) rule-item)) end-line end-col fmt props) (cond ((or (not omake-included) (not pat)) nil) ((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat) nil) (t (setq pat (concat "^\\(?:      \\)?" (substring pat 1))))) (if (and (consp file) (not (functionp file))) (progn (setq fmt (cdr file)) (setq file (car file)))) (if (and (consp line) (not (functionp line))) (progn (setq end-line (cdr line)) (setq line (car line)))) (if (and (consp col) (not (functionp col))) (progn (setq end-col (cdr col)) (setq col (car col)))) (if (or (null (nth 5 item)) (integerp (nth 5 item))) nil (error "HYPERLINK should be an integer: %s" (nth 5 item))) (goto-char start) (while (and pat (re-search-forward pat end t)) (if (setq props (compilation-error-properties file line end-line col end-col (or type 2) fmt rule)) (progn (if file (progn ...)) (compilation--put-prop line 'font-lock-face compilation-line-face) (compilation--put-prop end-line 'font-lock-face compilation-line-face) (compilation--put-prop col 'font-lock-face compilation-column-face) (compilation--put-prop end-col 'font-lock-face compilation-column-face) (let (...) (while tail ...)) (let (...) (if compilation-debug ...) (add-text-properties ... ... ...) (font-lock-append-text-property ... ... ... ...)))))) (setq tail (cdr tail))))
  (let ((tail (or rules compilation-error-regexp-alist))) (while tail (let ((rule-item (car tail))) (let* ((item (if (symbolp rule-item) (cdr ...) rule-item)) (pat (car item)) (file (nth 1 item)) (line (nth 2 item)) (col (nth 3 item)) (type (nth 4 item)) (rule (and (symbolp rule-item) rule-item)) end-line end-col fmt props) (cond ((or (not omake-included) (not pat)) nil) ((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat) nil) (t (setq pat (concat "^\\(?:      \\)?" ...)))) (if (and (consp file) (not (functionp file))) (progn (setq fmt (cdr file)) (setq file (car file)))) (if (and (consp line) (not (functionp line))) (progn (setq end-line (cdr line)) (setq line (car line)))) (if (and (consp col) (not (functionp col))) (progn (setq end-col (cdr col)) (setq col (car col)))) (if (or (null (nth 5 item)) (integerp (nth 5 item))) nil (error "HYPERLINK should be an integer: %s" (nth 5 item))) (goto-char start) (while (and pat (re-search-forward pat end t)) (if (setq props (compilation-error-properties file line end-line col end-col ... fmt rule)) (progn (if file ...) (compilation--put-prop line ... compilation-line-face) (compilation--put-prop end-line ... compilation-line-face) (compilation--put-prop col ... compilation-column-face) (compilation--put-prop end-col ... compilation-column-face) (let ... ...) (let ... ... ... ...))))) (setq tail (cdr tail)))))
  (let ((case-fold-search compilation-error-case-fold-search) (omake-included (memq 'omake compilation-error-regexp-alist))) (let ((tail (or rules compilation-error-regexp-alist))) (while tail (let ((rule-item (car tail))) (let* ((item (if ... ... rule-item)) (pat (car item)) (file (nth 1 item)) (line (nth 2 item)) (col (nth 3 item)) (type (nth 4 item)) (rule (and ... rule-item)) end-line end-col fmt props) (cond ((or ... ...) nil) ((string-match "\\`\\([^^]\\|\\^\\( \\*\\|\\[\\)\\)" pat) nil) (t (setq pat ...))) (if (and (consp file) (not ...)) (progn (setq fmt ...) (setq file ...))) (if (and (consp line) (not ...)) (progn (setq end-line ...) (setq line ...))) (if (and (consp col) (not ...)) (progn (setq end-col ...) (setq col ...))) (if (or (null ...) (integerp ...)) nil (error "HYPERLINK should be an integer: %s" (nth 5 item))) (goto-char start) (while (and pat (re-search-forward pat end t)) (if (setq props ...) (progn ... ... ... ... ... ... ...)))) (setq tail (cdr tail))))))
  compilation-parse-errors(1 28)
  eval-expression((compilation-parse-errors (point-min) (point-max)) nil nil 127)
  funcall-interactively(eval-expression (compilation-parse-errors (point-min) (point-max)) nil nil 127)
  command-execute(eval-expression)

+++

> On Sep 3, 2023, at 5:18 AM, Stefan Kangas <stefankangas@gmail.com> wrote:
> 
> Lars Ingebrigtsen <larsi@gnus.org> writes:
> 
>> JD Smith <jdtsmith@gmail.com> writes:
>> 
>>> Note that this is useful for modes which report errors in text from open buffers, which
>>> may have no associated file.   The issue is this line in `compilation-get-file-structure’:
>>> 
>>> (if (file-name-absolute-p filename)
>>>   (setq filename (concat comint-file-name-prefix filename)))
>>> which signals an
>> 
>> This is how your email ended, so I think your message may have been cut
>> off?
>> 
>> In any case, do you have a recipe to reproduce the problem, starting
>> from "emacs -Q"?
> 
> More information was requested, but none was given within 12 months, so
> I'm closing this bug.
> 
> If this is still an issue, please reply to this email (use "Reply to
> all" in your email client) and we can reopen the bug report.


[-- Attachment #2: Type: text/html, Size: 18528 bytes --]

  reply	other threads:[~2023-09-03 13:36 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-09-17 14:25 bug#57883: compilation-get-file-structure mishandles buffers JD Smith
2022-09-18 10:55 ` Lars Ingebrigtsen
2023-09-03  9:18   ` Stefan Kangas
2023-09-03 13:36     ` JD Smith [this message]
2023-09-03 18:27       ` Stefan Kangas
2024-01-10 10:55         ` Stefan Kangas
2024-01-10 22:14           ` JD Smith
2024-01-10 23:20             ` Stefan Kangas

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

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

  git send-email \
    --in-reply-to=18051D5E-0D75-410C-A89C-2BF92BD0C471@gmail.com \
    --to=jdtsmith@gmail.com \
    --cc=57883-done@debbugs.gnu.org \
    --cc=larsi@gnus.org \
    --cc=stefankangas@gmail.com \
    /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.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.