Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 12 Jun 2026 05:58:53 +0000
From:      Charlie Li <vishwin@FreeBSD.org>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-branches@FreeBSD.org
Cc:        Matthias Andree <mandree@FreeBSD.org>
Subject:   git: 7bec71c4243b - 2026Q2 - lang/python314: Update to 3.14.5
Message-ID:  <6a2ba01d.436f2.101e95ee@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch 2026Q2 has been updated by vishwin:

URL: https://cgit.FreeBSD.org/ports/commit/?id=7bec71c4243bdec53bb63a38d561ad41b89e09de

commit 7bec71c4243bdec53bb63a38d561ad41b89e09de
Author:     Matthias Andree <mandree@FreeBSD.org>
AuthorDate: 2026-05-11 16:00:29 +0000
Commit:     Charlie Li <vishwin@FreeBSD.org>
CommitDate: 2026-06-12 05:53:18 +0000

    lang/python314: Update to 3.14.5
    
    This release swaps out the incremental garbage collector for the
    generational one used in 3.13 due to reports of memory pressure.
    
    Backport the post-release upstream fix for:
    Heap Buffer Overflow in pyexpat Character Data Buffering #148441
    which is believed to be only triggered in rare circumstances.
    
    Changelog: https://www.python.org/downloads/release/python-3145/
    
    PR:             295200
    MFH:            2026Q2
    (cherry picked from commit ecdfdb02e3cdae8b5d61d074175ee0424f90bd85)
---
 lang/python314/Makefile                            |   2 +-
 lang/python314/Makefile.version                    |   2 +-
 lang/python314/distinfo                            |   6 +-
 ...211-reject-CR_LF-in-HTTP-tunnel-request-headers | 108 ---------------------
 ...ix-quadratic-regex-backtracking-in-configparser |  83 ----------------
 ...action_substitution-bypass-of-dash-prefix-check |  66 -------------
 ...tch-gh-148395-fix-possible-uaf-in-decompressors |  65 -------------
 ...integer-overflow-in-Expats-CharacterDataHandler |  70 +++++++++++++
 lang/python314/pkg-plist                           |   7 +-
 9 files changed, 77 insertions(+), 332 deletions(-)

diff --git a/lang/python314/Makefile b/lang/python314/Makefile
index d3513d47ad73..55ea7849a9cf 100644
--- a/lang/python314/Makefile
+++ b/lang/python314/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=	python
 DISTVERSION=	${PYTHON_DISTVERSION}  # see Makefile.version
-PORTREVISION=	3
+PORTREVISION=	0
 CATEGORIES=	lang python
 MASTER_SITES=	PYTHON/ftp/python/${DISTVERSION:C/[a-z].*//}
 PKGNAMESUFFIX=	${PYTHON_SUFFIX}
diff --git a/lang/python314/Makefile.version b/lang/python314/Makefile.version
index c8ccfa3963b0..01917fa79e66 100644
--- a/lang/python314/Makefile.version
+++ b/lang/python314/Makefile.version
@@ -4,4 +4,4 @@
 # 1. Update python documentation (lang/python-doc-*)
 #    Run "make -C lang/python-doc-html makesum"
 # 2. Remove PORTREVISION in Makefile
-PYTHON_DISTVERSION=	3.14.4
+PYTHON_DISTVERSION=	3.14.5
diff --git a/lang/python314/distinfo b/lang/python314/distinfo
index 7c5dead58955..762b3cb841c8 100644
--- a/lang/python314/distinfo
+++ b/lang/python314/distinfo
@@ -1,3 +1,3 @@
-TIMESTAMP = 1775640582
-SHA256 (python/Python-3.14.4.tar.xz) = d923c51303e38e249136fc1bdf3568d56ecb03214efdef48516176d3d7faaef8
-SIZE (python/Python-3.14.4.tar.xz) = 23855332
+TIMESTAMP = 1778513616
+SHA256 (python/Python-3.14.5.tar.xz) = 7e32597b99e5d9a39abed35de4693fa169df3e5850d4c334337ffd6a19a36db6
+SIZE (python/Python-3.14.5.tar.xz) = 23903332
diff --git a/lang/python314/files/patch-gh-146211-reject-CR_LF-in-HTTP-tunnel-request-headers b/lang/python314/files/patch-gh-146211-reject-CR_LF-in-HTTP-tunnel-request-headers
deleted file mode 100644
index 989f22a0529b..000000000000
--- a/lang/python314/files/patch-gh-146211-reject-CR_LF-in-HTTP-tunnel-request-headers
+++ /dev/null
@@ -1,108 +0,0 @@
-From afdd351544e8112d4070a31f2218f99256697472 Mon Sep 17 00:00:00 2001
-From: Seth Larson <seth@python.org>
-Date: Fri, 10 Apr 2026 10:21:42 -0500
-Subject: [PATCH] gh-146211: Reject CR/LF in HTTP tunnel request headers
- (GH-146212) (cherry picked from commit
- 05ed7ce7ae9e17c23a04085b2539fe6d6d3cef69)
-
-Co-authored-by: Seth Larson <seth@python.org>
-Co-authored-by: Illia Volochii <illia.volochii@gmail.com>
----
- Lib/http/client.py                            | 11 ++++-
- Lib/test/test_httplib.py                      | 45 +++++++++++++++++++
- ...-03-20-09-29-42.gh-issue-146211.PQVbs7.rst |  2 +
- 3 files changed, 57 insertions(+), 1 deletion(-)
- create mode 100644 Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst
-
-diff --git a/Lib/http/client.py b/Lib/http/client.py
-index 77f8d26291dfc2..6fb7d254ea9c27 100644
---- ./Lib/http/client.py
-+++ b/Lib/http/client.py
-@@ -972,13 +972,22 @@ def _wrap_ipv6(self, ip):
-         return ip
- 
-     def _tunnel(self):
-+        if _contains_disallowed_url_pchar_re.search(self._tunnel_host):
-+            raise ValueError('Tunnel host can\'t contain control characters %r'
-+                             % (self._tunnel_host,))
-         connect = b"CONNECT %s:%d %s\r\n" % (
-             self._wrap_ipv6(self._tunnel_host.encode("idna")),
-             self._tunnel_port,
-             self._http_vsn_str.encode("ascii"))
-         headers = [connect]
-         for header, value in self._tunnel_headers.items():
--            headers.append(f"{header}: {value}\r\n".encode("latin-1"))
-+            header_bytes = header.encode("latin-1")
-+            value_bytes = value.encode("latin-1")
-+            if not _is_legal_header_name(header_bytes):
-+                raise ValueError('Invalid header name %r' % (header_bytes,))
-+            if _is_illegal_header_value(value_bytes):
-+                raise ValueError('Invalid header value %r' % (value_bytes,))
-+            headers.append(b"%s: %s\r\n" % (header_bytes, value_bytes))
-         headers.append(b"\r\n")
-         # Making a single send() call instead of one per line encourages
-         # the host OS to use a more optimal packet size instead of
-diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
-index bcb828edec7c39..6f3eac6b98a4de 100644
---- ./Lib/test/test_httplib.py
-+++ b/Lib/test/test_httplib.py
-@@ -369,6 +369,51 @@ def test_invalid_headers(self):
-                 with self.assertRaisesRegex(ValueError, 'Invalid header'):
-                     conn.putheader(name, value)
- 
-+    def test_invalid_tunnel_headers(self):
-+        cases = (
-+            ('Invalid\r\nName', 'ValidValue'),
-+            ('Invalid\rName', 'ValidValue'),
-+            ('Invalid\nName', 'ValidValue'),
-+            ('\r\nInvalidName', 'ValidValue'),
-+            ('\rInvalidName', 'ValidValue'),
-+            ('\nInvalidName', 'ValidValue'),
-+            (' InvalidName', 'ValidValue'),
-+            ('\tInvalidName', 'ValidValue'),
-+            ('Invalid:Name', 'ValidValue'),
-+            (':InvalidName', 'ValidValue'),
-+            ('ValidName', 'Invalid\r\nValue'),
-+            ('ValidName', 'Invalid\rValue'),
-+            ('ValidName', 'Invalid\nValue'),
-+            ('ValidName', 'InvalidValue\r\n'),
-+            ('ValidName', 'InvalidValue\r'),
-+            ('ValidName', 'InvalidValue\n'),
-+        )
-+        for name, value in cases:
-+            with self.subTest((name, value)):
-+                conn = client.HTTPConnection('example.com')
-+                conn.set_tunnel('tunnel', headers={
-+                    name: value
-+                })
-+                conn.sock = FakeSocket('')
-+                with self.assertRaisesRegex(ValueError, 'Invalid header'):
-+                    conn._tunnel()  # Called in .connect()
-+
-+    def test_invalid_tunnel_host(self):
-+        cases = (
-+            'invalid\r.host',
-+            '\ninvalid.host',
-+            'invalid.host\r\n',
-+            'invalid.host\x00',
-+            'invalid host',
-+        )
-+        for tunnel_host in cases:
-+            with self.subTest(tunnel_host):
-+                conn = client.HTTPConnection('example.com')
-+                conn.set_tunnel(tunnel_host)
-+                conn.sock = FakeSocket('')
-+                with self.assertRaisesRegex(ValueError, 'Tunnel host can\'t contain control characters'):
-+                    conn._tunnel()  # Called in .connect()
-+
-     def test_headers_debuglevel(self):
-         body = (
-             b'HTTP/1.1 200 OK\r\n'
-diff --git a/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst b/Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst
-new file mode 100644
-index 00000000000000..4993633b8ebebb
---- /dev/null
-+++ ./Misc/NEWS.d/next/Security/2026-03-20-09-29-42.gh-issue-146211.PQVbs7.rst
-@@ -0,0 +1,2 @@
-+Reject CR/LF characters in tunnel request headers for the
-+HTTPConnection.set_tunnel() method.
diff --git a/lang/python314/files/patch-gh-146333-Fix-quadratic-regex-backtracking-in-configparser b/lang/python314/files/patch-gh-146333-Fix-quadratic-regex-backtracking-in-configparser
deleted file mode 100644
index 7dffa8ff1cfe..000000000000
--- a/lang/python314/files/patch-gh-146333-Fix-quadratic-regex-backtracking-in-configparser
+++ /dev/null
@@ -1,83 +0,0 @@
-From ab8704a8e05e2f926c10f994e4085e8726048fa4 Mon Sep 17 00:00:00 2001
-From: Joshua Swanson <22283299+joshuaswanson@users.noreply.github.com>
-Date: Tue, 7 Apr 2026 16:10:34 +0200
-Subject: [PATCH] gh-146333: Fix quadratic regex backtracking in configparser
- option parsing (GH-146399)
-
-Use negative lookahead in option regex to prevent backtracking, and to avoid changing logic outside the regexes (since people could use the regex directly).
-(cherry picked from commit 7e0a0be4097f9d29d66fe23f5af86f18a34ed7dd)
-
-Co-authored-by: Joshua Swanson <22283299+joshuaswanson@users.noreply.github.com>
----
- Lib/configparser.py                           |  8 ++++++--
- Lib/test/test_configparser.py                 | 20 +++++++++++++++++++
- ...3-25-00-51-03.gh-issue-146333.LqdL__bn.rst |  3 +++
- 3 files changed, 29 insertions(+), 2 deletions(-)
- create mode 100644 Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst
-
-diff --git a/Lib/configparser.py b/Lib/configparser.py
-index d435a5c2fe0da2..e76647d339e913 100644
---- ./Lib/configparser.py
-+++ b/Lib/configparser.py
-@@ -613,7 +613,9 @@ class RawConfigParser(MutableMapping):
-         \]                                 # ]
-         """
-     _OPT_TMPL = r"""
--        (?P<option>.*?)                    # very permissive!
-+        (?P<option>                        # very permissive!
-+            (?:(?!{delim})\S)*             # non-delimiter non-whitespace
-+            (?:\s+(?:(?!{delim})\S)+)*)    # optionally more words
-         \s*(?P<vi>{delim})\s*              # any number of space/tab,
-                                            # followed by any of the
-                                            # allowed delimiters,
-@@ -621,7 +623,9 @@ class RawConfigParser(MutableMapping):
-         (?P<value>.*)$                     # everything up to eol
-         """
-     _OPT_NV_TMPL = r"""
--        (?P<option>.*?)                    # very permissive!
-+        (?P<option>                        # very permissive!
-+            (?:(?!{delim})\S)*             # non-delimiter non-whitespace
-+            (?:\s+(?:(?!{delim})\S)+)*)    # optionally more words
-         \s*(?:                             # any number of space/tab,
-         (?P<vi>{delim})\s*                 # optionally followed by
-                                            # any of the allowed
-diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py
-index 1bfb53ccbb1398..d7c4f19c1a5ef0 100644
---- ./Lib/test/test_configparser.py
-+++ b/Lib/test/test_configparser.py
-@@ -2270,6 +2270,26 @@ def test_section_bracket_in_key(self):
-         output.close()
- 
- 
-+class ReDoSTestCase(unittest.TestCase):
-+    """Regression tests for quadratic regex backtracking (gh-146333)."""
-+
-+    def test_option_regex_does_not_backtrack(self):
-+        # A line with many spaces between non-delimiter characters
-+        # should be parsed in linear time, not quadratic.
-+        parser = configparser.RawConfigParser()
-+        content = "[section]\n" + "x" + " " * 40000 + "y" + "\n"
-+        # This should complete almost instantly. Before the fix,
-+        # it would take over a minute due to catastrophic backtracking.
-+        with self.assertRaises(configparser.ParsingError):
-+            parser.read_string(content)
-+
-+    def test_option_regex_no_value_does_not_backtrack(self):
-+        parser = configparser.RawConfigParser(allow_no_value=True)
-+        content = "[section]\n" + "x" + " " * 40000 + "y" + "\n"
-+        parser.read_string(content)
-+        self.assertTrue(parser.has_option("section", "x" + " " * 40000 + "y"))
-+
-+
- class MiscTestCase(unittest.TestCase):
-     def test__all__(self):
-         support.check__all__(self, configparser, not_exported={"Error"})
-diff --git a/Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst b/Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst
-new file mode 100644
-index 00000000000000..96d86ecc0a0fb3
---- /dev/null
-+++ ./Misc/NEWS.d/next/Security/2026-03-25-00-51-03.gh-issue-146333.LqdL__bn.rst
-@@ -0,0 +1,3 @@
-+Fix quadratic backtracking in :class:`configparser.RawConfigParser` option
-+parsing regexes (``OPTCRE`` and ``OPTCRE_NV``). A crafted configuration line
-+with many whitespace characters could cause excessive CPU usage.
diff --git a/lang/python314/files/patch-gh-148169-fix-webbrowser-_action_substitution-bypass-of-dash-prefix-check b/lang/python314/files/patch-gh-148169-fix-webbrowser-_action_substitution-bypass-of-dash-prefix-check
deleted file mode 100644
index 5407326b750a..000000000000
--- a/lang/python314/files/patch-gh-148169-fix-webbrowser-_action_substitution-bypass-of-dash-prefix-check
+++ /dev/null
@@ -1,66 +0,0 @@
-From f529b9470752c28ab69c96f31b0dbc10db69b404 Mon Sep 17 00:00:00 2001
-From: Stan Ulbrych <stan@python.org>
-Date: Mon, 13 Apr 2026 20:02:52 +0100
-Subject: [PATCH] gh-148169: Fix webbrowser `%action` substitution bypass of
- dash-prefix check (GH-148170) (cherry picked from commit
- d22922c8a7958353689dc4763dd72da2dea03fff)
-
-Co-authored-by: Stan Ulbrych <stan@python.org>
----
- Lib/test/test_webbrowser.py                              | 9 +++++++++
- Lib/webbrowser.py                                        | 5 +++--
- .../2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst       | 2 ++
- 3 files changed, 14 insertions(+), 2 deletions(-)
- create mode 100644 Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst
-
-diff --git a/Lib/test/test_webbrowser.py b/Lib/test/test_webbrowser.py
-index 404b3a31a5d2c9..bfbcf112b0b085 100644
---- ./Lib/test/test_webbrowser.py
-+++ b/Lib/test/test_webbrowser.py
-@@ -119,6 +119,15 @@ def test_open_bad_new_parameter(self):
-                        arguments=[URL],
-                        kw=dict(new=999))
- 
-+    def test_reject_action_dash_prefixes(self):
-+        browser = self.browser_class(name=CMD_NAME)
-+        with self.assertRaises(ValueError):
-+            browser.open('%action--incognito')
-+        # new=1: action is "--new-window", so "%action" itself expands to
-+        # a dash-prefixed flag even with no dash in the original URL.
-+        with self.assertRaises(ValueError):
-+            browser.open('%action', new=1)
-+
- 
- class EdgeCommandTest(CommandTestMixin, unittest.TestCase):
- 
-diff --git a/Lib/webbrowser.py b/Lib/webbrowser.py
-index 0e0b5034e5f53d..97aad6eea509eb 100644
---- ./Lib/webbrowser.py
-+++ b/Lib/webbrowser.py
-@@ -274,7 +274,6 @@ def _invoke(self, args, remote, autoraise, url=None):
- 
-     def open(self, url, new=0, autoraise=True):
-         sys.audit("webbrowser.open", url)
--        self._check_url(url)
-         if new == 0:
-             action = self.remote_action
-         elif new == 1:
-@@ -288,7 +287,9 @@ def open(self, url, new=0, autoraise=True):
-             raise Error("Bad 'new' parameter to open(); "
-                         f"expected 0, 1, or 2, got {new}")
- 
--        args = [arg.replace("%s", url).replace("%action", action)
-+        self._check_url(url.replace("%action", action))
-+
-+        args = [arg.replace("%action", action).replace("%s", url)
-                 for arg in self.remote_args]
-         args = [arg for arg in args if arg]
-         success = self._invoke(args, True, autoraise, url)
-diff --git a/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst b/Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst
-new file mode 100644
-index 00000000000000..45cdeebe1b6d64
---- /dev/null
-+++ ./Misc/NEWS.d/next/Security/2026-03-31-09-15-51.gh-issue-148169.EZJzz2.rst
-@@ -0,0 +1,2 @@
-+A bypass in :mod:`webbrowser` allowed URLs prefixed with ``%action`` to pass
-+the dash-prefix safety check.
diff --git a/lang/python314/files/patch-gh-148395-fix-possible-uaf-in-decompressors b/lang/python314/files/patch-gh-148395-fix-possible-uaf-in-decompressors
deleted file mode 100644
index d5532033752e..000000000000
--- a/lang/python314/files/patch-gh-148395-fix-possible-uaf-in-decompressors
+++ /dev/null
@@ -1,65 +0,0 @@
-From c8d8173c4b06d06902c99ec010ad785a30952880 Mon Sep 17 00:00:00 2001
-From: Stan Ulbrych <stan@python.org>
-Date: Mon, 13 Apr 2026 02:14:54 +0100
-Subject: [PATCH] gh-148395: Fix a possible UAF in
- `{LZMA,BZ2,_Zlib}Decompressor` (GH-148396)
-
-Fix dangling input pointer after `MemoryError` in _lzma/_bz2/_ZlibDecompressor.decompress
-(cherry picked from commit 8fc66aef6d7b3ae58f43f5c66f9366cc8cbbfcd2)
-
-Co-authored-by: Stan Ulbrych <stan@python.org>
----
- .../Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst  | 5 +++++
- Modules/_bz2module.c                                         | 1 +
- Modules/_lzmamodule.c                                        | 1 +
- Modules/zlibmodule.c                                         | 1 +
- 4 files changed, 8 insertions(+)
- create mode 100644 Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst
-
-diff --git a/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst b/Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst
-new file mode 100644
-index 00000000000000..9502189ab199c1
---- /dev/null
-+++ ./Misc/NEWS.d/next/Security/2026-04-10-16-28-21.gh-issue-148395.kfzm0G.rst
-@@ -0,0 +1,5 @@
-+Fix a dangling input pointer in :class:`lzma.LZMADecompressor`,
-+:class:`bz2.BZ2Decompressor`, and internal :class:`!zlib._ZlibDecompressor`
-+when memory allocation fails with :exc:`MemoryError`, which could let a
-+subsequent :meth:`!decompress` call read or write through a stale pointer to
-+the already-released caller buffer.
-diff --git a/Modules/_bz2module.c b/Modules/_bz2module.c
-index 9e85e0de42cd8d..055ce82e7d2863 100644
---- ./Modules/_bz2module.c
-+++ b/Modules/_bz2module.c
-@@ -593,6 +593,7 @@ decompress(BZ2Decompressor *d, char *data, size_t len, Py_ssize_t max_length)
-     return result;
- 
- error:
-+    bzs->next_in = NULL;
-     Py_XDECREF(result);
-     return NULL;
- }
-diff --git a/Modules/_lzmamodule.c b/Modules/_lzmamodule.c
-index 462c2181fa6036..6785dc56730c5c 100644
---- ./Modules/_lzmamodule.c
-+++ b/Modules/_lzmamodule.c
-@@ -1120,6 +1120,7 @@ decompress(Decompressor *d, uint8_t *data, size_t len, Py_ssize_t max_length)
-     return result;
- 
- error:
-+    lzs->next_in = NULL;
-     Py_XDECREF(result);
-     return NULL;
- }
-diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c
-index 5b6b0c5cac864a..a86aa5fdbb576c 100644
---- ./Modules/zlibmodule.c
-+++ b/Modules/zlibmodule.c
-@@ -1675,6 +1675,7 @@ decompress(ZlibDecompressor *self, uint8_t *data,
-     return result;
- 
- error:
-+    self->zst.next_in = NULL;
-     Py_XDECREF(result);
-     return NULL;
- }
diff --git a/lang/python314/files/patch-gh-148441-Avoid-integer-overflow-in-Expats-CharacterDataHandler b/lang/python314/files/patch-gh-148441-Avoid-integer-overflow-in-Expats-CharacterDataHandler
new file mode 100644
index 000000000000..1625b93d088f
--- /dev/null
+++ b/lang/python314/files/patch-gh-148441-Avoid-integer-overflow-in-Expats-CharacterDataHandler
@@ -0,0 +1,70 @@
+From 6588ca5b642a0f878197fc31afb6bfa424fd7219 Mon Sep 17 00:00:00 2001
+From: "Miss Islington (bot)"
+ <31488909+miss-islington@users.noreply.github.com>
+Date: Sun, 10 May 2026 16:08:59 +0200
+Subject: [PATCH] [3.14] gh-148441: Avoid integer overflow in Expat's
+ CharacterDataHandler (GH-148904) (#149638)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+gh-148441: Avoid integer overflow in Expat's CharacterDataHandler (GH-148904)
+(cherry picked from commit bc1be4f6174086b4a46e3fe656552f5bb4e6e7b2)
+
+Co-authored-by: ByteFlow <fakeshadow1337@gmail.com>
+Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
+---
+ Lib/test/test_pyexpat.py                           | 14 ++++++++++++++
+ .../2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst |  4 ++++
+ Modules/pyexpat.c                                  |  2 +-
+ 3 files changed, 19 insertions(+), 1 deletion(-)
+ create mode 100644 Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst
+
+diff --git ./Lib/test/test_pyexpat.py b/Lib/test/test_pyexpat.py
+index 465f65a03b9e15..6eda89ad2cdf2a 100644
+--- ./Lib/test/test_pyexpat.py
++++ b/Lib/test/test_pyexpat.py
+@@ -672,6 +672,20 @@ def test_change_size_2(self):
+         parser.Parse(xml2, True)
+         self.assertEqual(self.n, 4)
+ 
++    @support.requires_resource('cpu')
++    @support.requires_resource('walltime')
++    @support.bigmemtest(size=2**31, memuse=4, dry_run=False)
++    def test_large_character_data_does_not_crash(self):
++        # See https://github.com/python/cpython/issues/148441
++        parser = expat.ParserCreate()
++        parser.buffer_text = True
++        parser.buffer_size = 2**31 - 1  # INT_MAX
++        N = 2049 * (1 << 20) - 3  # Character data greater than INT_MAX
++        self.assertGreater(N, parser.buffer_size)
++        parser.CharacterDataHandler = lambda text: None
++        xml_data = b"<r>" + b"A" * N + b"</r>"
++        self.assertEqual(parser.Parse(xml_data, True), 1)
++
+ class ElementDeclHandlerTest(unittest.TestCase):
+     def test_trigger_leak(self):
+         # Unfixed, this test would leak the memory of the so-called
+diff --git a/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst b/Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst
+new file mode 100644
+index 00000000000000..762815270e4d40
+--- /dev/null
++++ ./Misc/NEWS.d/next/Library/2026-04-23-12-50-15.gh-issue-148441.zvpCkR.rst
+@@ -0,0 +1,4 @@
++:mod:`xml.parsers.expat`: prevent a crash in
++:meth:`~xml.parsers.expat.xmlparser.CharacterDataHandler`
++when the character data size exceeds the parser's
++:attr:`buffer size <xml.parsers.expat.xmlparser.buffer_size>`.
+diff --git a/Modules/pyexpat.c b/Modules/pyexpat.c
+index f82f8456e489eb..c9dc5e2211ecd5 100644
+--- ./Modules/pyexpat.c
++++ b/Modules/pyexpat.c
+@@ -389,7 +389,7 @@ my_CharacterDataHandler(void *userData, const XML_Char *data, int len)
+     if (self->buffer == NULL)
+         call_character_handler(self, data, len);
+     else {
+-        if ((self->buffer_used + len) > self->buffer_size) {
++        if (len > (self->buffer_size - self->buffer_used)) {
+             if (flush_character_buffer(self) < 0)
+                 return;
+             /* handler might have changed; drop the rest on the floor
diff --git a/lang/python314/pkg-plist b/lang/python314/pkg-plist
index b5fe9727f492..3090f13e1c5d 100644
--- a/lang/python314/pkg-plist
+++ b/lang/python314/pkg-plist
@@ -1847,7 +1847,7 @@ lib/python%%XYDOT%%/ensurepip/__pycache__/__main__.cpython-%%XY%%.pyc
 lib/python%%XYDOT%%/ensurepip/__pycache__/_uninstall.cpython-%%XY%%.opt-1.pyc
 lib/python%%XYDOT%%/ensurepip/__pycache__/_uninstall.cpython-%%XY%%.opt-2.pyc
 lib/python%%XYDOT%%/ensurepip/__pycache__/_uninstall.cpython-%%XY%%.pyc
-lib/python%%XYDOT%%/ensurepip/_bundled/pip-26.0.1-py3-none-any.whl
+lib/python%%XYDOT%%/ensurepip/_bundled/pip-26.1.1-py3-none-any.whl
 lib/python%%XYDOT%%/ensurepip/_uninstall.py
 lib/python%%XYDOT%%/enum.py
 lib/python%%XYDOT%%/filecmp.py
@@ -2908,9 +2908,6 @@ lib/python%%XYDOT%%/test/__pycache__/_test_eintr.cpython-%%XY%%.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_embed_structseq.cpython-%%XY%%.opt-1.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_embed_structseq.cpython-%%XY%%.opt-2.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_embed_structseq.cpython-%%XY%%.pyc
-lib/python%%XYDOT%%/test/__pycache__/_test_gc_fast_cycles.cpython-%%XY%%.opt-1.pyc
-lib/python%%XYDOT%%/test/__pycache__/_test_gc_fast_cycles.cpython-%%XY%%.opt-2.pyc
-lib/python%%XYDOT%%/test/__pycache__/_test_gc_fast_cycles.cpython-%%XY%%.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_monitoring_shutdown.cpython-%%XY%%.opt-1.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_monitoring_shutdown.cpython-%%XY%%.opt-2.pyc
 lib/python%%XYDOT%%/test/__pycache__/_test_monitoring_shutdown.cpython-%%XY%%.pyc
@@ -4233,7 +4230,6 @@ lib/python%%XYDOT%%/test/_crossinterp_definitions.py
 lib/python%%XYDOT%%/test/_test_atexit.py
 lib/python%%XYDOT%%/test/_test_eintr.py
 lib/python%%XYDOT%%/test/_test_embed_structseq.py
-lib/python%%XYDOT%%/test/_test_gc_fast_cycles.py
 lib/python%%XYDOT%%/test/_test_monitoring_shutdown.py
 lib/python%%XYDOT%%/test/_test_multiprocessing.py
 lib/python%%XYDOT%%/test/_test_venv_multiprocessing.py
@@ -6679,6 +6675,7 @@ lib/python%%XYDOT%%/test/test_json/__pycache__/test_tool.cpython-%%XY%%.pyc
 lib/python%%XYDOT%%/test/test_json/__pycache__/test_unicode.cpython-%%XY%%.opt-1.pyc
 lib/python%%XYDOT%%/test/test_json/__pycache__/test_unicode.cpython-%%XY%%.opt-2.pyc
 lib/python%%XYDOT%%/test/test_json/__pycache__/test_unicode.cpython-%%XY%%.pyc
+lib/python%%XYDOT%%/test/test_json/json_lines.jsonl
 lib/python%%XYDOT%%/test/test_json/test_decode.py
 lib/python%%XYDOT%%/test/test_json/test_default.py
 lib/python%%XYDOT%%/test/test_json/test_dump.py


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a2ba01d.436f2.101e95ee>