Protect against an infloop in python-mode
There appears to be an edge case caused by using `syntax-ppss' in a narrowed buffer during JIT lock inside of Python triple-quote strings. Unfortunately it is impossible to reproduce without manually destroying the syntactic information in the Python buffer, but it has been observed in practice. In that case it can happen that the syntax caches get sufficiently out of whack so that there appear to be overlapping strings in the buffer. As Python has no nested strings, this situation is impossible and leads to an infloop in `python-nav-end-of-statement'. Protect against this by checking whether the search for the end of the current string makes progress. * python.el (python-nav-end-of-statement): Protect against infloop. * progmodes/python-tests.el (python-tests--python-nav-end-of-statement--infloop): Add unit test.
This commit is contained in:
parent
aa0fb4fed8
commit
4fbd330fae
2 changed files with 32 additions and 3 deletions
|
@ -1491,10 +1491,18 @@ Optional argument NOEND is internal and makes the logic to not
|
|||
jump to the end of line when moving forward searching for the end
|
||||
of the statement."
|
||||
(interactive "^")
|
||||
(let (string-start bs-pos)
|
||||
(let (string-start bs-pos (last-string-end 0))
|
||||
(while (and (or noend (goto-char (line-end-position)))
|
||||
(not (eobp))
|
||||
(cond ((setq string-start (python-syntax-context 'string))
|
||||
;; The assertion can only fail if syntax table
|
||||
;; text properties and the `syntax-ppss' cache
|
||||
;; are somehow out of whack. This has been
|
||||
;; observed when using `syntax-ppss' during
|
||||
;; narrowing.
|
||||
(cl-assert (> string-start last-string-end)
|
||||
:show-args
|
||||
"Overlapping strings detected")
|
||||
(goto-char string-start)
|
||||
(if (python-syntax-context 'paren)
|
||||
;; Ended up inside a paren, roll again.
|
||||
|
@ -1504,8 +1512,10 @@ of the statement."
|
|||
(goto-char (+ (point)
|
||||
(python-syntax-count-quotes
|
||||
(char-after (point)) (point))))
|
||||
(or (re-search-forward (rx (syntax string-delimiter)) nil t)
|
||||
(goto-char (point-max)))))
|
||||
(setq last-string-end
|
||||
(or (re-search-forward
|
||||
(rx (syntax string-delimiter)) nil t)
|
||||
(goto-char (point-max))))))
|
||||
((python-syntax-context 'paren)
|
||||
;; The statement won't end before we've escaped
|
||||
;; at least one level of parenthesis.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue