Check for buffer liveness when accessing tree-sitter node (bug#71012)
authorYuan Fu <casouri@gmail.com>
Sat, 1 Jun 2024 17:20:48 +0000 (10:20 -0700)
committerYuan Fu <casouri@gmail.com>
Sat, 1 Jun 2024 17:29:55 +0000 (10:29 -0700)
* src/treesit.h (treesit_node_buffer_live_p): Declare function.
* src/print.c (print_vectorlike): Print node without position if
buffer is killed.
* src/treesit.c (treesit_node_buffer_live_p): New function.
(treesit_check_node): Add buffer liveness check.
(syms_of_treesit): New error treesit-node-buffer-killed.

src/print.c
src/treesit.c
src/treesit.h

index d52d98ad371bd047313ba22e290a90afef764574..8ee5a3616eb302d2fda928cde51848400b6f8a68 100644 (file)
@@ -2029,6 +2029,11 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag,
          print_c_string ("-outdated>", printcharfun);
          break;
        }
+      if (!treesit_node_buffer_live_p (obj))
+       {
+         print_c_string ("-in-killed-buffer>", printcharfun);
+         break;
+       }
       printchar (' ', printcharfun);
       /* Now the node must be up-to-date, and calling functions like
         Ftreesit_node_start will not signal.  */
index 21c61a35e70a4bcb30097eb5cd6e24755e583856..45efa429f9a51f310051305952b0b6675995a8c4 100644 (file)
@@ -1786,6 +1786,13 @@ treesit_check_node (Lisp_Object obj)
   CHECK_TS_NODE (obj);
   if (!treesit_node_uptodate_p (obj))
     xsignal1 (Qtreesit_node_outdated, obj);
+
+  /* Technically a lot of node functions can work without the
+     associated buffer being alive, but I doubt there're any real
+     use-cases for that; OTOH putting the buffer-liveness check here is
+     simple, clean, and safe.  */
+  if (!treesit_node_buffer_live_p (obj))
+    xsignal1 (Qtreesit_node_buffer_killed, obj);
 }
 
 /* Checks that OBJ is a positive integer and it is within the visible
@@ -1806,6 +1813,14 @@ treesit_node_uptodate_p (Lisp_Object obj)
   return XTS_NODE (obj)->timestamp == XTS_PARSER (lisp_parser)->timestamp;
 }
 
+bool
+treesit_node_buffer_live_p (Lisp_Object obj)
+{
+  struct buffer *buffer
+    = XBUFFER (XTS_PARSER (XTS_NODE (obj)->parser)->buffer);
+  return BUFFER_LIVE_P (buffer);
+}
+
 DEFUN ("treesit-node-type",
        Ftreesit_node_type, Streesit_node_type, 1, 1, 0,
        doc: /* Return the NODE's type as a string.
@@ -3549,6 +3564,8 @@ syms_of_treesit (void)
          "treesit-load-language-error");
   DEFSYM (Qtreesit_node_outdated,
          "treesit-node-outdated");
+  DEFSYM (Qtreesit_node_buffer_killed,
+         "treesit-node-buffer-killed");
   DEFSYM (Quser_emacs_directory,
          "user-emacs-directory");
   DEFSYM (Qtreesit_parser_deleted, "treesit-parser-deleted");
@@ -3577,6 +3594,9 @@ syms_of_treesit (void)
   define_error (Qtreesit_node_outdated,
                "This node is outdated, please retrieve a new one",
                Qtreesit_error);
+  define_error (Qtreesit_node_buffer_killed,
+               "The buffer associated with this node is killed",
+               Qtreesit_error);
   define_error (Qtreesit_parser_deleted,
                "This parser is deleted and cannot be used",
                Qtreesit_error);
index f5c8c67395d458186baff05182873a283c314a55..dcb19648a37a9a363b169dcb1e3f9ab5ebd8e580 100644 (file)
@@ -189,6 +189,7 @@ extern Lisp_Object make_treesit_parser (Lisp_Object, TSParser *, TSTree *,
 extern Lisp_Object make_treesit_node (Lisp_Object, TSNode);
 
 extern bool treesit_node_uptodate_p (Lisp_Object);
+extern bool treesit_node_buffer_live_p (Lisp_Object);
 
 extern void treesit_delete_parser (struct Lisp_TS_Parser *);
 extern void treesit_delete_query (struct Lisp_TS_Query *);