unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#31981: 26.1; flymake: removes temporary file before finishing check
@ 2018-06-26 17:26 Enrico Scholz
  2019-08-27 20:35 ` bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug Joel Rosdahl
  0 siblings, 1 reply; 7+ messages in thread
From: Enrico Scholz @ 2018-06-26 17:26 UTC (permalink / raw)
  To: 31981

flymake gets confused and terminates itself when checking needs a long
time.  It can be reproduced with a makefile like

--- Makefile ---
check-syntax:
	sleep 2
	${MAKE} ${CHK_SOURCES}
----------------

1. start 'emacs -Q'

2. open 'foo.c' in the directory with the makefile above

3. M-x flymake-mode

4. start typing

   --> "Wait" appears in status line

5. continue typing

   --> "!" appears in status line and log reports


  | Warning [flymake-proc foo.c]: deleted file /tmp/YYY/foo_flymake.c
  | Warning [flymake-proc  *flymake output for foo.c*-919402]: Reference to file e: *** [Makefile is out of scope
  | Warning [flymake-proc  *flymake output for foo.c*-131024]: Reference to file e: *** [Makefile is out of scope
  | Warning [flymake-proc foo.c]: process 2803326 exited with code 2
  | Error [flymake-proc foo.c]: :configuration-error: Command (make -s -C ./ CHK_SOURCES=foo_flymake.c SYNTAX_CHECK_MODE=1 check-syntax) errored, but no diagnostics
  | Warning [flymake foo.c]: Disabling backend flymake-proc-legacy-flymake because :configuration-error: Command (make -s -C ./ CHK_SOURCES=foo_flymake.c SYNTAX_CHECK_MODE=1 check-syntax) errored, but no diagnostics




--------------
GNU Emacs 26.1 (build 1, x86_64-redhat-linux-gnu, GTK+ Version 2.24.32)
 of 2018-05-31 built on koji-builder4.intern.sigma-chemnitz.de
Windowing system distributor 'Fedora Project', version 11.0.11906000
System Description:	Fedora release 28 (Twenty Eight)

...

Configured using:
 'configure --build=x86_64-redhat-linux-gnu
 --host=x86_64-redhat-linux-gnu --program-prefix=
 --disable-dependency-tracking --prefix=/usr --exec-prefix=/usr
 --bindir=/usr/bin --sbindir=/usr/sbin --sysconfdir=/etc
 --datadir=/usr/share --includedir=/usr/include --libdir=/usr/lib64
 --libexecdir=/usr/libexec --localstatedir=/var
 --sharedstatedir=/var/lib --mandir=/usr/share/man
 --infodir=/usr/share/info --with-dbus --with-gif --with-jpeg --with-png
 --with-rsvg --with-tiff --with-xft --with-xpm --with-x-toolkit=gtk
 --with-gpm=no --with-modules build_alias=x86_64-redhat-linux-gnu
 host_alias=x86_64-redhat-linux-gnu 'CFLAGS=-DMAIL_USE_LOCKF -O2 -g
 -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2
 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-strong
 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1
 -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -mtune=generic
 -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection'
 LDFLAGS=-Wl,-z,relro
 PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'

Configured features:
XPM JPEG TIFF GIF PNG RSVG IMAGEMAGICK SOUND DBUS GSETTINGS NOTIFY ACL
LIBSELINUX GNUTLS LIBXML2 FREETYPE M17N_FLT LIBOTF XFT ZLIB
TOOLKIT_SCROLL_BARS GTK2 X11 MODULES THREADS LCMS2

Important settings:
  value of $LC_COLLATE: C
  value of $LANG: de_DE.UTF-8
  locale-coding-system: utf-8-unix





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2018-06-26 17:26 bug#31981: 26.1; flymake: removes temporary file before finishing check Enrico Scholz
@ 2019-08-27 20:35 ` Joel Rosdahl
  2019-08-27 23:37   ` Noam Postavsky
  0 siblings, 1 reply; 7+ messages in thread
From: Joel Rosdahl @ 2019-08-27 20:35 UTC (permalink / raw)
  To: 31981

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

I can reproduce this bug on latest master.

The problem is that if a check command takes a long time, the
following can happen:

1. The user modifies the buffer, making flymake-proc start a process A
which reads from a temporary file T containing the buffer content.
2. Before process A has finished, the user modifies the buffer again,
making flymake-proc start a new process B reading from the same
temporary file T.
3. A is marked as obsolete.
4. When A's sentinel detects that A has died, it runs A's cleanup
function which deletes T.
5. B may fail since T is gone.

Attached is a patch which solves the issue, at least for me: simply
don't run the cleanup function for an obsolete process. This should
work well for checks that use flymake-proc-simple-cleanup or one of
the other cleanup functions defined in flymake-proc.el.

I'm not sure if the fix is appropriate for the general case with a
user-supplied custom cleanup function, though. But I see no other
quick fix for the issue since the name of the temporary file is kept
in a single buffer-local variable and there is no way for the cleanup
function to know that it's being called for an obsolete process.

-- Joel

[-- Attachment #2: 0001-Fix-flymake-proc-temporary-file-deletion-bug.patch --]
[-- Type: text/x-patch, Size: 1577 bytes --]

From fef0fe5ed6cec78e87f29444af8d400bcbd01e72 Mon Sep 17 00:00:00 2001
From: Joel Rosdahl <joel@rosdahl.net>
Date: Tue, 27 Aug 2019 22:00:45 +0200
Subject: [PATCH] Fix flymake-proc temporary file deletion bug

* list/progmodes/flymake-proc.el (flymake-proc--process-sentinel):
Don't run cleanup if this is an obsolete process -- deleting the
temporary file will make the the active process fail since it uses the
same file. (Bug#31981)
---
 lisp/progmodes/flymake-proc.el | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index 2d5a47a07978..2095de6117e5 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -649,7 +649,12 @@ flymake-proc--process-sentinel
                (flymake-log 3 "Output buffer %s kept alive for debugging"
                             output-buffer))
               (t
-               (when (buffer-live-p source-buffer)
+               (when (and (buffer-live-p source-buffer)
+                          ;; Don't run cleanup if this is an obsolete
+                          ;; process -- deleting the temporary file
+                          ;; will make the the active process fail
+                          ;; since it uses the same file (bug#31981):
+                          (not (process-get proc 'flymake-proc--obsolete)))
                  (with-current-buffer source-buffer
                    (let ((cleanup-f (flymake-proc--get-cleanup-function
                                      (buffer-file-name))))
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2019-08-27 20:35 ` bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug Joel Rosdahl
@ 2019-08-27 23:37   ` Noam Postavsky
  2019-08-28 19:18     ` Joel Rosdahl
  0 siblings, 1 reply; 7+ messages in thread
From: Noam Postavsky @ 2019-08-27 23:37 UTC (permalink / raw)
  To: Joel Rosdahl; +Cc: 31981

Joel Rosdahl <joel@rosdahl.net> writes:

> 1. The user modifies the buffer, making flymake-proc start a process A
> which reads from a temporary file T containing the buffer content.
> 2. Before process A has finished, the user modifies the buffer again,
> making flymake-proc start a new process B reading from the same
> temporary file T.

If I'm reading flymake-proc-init-create-temp-buffer-copy correctly, it
actually makes a new temporary file (say T1), but the file name is
stored in a single variable, so Emacs effectively forgets about the
original file T.

> 3. A is marked as obsolete.
> 4. When A's sentinel detects that A has died, it runs A's cleanup
> function which deletes T.

So here it deletes T1, leaving the original T.  And then B will fail,
since it needs T1, not T.

> But I see no other quick fix for the issue since the name of the
> temporary file is kept in a single buffer-local variable and there is
> no way for the cleanup function to know that it's being called for an
> obsolete process.

Would it work to store the filename in the process object instead, with
process-put (and then the sentinel can retreive it with process-get)?






^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2019-08-27 23:37   ` Noam Postavsky
@ 2019-08-28 19:18     ` Joel Rosdahl
  2019-08-29 16:04       ` Noam Postavsky
  0 siblings, 1 reply; 7+ messages in thread
From: Joel Rosdahl @ 2019-08-28 19:18 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 31981

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

On Wed, 28 Aug 2019 at 01:38, Noam Postavsky <npostavs@gmail.com> wrote:
> If I'm reading flymake-proc-init-create-temp-buffer-copy correctly, it
> actually makes a new temporary file (say T1), but the file name is stored in
> a single variable, so Emacs effectively forgets about the original file T.

The create-temp-f parameter to flymake-proc-init-create-temp-buffer-copy is in
practice flymake-proc-create-temp-inplace, which always creates the same result
for a given file-name and prefix. And file-name and prefix are the same for
both modification A and B (since it's the same file). Or am I missing
something?

> So here it deletes T1, leaving the original T. And then B will fail, since it
> needs T1, not T.

Nope, it's T both times, but it's true that only generating a unique filename
wouldn't fix the issue since, as you said, the filename is stored in a single
variable.

> Would it work to store the filename in the process object instead, with
> process-put (and then the sentinel can retreive it with process-get)?

Yes, flymake-proc-create-temp-inplace could create a unique filename and store
it in the process, but that wouldn't help since the cleanup function doesn't
have access to the process (since the process is stored in a single variable as
well). Passing the process or filename(s) to the cleanup function would work,
but it would break the interface to existing custom cleanup functions which
don't take a parameter, so I wrote off that solution earlier.

...unless we can pass the value(s) using dynamic binding to the cleanup
function. I didn't consider this before since lexical binding would prevent
such a solution, but I just learnt to my surprise that global defvar-ed
variables are still dynamically scoped.

Attached is a new proposed solution as sketched above.

-- Joel

[-- Attachment #2: 0001-Fix-flymake-proc-temporary-file-deletion-bug.patch --]
[-- Type: text/x-patch, Size: 3142 bytes --]

From 81f885381343f4f08d0aef1fd0589e76f841bdb8 Mon Sep 17 00:00:00 2001
From: Joel Rosdahl <joel@rosdahl.net>
Date: Wed, 28 Aug 2019 21:00:00 +0200
Subject: [PATCH] Fix flymake-proc temporary file deletion bug

* list/progmodes/flymake-proc.el (flymake-proc-create-temp-inplace):
Include a time string part (hour + minute + second + nanosecond) in the
temporary name to make it unique enough.

* list/progmodes/flymake-proc.el (flymake-proc-legacy-flymake): Store
temporary file names in the process for usage in the sentinel.

* list/progmodes/flymake-proc.el (flymake-proc--process-sentinel): Bind
values of temporary file names dynamically to values stored in the
process so that the cleanup function will delete the correct temporary
file(s).

Fixes bug#31981.
---
 lisp/progmodes/flymake-proc.el | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/lisp/progmodes/flymake-proc.el b/lisp/progmodes/flymake-proc.el
index 2d5a47a07978..f08ba2f36817 100644
--- a/lisp/progmodes/flymake-proc.el
+++ b/lisp/progmodes/flymake-proc.el
@@ -654,7 +654,14 @@ flymake-proc--process-sentinel
                    (let ((cleanup-f (flymake-proc--get-cleanup-function
                                      (buffer-file-name))))
                      (flymake-log 3 "cleaning up using %s" cleanup-f)
-                     (funcall cleanup-f))))
+                     ;; Make cleanup-f see the temporary file names
+                     ;; created by its corresponding init function
+                     ;; (bug#31981).
+                     (let ((flymake-proc--temp-source-file-name
+                            (process-get proc 'flymake-proc--temp-source-file-name))
+                           (flymake-proc--temp-master-file-name
+                            (process-get proc 'flymake-proc--temp-master-file-name)))
+                       (funcall cleanup-f)))))
                (kill-buffer output-buffer)))))))
 
 (defun flymake-proc--panic (problem explanation)
@@ -824,6 +831,10 @@ flymake-proc-legacy-flymake
                   (process-put proc 'flymake-proc--output-buffer
                                (generate-new-buffer
                                 (format " *flymake output for %s*" (current-buffer))))
+                  (process-put proc 'flymake-proc--temp-source-file-name
+                               flymake-proc--temp-source-file-name)
+                  (process-put proc 'flymake-proc--temp-master-file-name
+                               flymake-proc--temp-master-file-name)
                   (setq flymake-proc--current-process proc)
                   (flymake-log 2 "started process %d, command=%s, dir=%s"
                                (process-id proc) (process-command proc)
@@ -865,6 +876,7 @@ flymake-proc-create-temp-inplace
   (let* ((ext (file-name-extension file-name))
 	 (temp-name (file-truename
 		     (concat (file-name-sans-extension file-name)
+                             "_" (format-time-string "%H%M%S%N")
 			     "_" prefix
 			     (and ext (concat "." ext))))))
     (flymake-log 3 "create-temp-inplace: file=%s temp=%s" file-name temp-name)
-- 
2.20.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2019-08-28 19:18     ` Joel Rosdahl
@ 2019-08-29 16:04       ` Noam Postavsky
  2019-08-29 17:30         ` Joel Rosdahl
  0 siblings, 1 reply; 7+ messages in thread
From: Noam Postavsky @ 2019-08-29 16:04 UTC (permalink / raw)
  To: Joel Rosdahl; +Cc: 31981

Joel Rosdahl <joel@rosdahl.net> writes:

> On Wed, 28 Aug 2019 at 01:38, Noam Postavsky <npostavs@gmail.com> wrote:
>> If I'm reading flymake-proc-init-create-temp-buffer-copy correctly, it
>> actually makes a new temporary file (say T1), but the file name is stored in
>> a single variable, so Emacs effectively forgets about the original file T.
>
> The create-temp-f parameter to flymake-proc-init-create-temp-buffer-copy is in
> practice flymake-proc-create-temp-inplace, which always creates the same result
> for a given file-name and prefix. And file-name and prefix are the same for
> both modification A and B (since it's the same file). Or am I missing
> something?

No, it's just me who missed this.  There's a lot of indirection, and I
didn't read that carefully.

> but I just learnt to my surprise that global defvar-ed
> variables are still dynamically scoped.

Well, they would be unusable otherwise, since global vars don't have any
lexical scope as such.

> +                     ;; Make cleanup-f see the temporary file names
> +                     ;; created by its corresponding init function
> +                     ;; (bug#31981).
> +                     (let ((flymake-proc--temp-source-file-name
> +                            (process-get proc 'flymake-proc--temp-source-file-name))
> +                           (flymake-proc--temp-master-file-name
> +                            (process-get proc 'flymake-proc--temp-master-file-name)))
> +                       (funcall cleanup-f)))))

A little awkward, but that's proably the best we can do without changing
the signature of cleanup-f (which I guess would be much more
troublesome).






^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2019-08-29 16:04       ` Noam Postavsky
@ 2019-08-29 17:30         ` Joel Rosdahl
  2019-09-07 21:05           ` Noam Postavsky
  0 siblings, 1 reply; 7+ messages in thread
From: Joel Rosdahl @ 2019-08-29 17:30 UTC (permalink / raw)
  To: Noam Postavsky; +Cc: 31981

On Thu, 29 Aug 2019 at 18:05, Noam Postavsky <npostavs@gmail.com> wrote:
> A little awkward, but that's proably the best we can do without changing
> the signature of cleanup-f (which I guess would be much more
> troublesome).

I agree. Alternative solutions welcome, of course.

-- Joel





^ permalink raw reply	[flat|nested] 7+ messages in thread

* bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug
  2019-08-29 17:30         ` Joel Rosdahl
@ 2019-09-07 21:05           ` Noam Postavsky
  0 siblings, 0 replies; 7+ messages in thread
From: Noam Postavsky @ 2019-09-07 21:05 UTC (permalink / raw)
  To: Joel Rosdahl; +Cc: 31981

tags 31981 fixed
close 31981 27.1
quit

Joel Rosdahl <joel@rosdahl.net> writes:

> On Thu, 29 Aug 2019 at 18:05, Noam Postavsky <npostavs@gmail.com> wrote:
>> A little awkward, but that's proably the best we can do without changing
>> the signature of cleanup-f (which I guess would be much more
>> troublesome).
>
> I agree. Alternative solutions welcome, of course.
>
> -- Joel

None seems forthcoming, so I've pushed your patch to master (I coalesced
your ChangeLog entries, by the way).

8d588f09e9 2019-09-07T16:51:24-04:00 "Fix flymake-proc temporary file deletion bug"
https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=8d588f09e91e315c715cf824a9819a538a85cd9c






^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2019-09-07 21:05 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-06-26 17:26 bug#31981: 26.1; flymake: removes temporary file before finishing check Enrico Scholz
2019-08-27 20:35 ` bug#31981: Fix 'flymake-proc-legacy-flymake' temporary file deletion bug Joel Rosdahl
2019-08-27 23:37   ` Noam Postavsky
2019-08-28 19:18     ` Joel Rosdahl
2019-08-29 16:04       ` Noam Postavsky
2019-08-29 17:30         ` Joel Rosdahl
2019-09-07 21:05           ` Noam Postavsky

Code repositories for project(s) associated with this public inbox

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

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).