From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Philipp Stephani Newsgroups: gmane.emacs.devel Subject: [PATCH] Protect against an infloop in python-mode Date: Tue, 28 Feb 2017 22:31:49 +0100 Message-ID: <20170228213149.15842-1-phst@google.com> NNTP-Posting-Host: blaine.gmane.org X-Trace: blaine.gmane.org 1488318158 14995 195.159.176.226 (28 Feb 2017 21:42:38 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Tue, 28 Feb 2017 21:42:38 +0000 (UTC) Cc: Philipp Stephani To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Feb 28 22:42:31 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1cipXP-0002yh-P1 for ged-emacs-devel@m.gmane.org; Tue, 28 Feb 2017 22:42:27 +0100 Original-Received: from localhost ([::1]:37122 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cipXV-0003pB-CE for ged-emacs-devel@m.gmane.org; Tue, 28 Feb 2017 16:42:33 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:38023) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cipNR-00035t-GD for emacs-devel@gnu.org; Tue, 28 Feb 2017 16:32:10 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cipNO-0002Re-Cw for emacs-devel@gnu.org; Tue, 28 Feb 2017 16:32:09 -0500 Original-Received: from mail-wm0-x243.google.com ([2a00:1450:400c:c09::243]:34001) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cipNO-0002RW-5T for emacs-devel@gnu.org; Tue, 28 Feb 2017 16:32:06 -0500 Original-Received: by mail-wm0-x243.google.com with SMTP id m70so4379429wma.1 for ; Tue, 28 Feb 2017 13:32:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=VfGBXpWAL2OYfYFWXFL2Ty4mcYcxsAkw3anfJM+E/pI=; b=avHVb70udzn5pA3+ITKrFUSqCraTsDGwMZv/+l0ba5QJ/dOrV0//eva80lLnBFfHRu mtagdmRk64EhApOnKnIIrHaAZib15HsaQ7N3oxpknEKajmomoysSIRi4xHw0KrWP7w7m Z2+U8i6h51O7tob9cEWh9HlHr8HSX2JesuxgaJ7P9yFPd+KjvEdhfXgVmofeOqF+EVZ1 Hox839Ka8azsRLGcs9FsA2E238e2cRZCikqE1jYgofgybWSBwpVmT0nEiyOkqCYB1jEB VFQMWoAIvWSUBuwTTphYDwIsosihH2fGUHs7cGqQ8H+SA2jTzLjt5kywc+6FW2C/S0/Z hVEw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=VfGBXpWAL2OYfYFWXFL2Ty4mcYcxsAkw3anfJM+E/pI=; b=E+LqDRX0FUCGBhFKNytajfsxLSBV8oIeh7zitW2RvsxENl1bPipz2YjgzDByGbdV4t wb7nDadgdCaV47W0pvbY9rFvylBZrvZTefeMiWesV9KjikF+rp+QYeENqTD13On7rGNQ gTYLTUFA8l1CtWsC814FS4Ys44nsW6XPghMmVRo/UyFEH5swKwO2HH+Mri+9dSTR3WFM QCpLMlAOCBV7tluEooiXV1WcPvXRJP0FikQPv9tIfpwN9EhAEOpJNReDCX3zAGzZEetL IDIVSc9ukQlknI1mzccNM68/m8ZnB+T0JJPLedzqcwaA4BJkSeGRDbChfVKKU2dDZUCH n14Q== X-Gm-Message-State: AMke39nUcxwp4oIxud2PCk+PU+Gzksdq4U8paPo3e0PfW65gcvciQeq9rY9Hopqpy/dGgQ== X-Received: by 10.28.92.83 with SMTP id q80mr561778wmb.108.1488317524996; Tue, 28 Feb 2017 13:32:04 -0800 (PST) Original-Received: from p.cm.cablesurf.de (46.128.198.151.dynamic.cablesurf.de. [46.128.198.151]) by smtp.gmail.com with ESMTPSA id k195sm4246524wmd.7.2017.02.28.13.32.03 (version=TLS1 cipher=AES128-SHA bits=128/128); Tue, 28 Feb 2017 13:32:04 -0800 (PST) X-Google-Original-From: Philipp Stephani X-Mailer: git-send-email 2.11.1 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::243 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:212666 Archived-At: 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. --- lisp/progmodes/python.el | 16 +++++++++++++--- test/lisp/progmodes/python-tests.el | 17 +++++++++++++++++ 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 90b5e4e0dc..71f4298fa5 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -1491,10 +1491,18 @@ python-nav-end-of-statement 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 @@ python-nav-end-of-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. diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 1e6b867d30..893efca0a0 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -5314,6 +5314,23 @@ python-tests-shell-interpreter (or enabled (hs-minor-mode -1))))) +(ert-deftest python-tests--python-nav-end-of-statement--infloop () + "Checks that `python-nav-end-of-statement' doesn't infloop in a +buffer with overlapping strings." + (python-tests-with-temp-buffer "''' '\n''' ' '\n" + (syntax-propertize (point-max)) + ;; Create a situation where strings nominally overlap. This + ;; shouldn't happen in practice, but apparently it can happen when + ;; a package calls `syntax-ppss' in a narrowed buffer during JIT + ;; lock. + (put-text-property 4 5 'syntax-table (string-to-syntax "|")) + (remove-text-properties 8 9 '(syntax-table nil)) + (goto-char 4) + (setq-local syntax-propertize-function nil) + ;; The next form should not infloop. + (should-error (python-nav-end-of-statement)) + (should (eolp)))) + (provide 'python-tests) -- 2.11.1