]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-152847: Reject POSIX TZ rule with non-digit day-of-year in `_zoneinfo.py` (#152848)
authortonghuaroot (童话) <tonghuaroot@gmail.com>
Thu, 2 Jul 2026 18:04:53 +0000 (02:04 +0800)
committerGitHub <noreply@github.com>
Thu, 2 Jul 2026 18:04:53 +0000 (20:04 +0200)
Co-authored-by: Stan Ulbrych <stan@python.org>
Lib/test/test_zoneinfo/test_zoneinfo.py
Lib/zoneinfo/_zoneinfo.py
Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst [new file with mode: 0644]

index 813b56501308f9e0e37578560b5ffa3cba3cf9e8..a10f434eb27590d13011364dce3bcec64b3a5405 100644 (file)
@@ -1111,6 +1111,9 @@ class TZStrTest(ZoneInfoTestBase):
             "AAA4BBB,J1/2,J1/14",
             "AAA4BBB,J20/2,J365/2",
             "AAA4BBB,J365/2,J365/14",
+            # Leading-zero day-of-year
+            "AAA4BBB,J001/2,J065/2",
+            "AAA4BBB,001/2,065/2",
             # Extreme transition hour
             "AAA4BBB,J60/167,J300/2",
             "AAA4BBB,J60/+167,J300/2",
@@ -1209,6 +1212,15 @@ class TZStrTest(ZoneInfoTestBase):
             # Invalid julian offset
             "AAA4BBB,J0/2,J20/2",
             "AAA4BBB,J20/2,J366/2",
+            # gh-152847: non-digit day-of-year
+            "AAA4BBB,J1_0,J300/2",
+            "AAA4BBB,J60/2,J30_0/2",
+            "AAA4BBB,1_0,J300/2",
+            "AAA4BBB,J+1,J300/2",
+            "AAA4BBB,J 1,J300/2",
+            "AAA4BBB, 1,J300/2",
+            "AAA4BBB,J0001,J300/2",
+            "AAA4BBB,0001,J300/2",
             # Invalid transition time
             "AAA4BBB,J60/2/3,J300/2",
             "AAA4BBB,J60/2,J300/2/3",
@@ -1248,6 +1260,15 @@ class TZStrTest(ZoneInfoTestBase):
         with self.assertRaisesRegex(ValueError, expected):
             self.zone_from_tzstr(tzstr, encoding="utf-8")
 
+    def test_invalid_tzstr_non_ascii_dst_date(self):
+        tzstr = "AAA4BBB,J١,J300/2"
+        if self.module is py_zoneinfo:
+            expected = re.escape(tzstr)
+        else:
+            expected = re.escape(repr(tzstr.encode("utf-8")))
+        with self.assertRaisesRegex(ValueError, expected):
+            self.zone_from_tzstr(tzstr, encoding="utf-8")
+
     @classmethod
     def _populate_test_cases(cls):
         # This method uses a somewhat unusual style in that it populates the
index 90cf2bbf8f5d0d1bddfb3aa404449350fcc04d8b..48154775568b6dc050ec255f4ce811617356ba39 100644 (file)
@@ -720,6 +720,8 @@ def _parse_dst_start_end(dststr):
         else:
             n_is_julian = False
 
+        if re.fullmatch(r"\d{1,3}", date, re.ASCII) is None:
+            raise ValueError(f"Invalid dst start/end date: {dststr}")
         doy = int(date)
         offset = _DayOffset(doy, n_is_julian)
 
diff --git a/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst b/Misc/NEWS.d/next/Library/2026-07-02-12-00-00.gh-issue-152847.PitKqc.rst
new file mode 100644 (file)
index 0000000..3f20d78
--- /dev/null
@@ -0,0 +1,3 @@
+Reject a POSIX TZ transition rule with non-digit characters in the
+day-of-year field in the pure-Python :mod:`zoneinfo` parser. Patch by
+tonghuaroot.