branch: externals/relint commit 41fad874a3968d5ae36fada9e4e4991f3f6ef39a Author: Mattias Engdegård <matti...@acm.org> Commit: Mattias Engdegård <matti...@acm.org>
Find more bad string escapes: \8, \9, \x without following hex digit "\x" is particularly pernicious since it unexpectedly yields a NUL; this bug has been in Emacs for a very long time. --- README | 51 +++++++++++++++++++++++++++++---------------------- relint.el | 14 +++++++++----- test/13.elisp | 4 ++++ test/13.expected | 4 ++++ 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/README b/README index 80500adc87..1db153a450 100644 --- a/README +++ b/README @@ -227,28 +227,6 @@ skip-syntax-forward and skip-syntax-backward. In general, A?, where A matches the empty string, can be simplified to just A. - - Ineffective string escape '\X' - - A backslash precedes a character that does not need escaping in a - string literal (any string, not just regexps), like in "hot\-dog". - - If the backslash should be part of the string then it probably - needs to be doubled; otherwise, it is pointless and should be - removed to avoid confusion. - - In Emacs versions older than 27.1, a left round or square bracket, - '(' or '[', at the very start of a line in a multi-line string - could sometimes fool the Emacs-Lisp mode into believing it to be - the start of a function, thus people sometimes precede such - brackets with an otherwise unnecessary backslash. However, there - is usually no reason to put backslashes before brackets in strings - in general. - - - Suspect range '+-X' or 'X-+' - - A character range with '+' as one of its endpoints is more often an - incorrect attempt to include both '+' and '-' in the set. - - Unnecessarily escaped 'X' A character is backslash-escaped in a skip set despite not being @@ -324,6 +302,35 @@ skip-syntax-forward and skip-syntax-backward. A string argument to skip-syntax-forward or skip-syntax-backward is empty or "^", neither of which makes sense. + - Ineffective string escape '\X' + + A backslash precedes a character that does not need escaping in a + string literal (any string, not just regexps), like in "hot\-dog". + + If the backslash should be part of the string then it probably + needs to be doubled; otherwise, it is pointless and should be + removed to avoid confusion. + + In Emacs versions older than 27.1, a left round or square bracket, + '(' or '[', at the very start of a line in a multi-line string + could sometimes fool the Emacs-Lisp mode into believing it to be + the start of a function, thus people sometimes precede such + brackets with an otherwise unnecessary backslash. However, there + is usually no reason to put backslashes before brackets in strings + in general. + + - Character escape '\x' not followed by hex digit + + In Emacs versions older than 30.1, a hex escape without any actual + hex digits, as in "\x", was silently accepted as a null byte which + is not what anyone would expect. If the backslash should be + included in the string, double it as usual. + + - Suspect range '+-X' or 'X-+' + + A character range with '+' as one of its endpoints is more often an + incorrect attempt to include both '+' and '-' in the set. + * Suppressing diagnostics diff --git a/relint.el b/relint.el index fe27c17ba8..51a02aa6ef 100644 --- a/relint.el +++ b/relint.el @@ -2303,9 +2303,12 @@ STRING-START is the start of the string literal (first double quote)." (and (memq c '(?\( ?\) ?\[ ?\] ?\')) (relint--in-doc-string-p string-start))) (relint--warn (point) nil - (format-message - "Ineffective string escape `\\%s'" - (relint--escape-string (char-to-string c) nil)))))) + (if (eq c ?x) + (format-message + "Character escape `\\x' not followed by hex digit") + (format-message + "Ineffective string escape `\\%s'" + (relint--escape-string (char-to-string c) nil))))))) (defun relint--check-for-misplaced-backslashes () "Check for misplaced backslashes in the current buffer." @@ -2322,10 +2325,11 @@ STRING-START is the start of the string literal (first double quote)." (forward-char) (while (not (memq (char-after) '(?\" nil))) (when (looking-at - (rx (1+ (or (seq ?\\ (any "0-9" "xuUN" "abfnrtv" + (rx (1+ (or (seq ?\\ (or (any "0-7" "uUN" "abfnrtv" "des" "^" " " ?\\ ?\n ?\" - "CM")) + "CM") + (seq "x" xdigit))) (not (any ?\\ ?\")))))) (goto-char (match-end 0))) (when (eq (following-char) ?\\) diff --git a/test/13.elisp b/test/13.elisp index 1f8cb5826f..d07f72fbd2 100644 --- a/test/13.elisp +++ b/test/13.elisp @@ -17,3 +17,7 @@ and \a \b \f \n \r \t \v \d \e \s \^P")) (defun f2 () (re-search-forward "\$\.x\+\+") '("bracketed \q string")) + +(defun f3 () + (print "a \7 \8 \9 b") + (print "c \xf \xg \x d")) diff --git a/test/13.expected b/test/13.expected index 53a4568aab..1bf32daa53 100644 --- a/test/13.expected +++ b/test/13.expected @@ -26,3 +26,7 @@ ....^ 13.elisp:18:30: Ineffective string escape `\+' 13.elisp:19:16: Ineffective string escape `\q' +13.elisp:22:16: Ineffective string escape `\8' +13.elisp:22:19: Ineffective string escape `\9' +13.elisp:23:17: Character escape `\x' not followed by hex digit +13.elisp:23:21: Character escape `\x' not followed by hex digit