bug-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

bug#13860: 24.2; dir-locals-directory-cache unreliable in one rare case


From: Johan Claesson
Subject: bug#13860: 24.2; dir-locals-directory-cache unreliable in one rare case
Date: Sun, 18 Aug 2019 21:19:01 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux)



Hi Lars,

I can reproduce with emacs -Q on Emacs 27 (ee1c638cff).  I get the wrong
value about 1 time in 3 tries.

(I cannot reproduce without -Q.  In particular when magit-autorevert is
loaded that will "fix" the issue.  Probably by slowing things down.)

My original description is a bit incorrect/misleading.  The race
condition is not about if it occurs in the same second or not.  But it
is about when two file modification timestamps are equal.

What happens seem to be that sometimes the second time the
.dir-locals.el file is written (now with value foo = 2) the file will
get the same timestamp as it already have from the first write.  At this
point the dir-locals-class-alist cache is not updated (it still have foo
= 1).

The cache is supposed to be updated when reading the .dir-locals.el. 
But that is only done if .dir-locals.el modification timestamp is newer
than the timestamp in the cache.  Sometimes they are the same just because 
the clock have not ticked forward.

I think one way to remedy this would be to explicitly invalidate the
directory cache every time a .dir-local.el file is modified.  Something
like the following seem to do the trick:

diff --git a/lisp/files-x.el b/lisp/files-x.el
index b71e9204f3..6b04518fe4 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -491,6 +491,13 @@ modify-dir-local-variable
                (cons `(,mode . ((,variable . ,value)))
                      variables))))
 
+      ;; Invalidate cache (may be needed if this .dir-locals.el file
+      ;; will be written with the same timestamp as is already present
+      ;; in the cache, see bug#13860).
+      (setq dir-locals-directory-cache
+            (assoc-delete-all (file-name-directory variables-file)
+                              dir-locals-directory-cache))
+
       ;; Insert modified alist of directory-local variables.
       (insert ";;; Directory Local Variables\n")
       (insert ";;; For more information see (info \"(emacs) Directory 
Variables\")\n\n")


Regards,

/Johan





On Wed, Aug 14 2019, Lars Ingebrigtsen wrote:
> Johan Claesson <johanclaesson@bredband.net> writes:
>
>> Maybe i have misunderstood something but i find the cache
>> mechanism for directory local variables unreliable in one rare
>> case.  If first .dir-locals.el is read and a binding say foo = 1 is
>> inserted in the dir-locals-directory-cache.  And then foo = 2 is
>> written in the same second.  Now next time the dir locals the old
>> binding foo = 1 will be returned.  The cache entry is considered
>> valid when it should not.  
>>
>> Of course it is unlikely that a user is typing so fast that they
>> trigger this :).  But it can be triggered from Lisp.  I found out
>> when playing with a ert test case that was tampering with a dir
>> local.  
>
> (I'm going through old bug reports that have unfortunately gotten no
> responses yet.)
>
>> Here is a recipe for this:
>>
>> (defvar foo nil)
>> (put 'foo 'safe-local-variable 'numberp)
>> (let ((dir (make-temp-file "cache-test" t)))
>>   ;; Create .dir-locals.el with foo = 1.
>>   (with-temp-buffer
>>     (cd dir)
>>     (add-dir-local-variable nil 'foo 1)
>>     (save-buffer)
>>     (kill-buffer))
>>   ;; Read it into dir-locals-directory-cache
>>   ;; and save .dir-locals.el with foo = 2.
>>   (with-temp-buffer
>>     (cd dir)
>>     (make-local-variable 'foo)
>>     (hack-dir-local-variables-non-file-buffer)
>>     (add-dir-local-variable nil 'foo 2)
>>     (save-buffer)
>>     (kill-buffer))
>>   ;; Read it back again.
>>   ;; It should be 2 at this point but is 1 most of the times. 
>>   ;; (At the rare occasion that seconds increase
>>   ;; between the two add-dir-local-variable it returns 1).
>>   (with-temp-buffer
>>     (cd dir)
>>     (make-local-variable 'foo)
>>     (hack-dir-local-variables-non-file-buffer)
>>     (delete-file dir-locals-file)
>>     (delete-directory dir) 
>>     foo))
>
> I'm unable to reproduce this problem in Emacs 27, but perhaps this could
> be a problem if the file system doesn't have sub-second resolution?  Are
> there such file systems still in use (I mean, for something where'd you
> store file with file-local variables)?





reply via email to

[Prev in Thread] Current Thread [Next in Thread]