[pypy-commit] pypy py3.7: way too much work: forbid "% %" % () and variants

cfbolz pypy.commits at gmail.com
Wed Jan 29 15:47:24 EST 2020


Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: py3.7
Changeset: r98598:a512d2966a9a
Date: 2020-01-29 21:46 +0100
http://bitbucket.org/pypy/pypy/changeset/a512d2966a9a/

Log:	way too much work: forbid "% %" % () and variants

diff --git a/pypy/objspace/std/formatting.py b/pypy/objspace/std/formatting.py
--- a/pypy/objspace/std/formatting.py
+++ b/pypy/objspace/std/formatting.py
@@ -297,12 +297,20 @@
                 result.append_slice(fmt, i0, i)
                 self.fmtpos = i + 1
 
+                c = self.peekchr()
+                if c == '%':
+                    self.forward()
+                    self.result.append('%')
+                    continue
+
                 # interpret the next formatter
                 w_value = self.parse_fmt()
                 c = self.peekchr()
                 self.forward()
                 if c == '%':
-                    self.result.append('%')
+                    # if we get here there were extra characters between the
+                    # two %, forbidden now
+                    self.two_percent_error(i + 1)
                     continue
 
                 # first check whether it's a invalid char, *then* call
@@ -329,17 +337,29 @@
             self.checkconsumed()
             return result.build()
 
-        def unknown_fmtchar(self):
+        def _get_error_info(self, pos):
             space = self.space
             if do_unicode:
-                cp = rutf8.codepoint_at_pos(self.fmt, self.fmtpos - 1)
-                pos = rutf8.codepoints_in_utf8(self.fmt, 0, self.fmtpos - 1)
+                cp = rutf8.codepoint_at_pos(self.fmt, pos)
+                pos = rutf8.codepoints_in_utf8(self.fmt, 0, pos)
                 w_s = space.newutf8(rutf8.unichr_as_utf8(r_uint(cp),
                                                   allow_surrogates=True), 1)
             else:
-                cp = ord(self.fmt[self.fmtpos - 1])
-                pos = self.fmtpos - 1
+                cp = ord(self.fmt[pos])
                 w_s = space.newbytes(chr(cp))
+            return w_s, pos, cp
+
+        def two_percent_error(self, pos):
+            space = self.space
+            w_s, pos, cp = self._get_error_info(pos)
+            raise oefmt(space.w_ValueError,
+                        # hahahaha
+                        "extra character %R (%s) before escaped '%%' at index %d, use '%%%%'",
+                        w_s, hex(cp), pos)
+
+        def unknown_fmtchar(self):
+            space = self.space
+            w_s, pos, cp = self._get_error_info(self.fmtpos - 1)
             raise oefmt(space.w_ValueError,
                         "unsupported format character %R (%s) at index %d",
                         w_s, hex(cp), pos)
diff --git a/pypy/objspace/std/test/test_stringformat.py b/pypy/objspace/std/test/test_stringformat.py
--- a/pypy/objspace/std/test/test_stringformat.py
+++ b/pypy/objspace/std/test/test_stringformat.py
@@ -278,6 +278,11 @@
         with raises(ValueError):
             "%?" % {} # not TypeError
 
+    def test_no_chars_between_percent(self):
+        with raises(ValueError) as exc:
+            "%   %" % ()
+        assert "extra character ' ' (0x20) before escaped '%' at index 1" in str(exc.value)
+
 class AppTestWidthPrec:
     def test_width(self):
         a = 'a'


More information about the pypy-commit mailing list