branch: externals/org
commit 4a38e4d4ccbee2f79b7c160d955b02de3f92067f
Author: Ihor Radchenko <[email protected]>
Commit: Ihor Radchenko <[email protected]>
org-element-plain-list-parser: Add diagnostics to catch cache bug
* lisp/org-element.el (org-element-plain-list-parser): Detect, report,
and recover from STRUCTURE passed being invalid. It is not clear what
the origin of this bug is. Hopefully catching it early can provide
more insights.
(org-element--cache-diagnostics-level):
(org-element--cache-diagnostics-ring):
(org-element--cache-diagnostics-ring-size):
(org-element--cache-self-verify):
(org-element--cache-warn): Move definitions before they are being used.
Reported-by: Jason Terk <[email protected]>
Link:
https://orgmode.org/list/cakcq1cidotw7nig4hs7pc0tho-f3lvnogf3+tt2tcu8yk5e...@mail.gmail.com
---
lisp/org-element.el | 92 +++++++++++++++++++++++++++++------------------------
1 file changed, 50 insertions(+), 42 deletions(-)
diff --git a/lisp/org-element.el b/lisp/org-element.el
index 8afd67df9a..10e29e1baf 100644
--- a/lisp/org-element.el
+++ b/lisp/org-element.el
@@ -853,6 +853,48 @@ and END-OFFSET."
(org-unescape-code-in-string
(org-element--substring element beg-offset end-offset)))
+(defvar org-element--cache-diagnostics-level 2
+ "Detail level of the diagnostics.")
+
+(defvar-local org-element--cache-diagnostics-ring nil
+ "Ring containing cache process log entries.
+The ring size is `org-element--cache-diagnostics-ring-size'.")
+
+(defvar org-element--cache-diagnostics-ring-size 5000
+ "Size of `org-element--cache-diagnostics-ring'.")
+
+(defvar org-element--cache-self-verify nil
+ "Activate extra consistency checks for the cache.
+
+This may cause serious performance degradation depending on the value
+of `org-element--cache-self-verify-frequency'.
+
+When set to symbol `backtrace', record and display backtrace log if
+any inconsistency is detected.")
+
+(defmacro org-element--cache-warn (format-string &rest args)
+ "Raise warning for org-element-cache.
+FORMAT-STRING and ARGS are the same arguments as in `format'."
+ `(let* ((format-string (funcall #'format ,format-string ,@args))
+ (format-string
+ (if (or (not org-element--cache-diagnostics-ring)
+ (not (eq 'backtrace org-element--cache-self-verify)))
+ format-string
+ (prog1
+ (concat (format "Warning(%s): "
+ (buffer-name (current-buffer)))
+ format-string
+ "\nBacktrace:\n "
+ (mapconcat #'identity
+ (ring-elements
org-element--cache-diagnostics-ring)
+ "\n "))
+ (setq org-element--cache-diagnostics-ring nil)))))
+ (if (and (boundp 'org-batch-test) org-batch-test)
+ (error "%s" (concat "org-element--cache: " format-string))
+ (push (concat "org-element--cache: " format-string) org--warnings)
+ (display-warning '(org-element org-element-cache)
+ (concat "org-element--cache: " format-string)))))
+
;;; Greater elements
;;
@@ -1997,6 +2039,14 @@ Return a new syntax node of `plain-list' type containing
`:type',
`:post-blank' and `:post-affiliated' properties.
Assume point is at the beginning of the list."
+ (when (and structure (not (assq (point) structure)))
+ ;; STRUCT is corrupted - cannot find list inside.
+ (org-element--cache-warn
+ "Invalid :struct passed to plain-list parser at %S: %S
+If this warning appears regularly, please report the warning text to Org mode
mailing list (M-x org-submit-bug-report)."
+ (point) structure)
+ ;; Try to recover
+ (setq structure nil))
(save-excursion
(let* ((struct (or structure (org-element--list-struct limit)))
(type (cond ((looking-at-p "[ \t]*[A-Za-z0-9]") 'ordered)
@@ -5805,15 +5855,6 @@ seconds.")
"Duration, as a time value, of the pause between synchronizations.
See `org-element-cache-sync-duration' for more information.")
-(defvar org-element--cache-self-verify nil
- "Activate extra consistency checks for the cache.
-
-This may cause serious performance degradation depending on the value
-of `org-element--cache-self-verify-frequency'.
-
-When set to symbol `backtrace', record and display backtrace log if
-any inconsistency is detected.")
-
(defvar org-element--cache-self-verify-before-persisting nil
"Perform consistency checks for the cache before writing to disk.
@@ -5836,16 +5877,6 @@ to be correct. Setting this to a value less than 0.0001
is useless.")
(defvar org-element--cache-map-statistics-threshold 0.1
"Time threshold in seconds to log statistics for `org-element-cache-map'.")
-(defvar org-element--cache-diagnostics-level 2
- "Detail level of the diagnostics.")
-
-(defvar-local org-element--cache-diagnostics-ring nil
- "Ring containing cache process log entries.
-The ring size is `org-element--cache-diagnostics-ring-size'.")
-
-(defvar org-element--cache-diagnostics-ring-size 5000
- "Size of `org-element--cache-diagnostics-ring'.")
-
;;;; Data Structure
(defvar-local org-element--cache nil
@@ -6008,29 +6039,6 @@ FORMAT-STRING and ARGS are the same arguments as in
`format'."
(make-ring org-element--cache-diagnostics-ring-size)))
(ring-insert org-element--cache-diagnostics-ring format-string)))))
-(defmacro org-element--cache-warn (format-string &rest args)
- "Raise warning for org-element-cache.
-FORMAT-STRING and ARGS are the same arguments as in `format'."
- `(let* ((format-string (funcall #'format ,format-string ,@args))
- (format-string
- (if (or (not org-element--cache-diagnostics-ring)
- (not (eq 'backtrace org-element--cache-self-verify)))
- format-string
- (prog1
- (concat (format "Warning(%s): "
- (buffer-name (current-buffer)))
- format-string
- "\nBacktrace:\n "
- (mapconcat #'identity
- (ring-elements
org-element--cache-diagnostics-ring)
- "\n "))
- (setq org-element--cache-diagnostics-ring nil)))))
- (if (and (boundp 'org-batch-test) org-batch-test)
- (error "%s" (concat "org-element--cache: " format-string))
- (push (concat "org-element--cache: " format-string) org--warnings)
- (display-warning '(org-element org-element-cache)
- (concat "org-element--cache: " format-string)))))
-
(defsubst org-element--cache-key (element)
"Return a unique key for ELEMENT in cache tree.