org-persist: Fix cached data being modified by reference

* lisp/org-persist.el (org-persist--write-cache):
* lisp/org-persist.el (org-persist-read):
(org-persist-write): Remove `org-persist--write-cache'.  The values,
after reading, might sometimes be modified in place.  The
modifications, when done inside some kind of deeply nested structure,
will propagate to the cache, polluting what was originally written in
the persist file.

This was a difficult bug to spot - the modification hapenned when an
Org buffer was saved to a different file (C-x C-w), modified, leading
to `org-element--cache' modification, and then closed.  This
modification propagated to `org-persist--write-cache', leading to
incorrect cache value being assigned to the original buffer (before
C-x C-w).

Reported-by: Gregor Zattler <telegraph@gmx.net>
This commit is contained in:
Ihor Radchenko 2024-10-07 20:35:12 +02:00
parent d33940f6e2
commit eb6d70f817
No known key found for this signature in database
GPG Key ID: 6470762A7DA11D8B
1 changed files with 1 additions and 7 deletions

View File

@ -1006,10 +1006,6 @@ the CONTAINER as well."
(remove container (plist-get collection :container)))
(org-persist--add-to-index collection))))))
(defvar org-persist--write-cache (make-hash-table :test #'equal)
"Hash table storing as-written data objects.
This data is used to avoid reading the data multiple times.")
(cl-defun org-persist-read (container &optional associated hash-must-match load &key read-related)
"Restore CONTAINER data for ASSOCIATED.
When HASH-MUST-MATCH is non-nil, do not restore data if hash for
@ -1057,8 +1053,7 @@ CONTAINER as well. For example:
(unless (seq-find (lambda (v)
(run-hook-with-args-until-success 'org-persist-before-read-hook v associated))
(plist-get collection :container))
(setq data (or (gethash persist-file org-persist--write-cache)
(org-persist--read-elisp-file persist-file)))
(setq data (org-persist--read-elisp-file persist-file))
(when data
(cl-loop for c in (plist-get collection :container)
with result = nil
@ -1129,7 +1124,6 @@ When IGNORE-RETURN is non-nil, just return t on success without calling
(let ((file (org-file-name-concat org-persist-directory (plist-get collection :persist-file)))
(data (mapcar (lambda (c) (cons c (org-persist-write:generic c collection)))
(plist-get collection :container))))
(puthash file data org-persist--write-cache)
(org-persist--write-elisp-file file data)
(or ignore-return (org-persist-read container associated)))))))