Merge from origin/emacs-29

53e9caa23e ; * doc/emacs/help.texi (Help, Apropos): Improve text and...
00360258ca Fix treesit-parse-string crash (bug#71012)
20af58d3a1 Check for buffer liveness when accessing tree-sitter node...
This commit is contained in:
Eli Zaretskii 2024-06-08 07:34:20 -04:00
commit 35e65a84eb
5 changed files with 47 additions and 11 deletions

View file

@ -45,22 +45,27 @@ window displaying the @samp{*Help*} buffer will be reused instead.
@cindex searching documentation efficiently
@cindex looking for a subject in documentation
If you are looking for a certain feature, but don't know what it is
called or where to look, we recommend three methods. First, try an
apropos command, then try searching the manual index, then look in the
called or where to look, we recommend three methods. First, try
apropos commands, then try searching the manual index, then look in the
FAQ and the package keywords, and finally try listing external packages.
@table @kbd
@item C-h a @var{topics} @key{RET}
This searches for commands whose names match the argument
@var{topics}. The argument can be a keyword, a list of keywords, or a
regular expression (@pxref{Regexps}). @xref{Apropos}.
@var{topics}. The argument can be a keyword, a list of keywords
separated by whitespace, or a regular expression (@pxref{Regexps}).
@xref{Apropos}.
@item C-h i d m emacs @key{RET} i @var{topic} @key{RET}
@item C-h d @var{topics} @key{RET}
Similar, but searches the @emph{text} of the documentation strings
rather than the names of commands and functions.
@item C-h r i @var{topic} @key{RET}
This searches for @var{topic} in the indices of the Emacs Info manual,
displaying the first match found. Press @kbd{,} to see subsequent
matches. You can use a regular expression as @var{topic}.
@item C-h i d m emacs @key{RET} s @var{topic} @key{RET}
@item C-h r s @var{topic} @key{RET}
Similar, but searches the @emph{text} of the manual rather than the
indices.
@ -384,10 +389,12 @@ are included varies depending on the command used.
@section Apropos
@cindex apropos
@cindex apropos pattern
@cindex apropos commands, list of keywords
The @dfn{apropos} commands answer questions like, ``What are the
commands for working with files?'' More precisely, you specify your
query as an @dfn{apropos pattern}, which is either a word, a list of
words, or a regular expression.
words separated by whitespace, or a regular expression.
Each of the following apropos commands reads an apropos pattern in
the minibuffer, searches for items that match the pattern, and

View file

@ -126,10 +126,13 @@ of max unsigned 32-bit value for byte offsets into buffer text."
(defun treesit-parse-string (string language)
"Parse STRING using a parser for LANGUAGE.
Return the root node of the syntax tree."
(with-temp-buffer
(insert string)
(treesit-parser-root-node
(treesit-parser-create language))))
;; We can't use `with-temp-buffer' because it kills the buffer when
;; returning from the form.
(let ((buf (generate-new-buffer " *treesit-parse-string*")))
(with-current-buffer buf
(insert string)
(treesit-parser-root-node
(treesit-parser-create language)))))
(defvar-local treesit-language-at-point-function nil
"A function that returns the language at point.

View file

@ -2033,6 +2033,11 @@ print_vectorlike_unreadable (Lisp_Object obj, Lisp_Object printcharfun,
print_c_string ("-outdated>", printcharfun);
return;
}
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. */

View file

@ -1837,6 +1837,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
@ -1857,6 +1864,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.
@ -4016,6 +4031,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");
@ -4046,6 +4063,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);

View file

@ -194,6 +194,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 *);