forked from python-interpreters/python314
Compare commits
2 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
| 990b2813e1 | |||
|
7a848baf56
|
@@ -4,11 +4,11 @@
|
||||
Lib/test/test_xml_etree.py | 10 ++++++++++
|
||||
3 files changed, 17 insertions(+)
|
||||
|
||||
Index: Python-3.14.0/Lib/test/test_pyexpat.py
|
||||
Index: Python-3.14.2/Lib/test/test_pyexpat.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/test/test_pyexpat.py 2025-10-08 11:27:29.989583305 +0200
|
||||
+++ Python-3.14.0/Lib/test/test_pyexpat.py 2025-10-08 11:28:09.418914658 +0200
|
||||
@@ -827,6 +827,10 @@
|
||||
--- Python-3.14.2.orig/Lib/test/test_pyexpat.py 2025-12-11 18:10:58.057084164 +0100
|
||||
+++ Python-3.14.2/Lib/test/test_pyexpat.py 2025-12-11 18:12:07.480767746 +0100
|
||||
@@ -848,6 +848,10 @@
|
||||
self.assertEqual(started, ['doc'])
|
||||
|
||||
def test_reparse_deferral_disabled(self):
|
||||
@@ -19,10 +19,10 @@ Index: Python-3.14.0/Lib/test/test_pyexpat.py
|
||||
started = []
|
||||
|
||||
def start_element(name, _):
|
||||
Index: Python-3.14.0/Lib/test/test_sax.py
|
||||
Index: Python-3.14.2/Lib/test/test_sax.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/test/test_sax.py 2025-10-08 11:27:30.053760879 +0200
|
||||
+++ Python-3.14.0/Lib/test/test_sax.py 2025-10-08 11:28:09.419532320 +0200
|
||||
--- Python-3.14.2.orig/Lib/test/test_sax.py 2025-12-11 18:10:58.116419305 +0100
|
||||
+++ Python-3.14.2/Lib/test/test_sax.py 2025-12-11 18:12:07.481506046 +0100
|
||||
@@ -1241,6 +1241,9 @@
|
||||
|
||||
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
|
||||
@@ -33,10 +33,10 @@ Index: Python-3.14.0/Lib/test/test_sax.py
|
||||
def test_flush_reparse_deferral_disabled(self):
|
||||
result = BytesIO()
|
||||
xmlgen = XMLGenerator(result)
|
||||
Index: Python-3.14.0/Lib/test/test_xml_etree.py
|
||||
Index: Python-3.14.2/Lib/test/test_xml_etree.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/test/test_xml_etree.py 2025-10-08 11:27:30.502943506 +0200
|
||||
+++ Python-3.14.0/Lib/test/test_xml_etree.py 2025-10-08 11:28:09.420206077 +0200
|
||||
--- Python-3.14.2.orig/Lib/test/test_xml_etree.py 2025-12-11 18:10:58.548740381 +0100
|
||||
+++ Python-3.14.2/Lib/test/test_xml_etree.py 2025-12-11 18:12:07.481767744 +0100
|
||||
@@ -138,6 +138,11 @@
|
||||
return mock.patch.object(cls, "__eq__", autospec=True, wraps=eq)
|
||||
|
||||
@@ -49,7 +49,7 @@ Index: Python-3.14.0/Lib/test/test_xml_etree.py
|
||||
def checkwarnings(*filters, quiet=False):
|
||||
def decorator(test):
|
||||
def newtest(*args, **kwargs):
|
||||
@@ -1547,9 +1552,11 @@
|
||||
@@ -1573,9 +1578,11 @@
|
||||
self.assert_event_tags(parser, [('end', 'root')])
|
||||
self.assertIsNone(parser.close())
|
||||
|
||||
@@ -61,7 +61,7 @@ Index: Python-3.14.0/Lib/test/test_xml_etree.py
|
||||
def test_simple_xml_chunk_5(self):
|
||||
self.test_simple_xml(chunk_size=5, flush=True)
|
||||
|
||||
@@ -1774,6 +1781,9 @@
|
||||
@@ -1802,6 +1809,9 @@
|
||||
|
||||
self.assert_event_tags(parser, [('end', 'doc')])
|
||||
|
||||
|
||||
@@ -1,374 +0,0 @@
|
||||
From 5c0bf5295a6a38ee7540e447bcdc4889d131e261 Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Fri, 31 Oct 2025 15:49:51 +0200
|
||||
Subject: [PATCH] [3.14] gh-136065: Fix quadratic complexity in
|
||||
os.path.expandvars() (GH-134952) (cherry picked from commit
|
||||
f029e8db626ddc6e3a3beea4eff511a71aaceb5c)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Co-authored-by: Łukasz Langa <lukasz@langa.pl>
|
||||
---
|
||||
Lib/ntpath.py | 126 ++++++------------
|
||||
Lib/posixpath.py | 43 +++---
|
||||
Lib/test/test_genericpath.py | 21 ++-
|
||||
Lib/test/test_ntpath.py | 22 ++-
|
||||
...-05-30-22-33-27.gh-issue-136065.bu337o.rst | 1 +
|
||||
5 files changed, 96 insertions(+), 117 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
|
||||
|
||||
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
|
||||
index 9cdc16480f9afe..01f060e70beed9 100644
|
||||
--- a/Lib/ntpath.py
|
||||
+++ b/Lib/ntpath.py
|
||||
@@ -400,17 +400,23 @@ def expanduser(path):
|
||||
# XXX With COMMAND.COM you can use any characters in a variable name,
|
||||
# XXX except '^|<>='.
|
||||
|
||||
+_varpattern = r"'[^']*'?|%(%|[^%]*%?)|\$(\$|[-\w]+|\{[^}]*\}?)"
|
||||
+_varsub = None
|
||||
+_varsubb = None
|
||||
+
|
||||
def expandvars(path):
|
||||
"""Expand shell variables of the forms $var, ${var} and %var%.
|
||||
|
||||
Unknown variables are left unchanged."""
|
||||
path = os.fspath(path)
|
||||
+ global _varsub, _varsubb
|
||||
if isinstance(path, bytes):
|
||||
if b'$' not in path and b'%' not in path:
|
||||
return path
|
||||
- import string
|
||||
- varchars = bytes(string.ascii_letters + string.digits + '_-', 'ascii')
|
||||
- quote = b'\''
|
||||
+ if not _varsubb:
|
||||
+ import re
|
||||
+ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
|
||||
+ sub = _varsubb
|
||||
percent = b'%'
|
||||
brace = b'{'
|
||||
rbrace = b'}'
|
||||
@@ -419,94 +425,44 @@ def expandvars(path):
|
||||
else:
|
||||
if '$' not in path and '%' not in path:
|
||||
return path
|
||||
- import string
|
||||
- varchars = string.ascii_letters + string.digits + '_-'
|
||||
- quote = '\''
|
||||
+ if not _varsub:
|
||||
+ import re
|
||||
+ _varsub = re.compile(_varpattern, re.ASCII).sub
|
||||
+ sub = _varsub
|
||||
percent = '%'
|
||||
brace = '{'
|
||||
rbrace = '}'
|
||||
dollar = '$'
|
||||
environ = os.environ
|
||||
- res = path[:0]
|
||||
- index = 0
|
||||
- pathlen = len(path)
|
||||
- while index < pathlen:
|
||||
- c = path[index:index+1]
|
||||
- if c == quote: # no expansion within single quotes
|
||||
- path = path[index + 1:]
|
||||
- pathlen = len(path)
|
||||
- try:
|
||||
- index = path.index(c)
|
||||
- res += c + path[:index + 1]
|
||||
- except ValueError:
|
||||
- res += c + path
|
||||
- index = pathlen - 1
|
||||
- elif c == percent: # variable or '%'
|
||||
- if path[index + 1:index + 2] == percent:
|
||||
- res += c
|
||||
- index += 1
|
||||
- else:
|
||||
- path = path[index+1:]
|
||||
- pathlen = len(path)
|
||||
- try:
|
||||
- index = path.index(percent)
|
||||
- except ValueError:
|
||||
- res += percent + path
|
||||
- index = pathlen - 1
|
||||
- else:
|
||||
- var = path[:index]
|
||||
- try:
|
||||
- if environ is None:
|
||||
- value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
- else:
|
||||
- value = environ[var]
|
||||
- except KeyError:
|
||||
- value = percent + var + percent
|
||||
- res += value
|
||||
- elif c == dollar: # variable or '$$'
|
||||
- if path[index + 1:index + 2] == dollar:
|
||||
- res += c
|
||||
- index += 1
|
||||
- elif path[index + 1:index + 2] == brace:
|
||||
- path = path[index+2:]
|
||||
- pathlen = len(path)
|
||||
- try:
|
||||
- index = path.index(rbrace)
|
||||
- except ValueError:
|
||||
- res += dollar + brace + path
|
||||
- index = pathlen - 1
|
||||
- else:
|
||||
- var = path[:index]
|
||||
- try:
|
||||
- if environ is None:
|
||||
- value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
- else:
|
||||
- value = environ[var]
|
||||
- except KeyError:
|
||||
- value = dollar + brace + var + rbrace
|
||||
- res += value
|
||||
- else:
|
||||
- var = path[:0]
|
||||
- index += 1
|
||||
- c = path[index:index + 1]
|
||||
- while c and c in varchars:
|
||||
- var += c
|
||||
- index += 1
|
||||
- c = path[index:index + 1]
|
||||
- try:
|
||||
- if environ is None:
|
||||
- value = os.fsencode(os.environ[os.fsdecode(var)])
|
||||
- else:
|
||||
- value = environ[var]
|
||||
- except KeyError:
|
||||
- value = dollar + var
|
||||
- res += value
|
||||
- if c:
|
||||
- index -= 1
|
||||
+
|
||||
+ def repl(m):
|
||||
+ lastindex = m.lastindex
|
||||
+ if lastindex is None:
|
||||
+ return m[0]
|
||||
+ name = m[lastindex]
|
||||
+ if lastindex == 1:
|
||||
+ if name == percent:
|
||||
+ return name
|
||||
+ if not name.endswith(percent):
|
||||
+ return m[0]
|
||||
+ name = name[:-1]
|
||||
else:
|
||||
- res += c
|
||||
- index += 1
|
||||
- return res
|
||||
+ if name == dollar:
|
||||
+ return name
|
||||
+ if name.startswith(brace):
|
||||
+ if not name.endswith(rbrace):
|
||||
+ return m[0]
|
||||
+ name = name[1:-1]
|
||||
+
|
||||
+ try:
|
||||
+ if environ is None:
|
||||
+ return os.fsencode(os.environ[os.fsdecode(name)])
|
||||
+ else:
|
||||
+ return environ[name]
|
||||
+ except KeyError:
|
||||
+ return m[0]
|
||||
+
|
||||
+ return sub(repl, path)
|
||||
|
||||
|
||||
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A\B.
|
||||
diff --git a/Lib/posixpath.py b/Lib/posixpath.py
|
||||
index d38f3bd5872bcd..ad86cc06c017a0 100644
|
||||
--- a/Lib/posixpath.py
|
||||
+++ b/Lib/posixpath.py
|
||||
@@ -284,42 +284,41 @@ def expanduser(path):
|
||||
# This expands the forms $variable and ${variable} only.
|
||||
# Non-existent variables are left unchanged.
|
||||
|
||||
-_varprog = None
|
||||
-_varprogb = None
|
||||
+_varpattern = r'\$(\w+|\{[^}]*\}?)'
|
||||
+_varsub = None
|
||||
+_varsubb = None
|
||||
|
||||
def expandvars(path):
|
||||
"""Expand shell variables of form $var and ${var}. Unknown variables
|
||||
are left unchanged."""
|
||||
path = os.fspath(path)
|
||||
- global _varprog, _varprogb
|
||||
+ global _varsub, _varsubb
|
||||
if isinstance(path, bytes):
|
||||
if b'$' not in path:
|
||||
return path
|
||||
- if not _varprogb:
|
||||
+ if not _varsubb:
|
||||
import re
|
||||
- _varprogb = re.compile(br'\$(\w+|\{[^}]*\})', re.ASCII)
|
||||
- search = _varprogb.search
|
||||
+ _varsubb = re.compile(_varpattern.encode(), re.ASCII).sub
|
||||
+ sub = _varsubb
|
||||
start = b'{'
|
||||
end = b'}'
|
||||
environ = getattr(os, 'environb', None)
|
||||
else:
|
||||
if '$' not in path:
|
||||
return path
|
||||
- if not _varprog:
|
||||
+ if not _varsub:
|
||||
import re
|
||||
- _varprog = re.compile(r'\$(\w+|\{[^}]*\})', re.ASCII)
|
||||
- search = _varprog.search
|
||||
+ _varsub = re.compile(_varpattern, re.ASCII).sub
|
||||
+ sub = _varsub
|
||||
start = '{'
|
||||
end = '}'
|
||||
environ = os.environ
|
||||
- i = 0
|
||||
- while True:
|
||||
- m = search(path, i)
|
||||
- if not m:
|
||||
- break
|
||||
- i, j = m.span(0)
|
||||
- name = m.group(1)
|
||||
- if name.startswith(start) and name.endswith(end):
|
||||
+
|
||||
+ def repl(m):
|
||||
+ name = m[1]
|
||||
+ if name.startswith(start):
|
||||
+ if not name.endswith(end):
|
||||
+ return m[0]
|
||||
name = name[1:-1]
|
||||
try:
|
||||
if environ is None:
|
||||
@@ -327,13 +326,11 @@ def expandvars(path):
|
||||
else:
|
||||
value = environ[name]
|
||||
except KeyError:
|
||||
- i = j
|
||||
+ return m[0]
|
||||
else:
|
||||
- tail = path[j:]
|
||||
- path = path[:i] + value
|
||||
- i = len(path)
|
||||
- path += tail
|
||||
- return path
|
||||
+ return value
|
||||
+
|
||||
+ return sub(repl, path)
|
||||
|
||||
|
||||
# Normalize a path, e.g. A//B, A/./B and A/foo/../B all become A/B.
|
||||
diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
|
||||
index df07af01fc7540..1a44cedcd360b1 100644
|
||||
--- a/Lib/test/test_genericpath.py
|
||||
+++ b/Lib/test/test_genericpath.py
|
||||
@@ -7,9 +7,9 @@
|
||||
import sys
|
||||
import unittest
|
||||
import warnings
|
||||
-from test.support import (
|
||||
- is_apple, is_emscripten, os_helper, warnings_helper
|
||||
-)
|
||||
+from test import support
|
||||
+from test.support import os_helper
|
||||
+from test.support import warnings_helper
|
||||
from test.support.script_helper import assert_python_ok
|
||||
from test.support.os_helper import FakePath
|
||||
|
||||
@@ -445,6 +445,19 @@ def check(value, expected):
|
||||
os.fsencode('$bar%s bar' % nonascii))
|
||||
check(b'$spam}bar', os.fsencode('%s}bar' % nonascii))
|
||||
|
||||
+ @support.requires_resource('cpu')
|
||||
+ def test_expandvars_large(self):
|
||||
+ expandvars = self.pathmodule.expandvars
|
||||
+ with os_helper.EnvironmentVarGuard() as env:
|
||||
+ env.clear()
|
||||
+ env["A"] = "B"
|
||||
+ n = 100_000
|
||||
+ self.assertEqual(expandvars('$A'*n), 'B'*n)
|
||||
+ self.assertEqual(expandvars('${A}'*n), 'B'*n)
|
||||
+ self.assertEqual(expandvars('$A!'*n), 'B!'*n)
|
||||
+ self.assertEqual(expandvars('${A}A'*n), 'BA'*n)
|
||||
+ self.assertEqual(expandvars('${'*10*n), '${'*10*n)
|
||||
+
|
||||
def test_abspath(self):
|
||||
self.assertIn("foo", self.pathmodule.abspath("foo"))
|
||||
with warnings.catch_warnings():
|
||||
@@ -502,7 +515,7 @@ def test_nonascii_abspath(self):
|
||||
# directory (when the bytes name is used).
|
||||
and sys.platform not in {
|
||||
"win32", "emscripten", "wasi"
|
||||
- } and not is_apple
|
||||
+ } and not support.is_apple
|
||||
):
|
||||
name = os_helper.TESTFN_UNDECODABLE
|
||||
elif os_helper.TESTFN_NONASCII:
|
||||
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
|
||||
index 03bfccf260b25d..9270f3257068d6 100644
|
||||
--- a/Lib/test/test_ntpath.py
|
||||
+++ b/Lib/test/test_ntpath.py
|
||||
@@ -7,8 +7,7 @@
|
||||
import unittest
|
||||
import warnings
|
||||
from test import support
|
||||
-from test.support import cpython_only, os_helper
|
||||
-from test.support import TestFailed
|
||||
+from test.support import os_helper
|
||||
from ntpath import ALLOW_MISSING
|
||||
from test.support.os_helper import FakePath
|
||||
from test import test_genericpath
|
||||
@@ -59,7 +58,7 @@ def tester(fn, wantResult):
|
||||
fn = fn.replace("\\", "\\\\")
|
||||
gotResult = eval(fn)
|
||||
if wantResult != gotResult and _norm(wantResult) != _norm(gotResult):
|
||||
- raise TestFailed("%s should return: %s but returned: %s" \
|
||||
+ raise support.TestFailed("%s should return: %s but returned: %s" \
|
||||
%(str(fn), str(wantResult), str(gotResult)))
|
||||
|
||||
# then with bytes
|
||||
@@ -75,7 +74,7 @@ def tester(fn, wantResult):
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
gotResult = eval(fn)
|
||||
if _norm(wantResult) != _norm(gotResult):
|
||||
- raise TestFailed("%s should return: %s but returned: %s" \
|
||||
+ raise support.TestFailed("%s should return: %s but returned: %s" \
|
||||
%(str(fn), str(wantResult), repr(gotResult)))
|
||||
|
||||
|
||||
@@ -1022,6 +1021,19 @@ def check(value, expected):
|
||||
check('%spam%bar', '%sbar' % nonascii)
|
||||
check('%{}%bar'.format(nonascii), 'ham%sbar' % nonascii)
|
||||
|
||||
+ @support.requires_resource('cpu')
|
||||
+ def test_expandvars_large(self):
|
||||
+ expandvars = ntpath.expandvars
|
||||
+ with os_helper.EnvironmentVarGuard() as env:
|
||||
+ env.clear()
|
||||
+ env["A"] = "B"
|
||||
+ n = 100_000
|
||||
+ self.assertEqual(expandvars('%A%'*n), 'B'*n)
|
||||
+ self.assertEqual(expandvars('%A%A'*n), 'BA'*n)
|
||||
+ self.assertEqual(expandvars("''"*n + '%%'), "''"*n + '%')
|
||||
+ self.assertEqual(expandvars("%%"*n), "%"*n)
|
||||
+ self.assertEqual(expandvars("$$"*n), "$"*n)
|
||||
+
|
||||
def test_expanduser(self):
|
||||
tester('ntpath.expanduser("test")', 'test')
|
||||
|
||||
@@ -1439,7 +1451,7 @@ def test_con_device(self):
|
||||
self.assertTrue(os.path.exists(r"\\.\CON"))
|
||||
|
||||
@unittest.skipIf(sys.platform != 'win32', "Fast paths are only for win32")
|
||||
- @cpython_only
|
||||
+ @support.cpython_only
|
||||
def test_fast_paths_in_use(self):
|
||||
# There are fast paths of these functions implemented in posixmodule.c.
|
||||
# Confirm that they are being used, and not the Python fallbacks in
|
||||
diff --git a/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..1d152bb5318380
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2025-05-30-22-33-27.gh-issue-136065.bu337o.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Fix quadratic complexity in :func:`os.path.expandvars`.
|
||||
@@ -1,306 +0,0 @@
|
||||
From 5454f861e2b3c96fa1e6430dc952544670955f69 Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Tue, 7 Oct 2025 20:15:26 +0300
|
||||
Subject: [PATCH] gh-139700: Check consistency of the zip64 end of central
|
||||
directory record (GH-139702)
|
||||
|
||||
Support records with "zip64 extensible data" if there are no bytes
|
||||
prepended to the ZIP file.
|
||||
(cherry picked from commit 162997bb70e067668c039700141770687bc8f267)
|
||||
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
---
|
||||
Lib/test/test_zipfile/test_core.py | 82 +++++++++-
|
||||
Lib/zipfile/__init__.py | 51 +++---
|
||||
Misc/NEWS.d/next/Security/2025-10-07-19-31-34.gh-issue-139700.vNHU1O.rst | 3
|
||||
3 files changed, 113 insertions(+), 23 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2025-10-07-19-31-34.gh-issue-139700.vNHU1O.rst
|
||||
|
||||
Index: Python-3.14.0/Lib/test/test_zipfile/test_core.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/test/test_zipfile/test_core.py 2025-11-12 01:03:54.947094045 +0100
|
||||
+++ Python-3.14.0/Lib/test/test_zipfile/test_core.py 2025-11-12 01:04:11.766432381 +0100
|
||||
@@ -898,6 +898,8 @@
|
||||
self, file_size_64_set=False, file_size_extra=False,
|
||||
compress_size_64_set=False, compress_size_extra=False,
|
||||
header_offset_64_set=False, header_offset_extra=False,
|
||||
+ extensible_data=b'',
|
||||
+ end_of_central_dir_size=None, offset_to_end_of_central_dir=None,
|
||||
):
|
||||
"""Generate bytes sequence for a zip with (incomplete) zip64 data.
|
||||
|
||||
@@ -951,6 +953,12 @@
|
||||
|
||||
central_dir_size = struct.pack('<Q', 58 + 8 * len(central_zip64_fields))
|
||||
offset_to_central_dir = struct.pack('<Q', 50 + 8 * len(local_zip64_fields))
|
||||
+ if end_of_central_dir_size is None:
|
||||
+ end_of_central_dir_size = 44 + len(extensible_data)
|
||||
+ if offset_to_end_of_central_dir is None:
|
||||
+ offset_to_end_of_central_dir = (108
|
||||
+ + 8 * len(local_zip64_fields)
|
||||
+ + 8 * len(central_zip64_fields))
|
||||
|
||||
local_extra_length = struct.pack("<H", 4 + 8 * len(local_zip64_fields))
|
||||
central_extra_length = struct.pack("<H", 4 + 8 * len(central_zip64_fields))
|
||||
@@ -979,14 +987,17 @@
|
||||
+ filename
|
||||
+ central_extra
|
||||
# Zip64 end of central directory
|
||||
- + b"PK\x06\x06,\x00\x00\x00\x00\x00\x00\x00-\x00-"
|
||||
- + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
|
||||
+ + b"PK\x06\x06"
|
||||
+ + struct.pack('<Q', end_of_central_dir_size)
|
||||
+ + b"-\x00-\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00"
|
||||
+ b"\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00"
|
||||
+ central_dir_size
|
||||
+ offset_to_central_dir
|
||||
+ + extensible_data
|
||||
# Zip64 end of central directory locator
|
||||
- + b"PK\x06\x07\x00\x00\x00\x00l\x00\x00\x00\x00\x00\x00\x00\x01"
|
||||
- + b"\x00\x00\x00"
|
||||
+ + b"PK\x06\x07\x00\x00\x00\x00"
|
||||
+ + struct.pack('<Q', offset_to_end_of_central_dir)
|
||||
+ + b"\x01\x00\x00\x00"
|
||||
# end of central directory
|
||||
+ b"PK\x05\x06\x00\x00\x00\x00\x01\x00\x01\x00:\x00\x00\x002\x00"
|
||||
+ b"\x00\x00\x00\x00"
|
||||
@@ -1017,6 +1028,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_file_size_extra))
|
||||
self.assertIn('file size', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_file_size_extra)))
|
||||
|
||||
# zip64 file size present, zip64 compress size present, one field in
|
||||
# extra, expecting two, equals missing compress size.
|
||||
@@ -1028,6 +1040,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
|
||||
self.assertIn('compress size', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
|
||||
|
||||
# zip64 compress size present, no fields in extra, expecting one,
|
||||
# equals missing compress size.
|
||||
@@ -1037,6 +1050,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_compress_size_extra))
|
||||
self.assertIn('compress size', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_compress_size_extra)))
|
||||
|
||||
# zip64 file size present, zip64 compress size present, zip64 header
|
||||
# offset present, two fields in extra, expecting three, equals missing
|
||||
@@ -1051,6 +1065,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
|
||||
self.assertIn('header offset', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
|
||||
|
||||
# zip64 compress size present, zip64 header offset present, one field
|
||||
# in extra, expecting two, equals missing header offset
|
||||
@@ -1063,6 +1078,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
|
||||
self.assertIn('header offset', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
|
||||
|
||||
# zip64 file size present, zip64 header offset present, one field in
|
||||
# extra, expecting two, equals missing header offset
|
||||
@@ -1075,6 +1091,7 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
|
||||
self.assertIn('header offset', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
|
||||
|
||||
# zip64 header offset present, no fields in extra, expecting one,
|
||||
# equals missing header offset
|
||||
@@ -1086,6 +1103,63 @@
|
||||
with self.assertRaises(zipfile.BadZipFile) as e:
|
||||
zipfile.ZipFile(io.BytesIO(missing_header_offset_extra))
|
||||
self.assertIn('header offset', str(e.exception).lower())
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(missing_header_offset_extra)))
|
||||
+
|
||||
+ def test_bad_zip64_end_of_central_dir(self):
|
||||
+ zipdata = self.make_zip64_file(end_of_central_dir_size=0)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ zipdata = self.make_zip64_file(end_of_central_dir_size=100)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ zipdata = self.make_zip64_file(offset_to_end_of_central_dir=0)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*record'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ zipdata = self.make_zip64_file(offset_to_end_of_central_dir=1000)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'Corrupt.*locator'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ def test_zip64_end_of_central_dir_record_not_found(self):
|
||||
+ zipdata = self.make_zip64_file()
|
||||
+ zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ zipdata = self.make_zip64_file(
|
||||
+ extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
|
||||
+ zipdata = zipdata.replace(b"PK\x06\x06", b'\x00'*4)
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
|
||||
+ zipfile.ZipFile(io.BytesIO(zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ def test_zip64_extensible_data(self):
|
||||
+ # These values are what is set in the make_zip64_file method.
|
||||
+ expected_file_size = 8
|
||||
+ expected_compress_size = 8
|
||||
+ expected_header_offset = 0
|
||||
+ expected_content = b"test1234"
|
||||
+
|
||||
+ zipdata = self.make_zip64_file(
|
||||
+ extensible_data=b'\xca\xfe\x04\x00\x00\x00data')
|
||||
+ with zipfile.ZipFile(io.BytesIO(zipdata)) as zf:
|
||||
+ zinfo = zf.infolist()[0]
|
||||
+ self.assertEqual(zinfo.file_size, expected_file_size)
|
||||
+ self.assertEqual(zinfo.compress_size, expected_compress_size)
|
||||
+ self.assertEqual(zinfo.header_offset, expected_header_offset)
|
||||
+ self.assertEqual(zf.read(zinfo), expected_content)
|
||||
+ self.assertTrue(zipfile.is_zipfile(io.BytesIO(zipdata)))
|
||||
+
|
||||
+ with self.assertRaisesRegex(zipfile.BadZipFile, 'record not found'):
|
||||
+ zipfile.ZipFile(io.BytesIO(b'prepended' + zipdata))
|
||||
+ self.assertFalse(zipfile.is_zipfile(io.BytesIO(b'prepended' + zipdata)))
|
||||
|
||||
def test_generated_valid_zip64_extra(self):
|
||||
# These values are what is set in the make_zip64_file method.
|
||||
Index: Python-3.14.0/Lib/zipfile/__init__.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/zipfile/__init__.py 2025-11-12 01:03:55.239347604 +0100
|
||||
+++ Python-3.14.0/Lib/zipfile/__init__.py 2025-11-12 01:04:11.767105446 +0100
|
||||
@@ -265,7 +265,7 @@
|
||||
else:
|
||||
with open(filename, "rb") as fp:
|
||||
result = _check_zipfile(fp)
|
||||
- except OSError:
|
||||
+ except (OSError, BadZipFile):
|
||||
pass
|
||||
return result
|
||||
|
||||
@@ -275,9 +275,6 @@
|
||||
|
||||
# "concat" is zero, unless zip was concatenated to another file
|
||||
concat = endrec[_ECD_LOCATION] - size_cd - offset_cd
|
||||
- if endrec[_ECD_SIGNATURE] == stringEndArchive64:
|
||||
- # If Zip64 extension structures are present, account for them
|
||||
- concat -= (sizeEndCentDir64 + sizeEndCentDir64Locator)
|
||||
|
||||
if debug > 2:
|
||||
inferred = concat + offset_cd
|
||||
@@ -289,16 +286,15 @@
|
||||
"""
|
||||
Read the ZIP64 end-of-archive records and use that to update endrec
|
||||
"""
|
||||
- try:
|
||||
- fpin.seek(offset - sizeEndCentDir64Locator, 2)
|
||||
- except OSError:
|
||||
- # If the seek fails, the file is not large enough to contain a ZIP64
|
||||
+ offset -= sizeEndCentDir64Locator
|
||||
+ if offset < 0:
|
||||
+ # The file is not large enough to contain a ZIP64
|
||||
# end-of-archive record, so just return the end record we were given.
|
||||
return endrec
|
||||
-
|
||||
+ fpin.seek(offset)
|
||||
data = fpin.read(sizeEndCentDir64Locator)
|
||||
if len(data) != sizeEndCentDir64Locator:
|
||||
- return endrec
|
||||
+ raise OSError("Unknown I/O error")
|
||||
sig, diskno, reloff, disks = struct.unpack(structEndArchive64Locator, data)
|
||||
if sig != stringEndArchive64Locator:
|
||||
return endrec
|
||||
@@ -306,16 +302,33 @@
|
||||
if diskno != 0 or disks > 1:
|
||||
raise BadZipFile("zipfiles that span multiple disks are not supported")
|
||||
|
||||
- # Assume no 'zip64 extensible data'
|
||||
- fpin.seek(offset - sizeEndCentDir64Locator - sizeEndCentDir64, 2)
|
||||
+ offset -= sizeEndCentDir64
|
||||
+ if reloff > offset:
|
||||
+ raise BadZipFile("Corrupt zip64 end of central directory locator")
|
||||
+ # First, check the assumption that there is no prepended data.
|
||||
+ fpin.seek(reloff)
|
||||
+ extrasz = offset - reloff
|
||||
data = fpin.read(sizeEndCentDir64)
|
||||
if len(data) != sizeEndCentDir64:
|
||||
- return endrec
|
||||
+ raise OSError("Unknown I/O error")
|
||||
+ if not data.startswith(stringEndArchive64) and reloff != offset:
|
||||
+ # Since we already have seen the Zip64 EOCD Locator, it's
|
||||
+ # possible we got here because there is prepended data.
|
||||
+ # Assume no 'zip64 extensible data'
|
||||
+ fpin.seek(offset)
|
||||
+ extrasz = 0
|
||||
+ data = fpin.read(sizeEndCentDir64)
|
||||
+ if len(data) != sizeEndCentDir64:
|
||||
+ raise OSError("Unknown I/O error")
|
||||
+ if not data.startswith(stringEndArchive64):
|
||||
+ raise BadZipFile("Zip64 end of central directory record not found")
|
||||
+
|
||||
sig, sz, create_version, read_version, disk_num, disk_dir, \
|
||||
dircount, dircount2, dirsize, diroffset = \
|
||||
struct.unpack(structEndArchive64, data)
|
||||
- if sig != stringEndArchive64:
|
||||
- return endrec
|
||||
+ if (diroffset + dirsize != reloff or
|
||||
+ sz + 12 != sizeEndCentDir64 + extrasz):
|
||||
+ raise BadZipFile("Corrupt zip64 end of central directory record")
|
||||
|
||||
# Update the original endrec using data from the ZIP64 record
|
||||
endrec[_ECD_SIGNATURE] = sig
|
||||
@@ -325,6 +338,7 @@
|
||||
endrec[_ECD_ENTRIES_TOTAL] = dircount2
|
||||
endrec[_ECD_SIZE] = dirsize
|
||||
endrec[_ECD_OFFSET] = diroffset
|
||||
+ endrec[_ECD_LOCATION] = offset - extrasz
|
||||
return endrec
|
||||
|
||||
|
||||
@@ -358,7 +372,7 @@
|
||||
endrec.append(filesize - sizeEndCentDir)
|
||||
|
||||
# Try to read the "Zip64 end of central directory" structure
|
||||
- return _EndRecData64(fpin, -sizeEndCentDir, endrec)
|
||||
+ return _EndRecData64(fpin, filesize - sizeEndCentDir, endrec)
|
||||
|
||||
# Either this is not a ZIP file, or it is a ZIP file with an archive
|
||||
# comment. Search the end of the file for the "end of central directory"
|
||||
@@ -382,8 +396,7 @@
|
||||
endrec.append(maxCommentStart + start)
|
||||
|
||||
# Try to read the "Zip64 end of central directory" structure
|
||||
- return _EndRecData64(fpin, maxCommentStart + start - filesize,
|
||||
- endrec)
|
||||
+ return _EndRecData64(fpin, maxCommentStart + start, endrec)
|
||||
|
||||
# Unable to find a valid end of central directory structure
|
||||
return None
|
||||
@@ -2142,7 +2155,7 @@
|
||||
" would require ZIP64 extensions")
|
||||
zip64endrec = struct.pack(
|
||||
structEndArchive64, stringEndArchive64,
|
||||
- 44, 45, 45, 0, 0, centDirCount, centDirCount,
|
||||
+ sizeEndCentDir64 - 12, 45, 45, 0, 0, centDirCount, centDirCount,
|
||||
centDirSize, centDirOffset)
|
||||
self.fp.write(zip64endrec)
|
||||
|
||||
Index: Python-3.14.0/Misc/NEWS.d/next/Security/2025-10-07-19-31-34.gh-issue-139700.vNHU1O.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.14.0/Misc/NEWS.d/next/Security/2025-10-07-19-31-34.gh-issue-139700.vNHU1O.rst 2025-11-12 01:04:11.767493557 +0100
|
||||
@@ -0,0 +1,3 @@
|
||||
+Check consistency of the zip64 end of central directory record. Support
|
||||
+records with "zip64 extensible data" if there are no bytes prepended to the
|
||||
+ZIP file.
|
||||
BIN
Python-3.14.0.tar.xz
LFS
BIN
Python-3.14.0.tar.xz
LFS
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Python-3.14.2.tar.xz
LFS
Normal file
BIN
Python-3.14.2.tar.xz
LFS
Normal file
Binary file not shown.
1
Python-3.14.2.tar.xz.sigstore
Normal file
1
Python-3.14.2.tar.xz.sigstore
Normal file
File diff suppressed because one or more lines are too long
@@ -13,11 +13,11 @@ Co-Authored-By: Xavier de Gaye <xdegaye@gmail.com>
|
||||
5 files changed, 37 insertions(+), 9 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
|
||||
|
||||
Index: Python-3.14.0rc1/Doc/library/ensurepip.rst
|
||||
Index: Python-3.14.2/Doc/library/ensurepip.rst
|
||||
===================================================================
|
||||
--- Python-3.14.0rc1.orig/Doc/library/ensurepip.rst 2025-07-22 18:42:44.000000000 +0200
|
||||
+++ Python-3.14.0rc1/Doc/library/ensurepip.rst 2025-07-23 10:10:31.690342385 +0200
|
||||
@@ -61,7 +61,11 @@
|
||||
--- Python-3.14.2.orig/Doc/library/ensurepip.rst 2025-12-11 18:11:54.214805989 +0100
|
||||
+++ Python-3.14.2/Doc/library/ensurepip.rst 2025-12-11 18:12:02.573781892 +0100
|
||||
@@ -65,7 +65,11 @@
|
||||
By default, ``pip`` is installed into the current virtual environment
|
||||
(if one is active) or into the system site packages (if there is no
|
||||
active virtual environment). The installation location can be controlled
|
||||
@@ -30,7 +30,7 @@ Index: Python-3.14.0rc1/Doc/library/ensurepip.rst
|
||||
|
||||
.. option:: --root <dir>
|
||||
|
||||
@@ -102,7 +106,7 @@
|
||||
@@ -106,7 +110,7 @@
|
||||
Returns a string specifying the available version of pip that will be
|
||||
installed when bootstrapping an environment.
|
||||
|
||||
@@ -39,7 +39,7 @@ Index: Python-3.14.0rc1/Doc/library/ensurepip.rst
|
||||
altinstall=False, default_pip=False, \
|
||||
verbosity=0)
|
||||
|
||||
@@ -112,6 +116,8 @@
|
||||
@@ -116,6 +120,8 @@
|
||||
If *root* is ``None``, then installation uses the default install location
|
||||
for the current environment.
|
||||
|
||||
@@ -48,7 +48,7 @@ Index: Python-3.14.0rc1/Doc/library/ensurepip.rst
|
||||
*upgrade* indicates whether or not to upgrade an existing installation
|
||||
of an earlier version of ``pip`` to the available version.
|
||||
|
||||
@@ -132,6 +138,8 @@
|
||||
@@ -136,6 +142,8 @@
|
||||
*verbosity* controls the level of output to :data:`sys.stdout` from the
|
||||
bootstrapping operation.
|
||||
|
||||
@@ -57,10 +57,10 @@ Index: Python-3.14.0rc1/Doc/library/ensurepip.rst
|
||||
.. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap
|
||||
|
||||
.. note::
|
||||
Index: Python-3.14.0rc1/Lib/ensurepip/__init__.py
|
||||
Index: Python-3.14.2/Lib/ensurepip/__init__.py
|
||||
===================================================================
|
||||
--- Python-3.14.0rc1.orig/Lib/ensurepip/__init__.py 2025-07-23 10:10:18.541751619 +0200
|
||||
+++ Python-3.14.0rc1/Lib/ensurepip/__init__.py 2025-07-23 10:10:31.690818287 +0200
|
||||
--- Python-3.14.2.orig/Lib/ensurepip/__init__.py 2025-12-11 18:11:54.214805989 +0100
|
||||
+++ Python-3.14.2/Lib/ensurepip/__init__.py 2025-12-11 18:12:02.574381834 +0100
|
||||
@@ -106,27 +106,27 @@
|
||||
os.environ['PIP_CONFIG_FILE'] = os.devnull
|
||||
|
||||
@@ -123,10 +123,10 @@ Index: Python-3.14.0rc1/Lib/ensurepip/__init__.py
|
||||
upgrade=args.upgrade,
|
||||
user=args.user,
|
||||
verbosity=args.verbosity,
|
||||
Index: Python-3.14.0rc1/Lib/test/test_ensurepip.py
|
||||
Index: Python-3.14.2/Lib/test/test_ensurepip.py
|
||||
===================================================================
|
||||
--- Python-3.14.0rc1.orig/Lib/test/test_ensurepip.py 2025-07-23 10:10:19.969641992 +0200
|
||||
+++ Python-3.14.0rc1/Lib/test/test_ensurepip.py 2025-07-23 10:10:31.691217643 +0200
|
||||
--- Python-3.14.2.orig/Lib/test/test_ensurepip.py 2025-12-11 18:11:54.214805989 +0100
|
||||
+++ Python-3.14.2/Lib/test/test_ensurepip.py 2025-12-11 18:12:02.574698987 +0100
|
||||
@@ -100,6 +100,17 @@
|
||||
unittest.mock.ANY,
|
||||
)
|
||||
@@ -145,11 +145,11 @@ Index: Python-3.14.0rc1/Lib/test/test_ensurepip.py
|
||||
def test_bootstrapping_with_user(self):
|
||||
ensurepip.bootstrap(user=True)
|
||||
|
||||
Index: Python-3.14.0rc1/Makefile.pre.in
|
||||
Index: Python-3.14.2/Makefile.pre.in
|
||||
===================================================================
|
||||
--- Python-3.14.0rc1.orig/Makefile.pre.in 2025-07-23 10:10:27.325708066 +0200
|
||||
+++ Python-3.14.0rc1/Makefile.pre.in 2025-07-23 10:10:31.691716104 +0200
|
||||
@@ -2371,7 +2371,7 @@
|
||||
--- Python-3.14.2.orig/Makefile.pre.in 2025-12-11 18:11:58.776792838 +0100
|
||||
+++ Python-3.14.2/Makefile.pre.in 2025-12-11 18:12:02.575189138 +0100
|
||||
@@ -2375,7 +2375,7 @@
|
||||
install|*) ensurepip="" ;; \
|
||||
esac; \
|
||||
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
|
||||
@@ -158,7 +158,7 @@ Index: Python-3.14.0rc1/Makefile.pre.in
|
||||
fi
|
||||
|
||||
.PHONY: altinstall
|
||||
@@ -2382,7 +2382,7 @@
|
||||
@@ -2386,7 +2386,7 @@
|
||||
install|*) ensurepip="--altinstall" ;; \
|
||||
esac; \
|
||||
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
|
||||
@@ -167,9 +167,9 @@ Index: Python-3.14.0rc1/Makefile.pre.in
|
||||
fi
|
||||
|
||||
.PHONY: commoninstall
|
||||
Index: Python-3.14.0rc1/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
|
||||
Index: Python-3.14.2/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.14.0rc1/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst 2025-07-23 10:10:31.692253536 +0200
|
||||
+++ Python-3.14.2/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst 2025-12-11 18:12:02.575697168 +0100
|
||||
@@ -0,0 +1 @@
|
||||
+A directory prefix can now be specified when using :mod:`ensurepip`.
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
Lib/test/test_compile.py | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
Index: Python-3.14.0/Lib/test/test_compile.py
|
||||
Index: Python-3.14.2/Lib/test/test_compile.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Lib/test/test_compile.py 2025-11-06 23:19:11.681015028 +0100
|
||||
+++ Python-3.14.0/Lib/test/test_compile.py 2025-11-06 23:22:47.971267371 +0100
|
||||
--- Python-3.14.2.orig/Lib/test/test_compile.py 2025-12-11 18:10:57.011786647 +0100
|
||||
+++ Python-3.14.2/Lib/test/test_compile.py 2025-12-11 18:12:09.732814688 +0100
|
||||
@@ -24,6 +24,9 @@
|
||||
from test.support.bytecode_helper import instructions_with_positions
|
||||
from test.support.os_helper import FakePath
|
||||
@@ -24,7 +24,7 @@ Index: Python-3.14.0/Lib/test/test_compile.py
|
||||
@support.skip_emscripten_stack_overflow()
|
||||
def test_extended_arg(self):
|
||||
repeat = 100
|
||||
@@ -709,6 +713,7 @@
|
||||
@@ -724,6 +728,7 @@
|
||||
|
||||
@support.cpython_only
|
||||
@unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
|
||||
|
||||
212
gh138498-llvm-version-config.patch
Normal file
212
gh138498-llvm-version-config.patch
Normal file
@@ -0,0 +1,212 @@
|
||||
Index: Python-3.14.0/Tools/jit/README.md
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Tools/jit/README.md
|
||||
+++ Python-3.14.0/Tools/jit/README.md
|
||||
@@ -9,7 +9,7 @@ Python 3.11 or newer is required to buil
|
||||
|
||||
The JIT compiler does not require end users to install any third-party dependencies, but part of it must be *built* using LLVM[^why-llvm]. You are *not* required to build the rest of CPython using LLVM, or even the same version of LLVM (in fact, this is uncommon).
|
||||
|
||||
-LLVM version 19 is required. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-19`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code.
|
||||
+LLVM version 19 is the officially supported version. You can modify if needed using the `LLVM_VERSION` env var during configure. Both `clang` and `llvm-readobj` need to be installed and discoverable (version suffixes, like `clang-19`, are okay). It's highly recommended that you also have `llvm-objdump` available, since this allows the build script to dump human-readable assembly for the generated code.
|
||||
|
||||
It's easy to install all of the required tools:
|
||||
|
||||
Index: Python-3.14.0/Tools/jit/_llvm.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Tools/jit/_llvm.py
|
||||
+++ Python-3.14.0/Tools/jit/_llvm.py
|
||||
@@ -10,8 +10,8 @@ import typing
|
||||
|
||||
import _targets
|
||||
|
||||
-_LLVM_VERSION = 19
|
||||
-_LLVM_VERSION_PATTERN = re.compile(rf"version\s+{_LLVM_VERSION}\.\d+\.\d+\S*\s+")
|
||||
+
|
||||
+_LLVM_VERSION = "19"
|
||||
_EXTERNALS_LLVM_TAG = "llvm-19.1.7.0"
|
||||
|
||||
_P = typing.ParamSpec("_P")
|
||||
@@ -56,53 +56,66 @@ async def _run(tool: str, args: typing.I
|
||||
|
||||
|
||||
@_async_cache
|
||||
-async def _check_tool_version(name: str, *, echo: bool = False) -> bool:
|
||||
+async def _check_tool_version(
|
||||
+ name: str, llvm_version: str, *, echo: bool = False
|
||||
+) -> bool:
|
||||
output = await _run(name, ["--version"], echo=echo)
|
||||
- return bool(output and _LLVM_VERSION_PATTERN.search(output))
|
||||
+ _llvm_version_pattern = re.compile(rf"version\s+{llvm_version}\.\d+\.\d+\S*\s+")
|
||||
+ return bool(output and _llvm_version_pattern.search(output))
|
||||
|
||||
|
||||
@_async_cache
|
||||
-async def _get_brew_llvm_prefix(*, echo: bool = False) -> str | None:
|
||||
- output = await _run("brew", ["--prefix", f"llvm@{_LLVM_VERSION}"], echo=echo)
|
||||
+async def _get_brew_llvm_prefix(llvm_version: str, *, echo: bool = False) -> str | None:
|
||||
+ output = await _run("brew", ["--prefix", f"llvm@{llvm_version}"], echo=echo)
|
||||
return output and output.removesuffix("\n")
|
||||
|
||||
|
||||
@_async_cache
|
||||
-async def _find_tool(tool: str, *, echo: bool = False) -> str | None:
|
||||
+async def _find_tool(tool: str, llvm_version: str, *, echo: bool = False) -> str | None:
|
||||
# Unversioned executables:
|
||||
path = tool
|
||||
- if await _check_tool_version(path, echo=echo):
|
||||
+ if await _check_tool_version(path, llvm_version, echo=echo):
|
||||
return path
|
||||
# Versioned executables:
|
||||
- path = f"{tool}-{_LLVM_VERSION}"
|
||||
- if await _check_tool_version(path, echo=echo):
|
||||
+ path = f"{tool}-{llvm_version}"
|
||||
+ if await _check_tool_version(path, llvm_version, echo=echo):
|
||||
return path
|
||||
# PCbuild externals:
|
||||
externals = os.environ.get("EXTERNALS_DIR", _targets.EXTERNALS)
|
||||
path = os.path.join(externals, _EXTERNALS_LLVM_TAG, "bin", tool)
|
||||
- if await _check_tool_version(path, echo=echo):
|
||||
+ if await _check_tool_version(path, llvm_version, echo=echo):
|
||||
return path
|
||||
# Homebrew-installed executables:
|
||||
- prefix = await _get_brew_llvm_prefix(echo=echo)
|
||||
+ prefix = await _get_brew_llvm_prefix(llvm_version, echo=echo)
|
||||
if prefix is not None:
|
||||
path = os.path.join(prefix, "bin", tool)
|
||||
- if await _check_tool_version(path, echo=echo):
|
||||
+ if await _check_tool_version(path, llvm_version, echo=echo):
|
||||
return path
|
||||
# Nothing found:
|
||||
return None
|
||||
|
||||
|
||||
async def maybe_run(
|
||||
- tool: str, args: typing.Iterable[str], echo: bool = False
|
||||
+ tool: str,
|
||||
+ args: typing.Iterable[str],
|
||||
+ echo: bool = False,
|
||||
+ llvm_version: str = _LLVM_VERSION,
|
||||
) -> str | None:
|
||||
"""Run an LLVM tool if it can be found. Otherwise, return None."""
|
||||
- path = await _find_tool(tool, echo=echo)
|
||||
+
|
||||
+ path = await _find_tool(tool, llvm_version, echo=echo)
|
||||
return path and await _run(path, args, echo=echo)
|
||||
|
||||
|
||||
-async def run(tool: str, args: typing.Iterable[str], echo: bool = False) -> str:
|
||||
+async def run(
|
||||
+ tool: str,
|
||||
+ args: typing.Iterable[str],
|
||||
+ echo: bool = False,
|
||||
+ llvm_version: str = _LLVM_VERSION,
|
||||
+) -> str:
|
||||
"""Run an LLVM tool if it can be found. Otherwise, raise RuntimeError."""
|
||||
- output = await maybe_run(tool, args, echo=echo)
|
||||
+
|
||||
+ output = await maybe_run(tool, args, echo=echo, llvm_version=llvm_version)
|
||||
if output is None:
|
||||
- raise RuntimeError(f"Can't find {tool}-{_LLVM_VERSION}!")
|
||||
+ raise RuntimeError(f"Can't find {tool}-{llvm_version}!")
|
||||
return output
|
||||
Index: Python-3.14.0/Tools/jit/_targets.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Tools/jit/_targets.py
|
||||
+++ Python-3.14.0/Tools/jit/_targets.py
|
||||
@@ -48,6 +48,7 @@ class _Target(typing.Generic[_S, _R]):
|
||||
debug: bool = False
|
||||
verbose: bool = False
|
||||
cflags: str = ""
|
||||
+ llvm_version: str = _llvm._LLVM_VERSION
|
||||
known_symbols: dict[str, int] = dataclasses.field(default_factory=dict)
|
||||
pyconfig_dir: pathlib.Path = pathlib.Path.cwd().resolve()
|
||||
|
||||
@@ -79,7 +80,9 @@ class _Target(typing.Generic[_S, _R]):
|
||||
async def _parse(self, path: pathlib.Path) -> _stencils.StencilGroup:
|
||||
group = _stencils.StencilGroup()
|
||||
args = ["--disassemble", "--reloc", f"{path}"]
|
||||
- output = await _llvm.maybe_run("llvm-objdump", args, echo=self.verbose)
|
||||
+ output = await _llvm.maybe_run(
|
||||
+ "llvm-objdump", args, echo=self.verbose, llvm_version=self.llvm_version
|
||||
+ )
|
||||
if output is not None:
|
||||
# Make sure that full paths don't leak out (for reproducibility):
|
||||
long, short = str(path), str(path.name)
|
||||
@@ -97,7 +100,9 @@ class _Target(typing.Generic[_S, _R]):
|
||||
"--sections",
|
||||
f"{path}",
|
||||
]
|
||||
- output = await _llvm.run("llvm-readobj", args, echo=self.verbose)
|
||||
+ output = await _llvm.run(
|
||||
+ "llvm-readobj", args, echo=self.verbose, llvm_version=self.llvm_version
|
||||
+ )
|
||||
# --elf-output-style=JSON is only *slightly* broken on Mach-O...
|
||||
output = output.replace("PrivateExtern\n", "\n")
|
||||
output = output.replace("Extern\n", "\n")
|
||||
@@ -164,7 +169,9 @@ class _Target(typing.Generic[_S, _R]):
|
||||
# Allow user-provided CFLAGS to override any defaults
|
||||
*shlex.split(self.cflags),
|
||||
]
|
||||
- await _llvm.run("clang", args, echo=self.verbose)
|
||||
+ await _llvm.run(
|
||||
+ "clang", args, echo=self.verbose, llvm_version=self.llvm_version
|
||||
+ )
|
||||
return await self._parse(o)
|
||||
|
||||
async def _build_stencils(self) -> dict[str, _stencils.StencilGroup]:
|
||||
@@ -212,6 +219,8 @@ class _Target(typing.Generic[_S, _R]):
|
||||
if not self.stable:
|
||||
warning = f"JIT support for {self.triple} is still experimental!"
|
||||
request = "Please report any issues you encounter.".center(len(warning))
|
||||
+ if self.llvm_version != _llvm._LLVM_VERSION:
|
||||
+ request = f"Warning! Building with an LLVM version other than {_llvm._LLVM_VERSION} is not supported."
|
||||
outline = "=" * len(warning)
|
||||
print("\n".join(["", outline, warning, request, outline, ""]))
|
||||
digest = f"// {self._compute_digest()}\n"
|
||||
Index: Python-3.14.0/Tools/jit/build.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Tools/jit/build.py
|
||||
+++ Python-3.14.0/Tools/jit/build.py
|
||||
@@ -42,6 +42,7 @@ if __name__ == "__main__":
|
||||
parser.add_argument(
|
||||
"--cflags", help="additional flags to pass to the compiler", default=""
|
||||
)
|
||||
+ parser.add_argument("--llvm-version", help="LLVM version to use")
|
||||
args = parser.parse_args()
|
||||
for target in args.target:
|
||||
target.debug = args.debug
|
||||
@@ -49,6 +50,8 @@ if __name__ == "__main__":
|
||||
target.verbose = args.verbose
|
||||
target.cflags = args.cflags
|
||||
target.pyconfig_dir = args.pyconfig_dir
|
||||
+ if args.llvm_version:
|
||||
+ target.llvm_version = args.llvm_version
|
||||
target.build(
|
||||
comment=comment,
|
||||
force=args.force,
|
||||
Index: Python-3.14.0/configure
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/configure
|
||||
+++ Python-3.14.0/configure
|
||||
@@ -10866,7 +10866,7 @@ then :
|
||||
|
||||
else case e in #(
|
||||
e) as_fn_append CFLAGS_NODIST " $jit_flags"
|
||||
- REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\""
|
||||
+ REGEN_JIT_COMMAND="\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\" --llvm-version=\"$LLVM_VERSION\""
|
||||
JIT_STENCILS_H="jit_stencils.h"
|
||||
if test "x$Py_DEBUG" = xtrue
|
||||
then :
|
||||
Index: Python-3.14.0/configure.ac
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/configure.ac
|
||||
+++ Python-3.14.0/configure.ac
|
||||
@@ -2779,7 +2779,7 @@ AS_VAR_IF([jit_flags],
|
||||
[],
|
||||
[AS_VAR_APPEND([CFLAGS_NODIST], [" $jit_flags"])
|
||||
AS_VAR_SET([REGEN_JIT_COMMAND],
|
||||
- ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\""])
|
||||
+ ["\$(PYTHON_FOR_REGEN) \$(srcdir)/Tools/jit/build.py ${ARCH_TRIPLES:-$host} --output-dir . --pyconfig-dir . --cflags=\"$CFLAGS_JIT\" --llvm-version=\"$LLVM_VERSION\""])
|
||||
AS_VAR_SET([JIT_STENCILS_H], ["jit_stencils.h"])
|
||||
AS_VAR_IF([Py_DEBUG],
|
||||
[true],
|
||||
@@ -4,33 +4,151 @@ Date: Tue, 23 Sep 2025 10:20:16 +0200
|
||||
Subject: [PATCH 1/2] gh-139257: Support docutils >= 0.22
|
||||
|
||||
---
|
||||
Doc/tools/extensions/pyspecific.py | 12 +++++++++++-
|
||||
1 file changed, 11 insertions(+), 1 deletion(-)
|
||||
Doc/tools/extensions/pyspecific.py | 68 +++++++++++++++++++++++++------------
|
||||
1 file changed, 46 insertions(+), 22 deletions(-)
|
||||
|
||||
Index: Python-3.14.0/Doc/tools/extensions/pyspecific.py
|
||||
Index: Python-3.14.2/Doc/tools/extensions/pyspecific.py
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Doc/tools/extensions/pyspecific.py
|
||||
+++ Python-3.14.0/Doc/tools/extensions/pyspecific.py
|
||||
@@ -25,11 +25,21 @@ from sphinx.util.docutils import SphinxD
|
||||
SOURCE_URI = 'https://github.com/python/cpython/tree/3.14/%s'
|
||||
--- Python-3.14.2.orig/Doc/tools/extensions/pyspecific.py 2025-12-05 17:49:16.000000000 +0100
|
||||
+++ Python-3.14.2/Doc/tools/extensions/pyspecific.py 2025-12-11 18:15:44.936875242 +0100
|
||||
@@ -1,12 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
- pyspecific.py
|
||||
- ~~~~~~~~~~~~~
|
||||
+pyspecific.py
|
||||
+~~~~~~~~~~~~~
|
||||
|
||||
# monkey-patch reST parser to disable alphabetic and roman enumerated lists
|
||||
- Sphinx extension with Python doc-specific markup.
|
||||
+Sphinx extension with Python doc-specific markup.
|
||||
|
||||
- :copyright: 2008-2014 by Georg Brandl.
|
||||
- :license: Python license.
|
||||
+:copyright: 2008-2014 by Georg Brandl.
|
||||
+:license: Python license.
|
||||
"""
|
||||
|
||||
import re
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
from docutils import nodes
|
||||
from docutils.parsers.rst import directives
|
||||
+from docutils.parsers.rst.states import Body
|
||||
from docutils.utils import unescape
|
||||
from sphinx import addnodes
|
||||
from sphinx.domains.python import PyFunction, PyMethod, PyModule
|
||||
@@ -22,30 +23,48 @@
|
||||
from sphinx.util.docutils import SphinxDirective
|
||||
|
||||
# Used in conf.py and updated here by python/release-tools/run_release.py
|
||||
-SOURCE_URI = 'https://github.com/python/cpython/tree/3.14/%s'
|
||||
+SOURCE_URI = "https://github.com/python/cpython/tree/3.14/%s"
|
||||
+
|
||||
+
|
||||
+# monkey-patch reST parser to disable alphabetic and roman enumerated lists
|
||||
+def _disable_alphabetic_and_roman(text):
|
||||
+ try:
|
||||
+ # docutils >= 0.22
|
||||
+ from docutils.parsers.rst.states import InvalidRomanNumeralError
|
||||
+
|
||||
+ raise InvalidRomanNumeralError(text)
|
||||
+ except ImportError:
|
||||
+ # docutils < 0.22
|
||||
+ return None
|
||||
+
|
||||
+
|
||||
from docutils.parsers.rst.states import Body
|
||||
Body.enum.converters['loweralpha'] = \
|
||||
Body.enum.converters['upperalpha'] = \
|
||||
Body.enum.converters['lowerroman'] = \
|
||||
- Body.enum.converters['upperroman'] = lambda x: None
|
||||
+ Body.enum.converters['upperroman'] = _disable_alphabetic_and_roman
|
||||
|
||||
+Body.enum.converters["loweralpha"] = Body.enum.converters["upperalpha"] = (
|
||||
+ Body.enum.converters["lowerroman"]
|
||||
+) = Body.enum.converters["upperroman"] = _disable_alphabetic_and_roman
|
||||
+
|
||||
|
||||
class PyAwaitableMixin(object):
|
||||
def handle_signature(self, sig, signode):
|
||||
ret = super(PyAwaitableMixin, self).handle_signature(sig, signode)
|
||||
- signode.insert(0, addnodes.desc_annotation('awaitable ', 'awaitable '))
|
||||
+ signode.insert(0, addnodes.desc_annotation("awaitable ", "awaitable "))
|
||||
return ret
|
||||
|
||||
|
||||
class PyAwaitableFunction(PyAwaitableMixin, PyFunction):
|
||||
def run(self):
|
||||
- self.name = 'py:function'
|
||||
+ self.name = "py:function"
|
||||
return PyFunction.run(self)
|
||||
|
||||
|
||||
class PyAwaitableMethod(PyAwaitableMixin, PyMethod):
|
||||
def run(self):
|
||||
- self.name = 'py:method'
|
||||
+ self.name = "py:method"
|
||||
return PyMethod.run(self)
|
||||
|
||||
|
||||
# Support for documenting Opcodes
|
||||
|
||||
-opcode_sig_re = re.compile(r'(\w+(?:\+\d)?)(?:\s*\((.*)\))?')
|
||||
+opcode_sig_re = re.compile(r"(\w+(?:\+\d)?)(?:\s*\((.*)\))?")
|
||||
|
||||
|
||||
def parse_opcode_signature(env, sig, signode):
|
||||
@@ -64,7 +83,7 @@
|
||||
|
||||
# Support for documenting pdb commands
|
||||
|
||||
-pdbcmd_sig_re = re.compile(r'([a-z()!]+)\s*(.*)')
|
||||
+pdbcmd_sig_re = re.compile(r"([a-z()!]+)\s*(.*)")
|
||||
|
||||
# later...
|
||||
# pdbargs_tokens_re = re.compile(r'''[a-zA-Z]+ | # identifiers
|
||||
@@ -80,16 +99,16 @@
|
||||
if m is None:
|
||||
raise ValueError
|
||||
name, args = m.groups()
|
||||
- fullname = name.replace('(', '').replace(')', '')
|
||||
+ fullname = name.replace("(", "").replace(")", "")
|
||||
signode += addnodes.desc_name(name, name)
|
||||
if args:
|
||||
- signode += addnodes.desc_addname(' '+args, ' '+args)
|
||||
+ signode += addnodes.desc_addname(" " + args, " " + args)
|
||||
return fullname
|
||||
|
||||
|
||||
def parse_monitoring_event(env, sig, signode):
|
||||
"""Transform a monitoring event signature into RST nodes."""
|
||||
- signode += addnodes.desc_addname('sys.monitoring.events.', 'sys.monitoring.events.')
|
||||
+ signode += addnodes.desc_addname("sys.monitoring.events.", "sys.monitoring.events.")
|
||||
signode += addnodes.desc_name(sig, sig)
|
||||
return sig
|
||||
|
||||
@@ -102,7 +121,7 @@
|
||||
As such, we link this to ``env-check-consistency``, even though it has
|
||||
nothing to do with the environment consistency check.
|
||||
"""
|
||||
- if app.builder.name != 'gettext':
|
||||
+ if app.builder.name != "gettext":
|
||||
return
|
||||
|
||||
# allow translating deprecated index entries
|
||||
@@ -119,10 +138,15 @@
|
||||
|
||||
|
||||
def setup(app):
|
||||
- app.add_object_type('opcode', 'opcode', '%s (opcode)', parse_opcode_signature)
|
||||
- app.add_object_type('pdbcommand', 'pdbcmd', '%s (pdb command)', parse_pdb_command)
|
||||
- app.add_object_type('monitoring-event', 'monitoring-event', '%s (monitoring event)', parse_monitoring_event)
|
||||
- app.add_directive_to_domain('py', 'awaitablefunction', PyAwaitableFunction)
|
||||
- app.add_directive_to_domain('py', 'awaitablemethod', PyAwaitableMethod)
|
||||
- app.connect('env-check-consistency', patch_pairindextypes)
|
||||
- return {'version': '1.0', 'parallel_read_safe': True}
|
||||
+ app.add_object_type("opcode", "opcode", "%s (opcode)", parse_opcode_signature)
|
||||
+ app.add_object_type("pdbcommand", "pdbcmd", "%s (pdb command)", parse_pdb_command)
|
||||
+ app.add_object_type(
|
||||
+ "monitoring-event",
|
||||
+ "monitoring-event",
|
||||
+ "%s (monitoring event)",
|
||||
+ parse_monitoring_event,
|
||||
+ )
|
||||
+ app.add_directive_to_domain("py", "awaitablefunction", PyAwaitableFunction)
|
||||
+ app.add_directive_to_domain("py", "awaitablemethod", PyAwaitableMethod)
|
||||
+ app.connect("env-check-consistency", patch_pairindextypes)
|
||||
+ return {"version": "1.0", "parallel_read_safe": True}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
Makefile.pre.in | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
Index: Python-3.14.0/Makefile.pre.in
|
||||
Index: Python-3.14.2/Makefile.pre.in
|
||||
===================================================================
|
||||
--- Python-3.14.0.orig/Makefile.pre.in 2025-10-07 11:34:52.000000000 +0200
|
||||
+++ Python-3.14.0/Makefile.pre.in 2025-11-06 23:19:25.434995608 +0100
|
||||
@@ -1910,6 +1910,11 @@
|
||||
--- Python-3.14.2.orig/Makefile.pre.in 2025-12-11 18:11:54.290805770 +0100
|
||||
+++ Python-3.14.2/Makefile.pre.in 2025-12-11 18:11:58.776792838 +0100
|
||||
@@ -1914,6 +1914,11 @@
|
||||
-DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \
|
||||
-o $@ $(srcdir)/Modules/getbuildinfo.c
|
||||
|
||||
|
||||
4
python314-base.rpmlintrc
Normal file
4
python314-base.rpmlintrc
Normal file
@@ -0,0 +1,4 @@
|
||||
addFilter("pem-certificate.*/usr/lib.*/python.*/test/*.pem")
|
||||
addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/tests/*.c")
|
||||
addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/test/*.cpp")
|
||||
addFilter("python-bytecode-inconsistent-mtime.*/usr/lib.*/python.*/*.pyc")
|
||||
@@ -1,3 +1,619 @@
|
||||
-------------------------------------------------------------------
|
||||
Thu Dec 12 07:00:00 UTC 2025 - Daniel Garcia <daniel.garcia@suse.com>
|
||||
|
||||
- Use LLVM21 to build python314, add patch
|
||||
gh138498-llvm-version-config.patch
|
||||
bsc#1254826, gh#python/cpython#138498
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Dec 11 17:37:09 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
* Update to 3.14.2:
|
||||
- Security
|
||||
- gh-142145: Remove quadratic behavior in xml.minidom node ID
|
||||
cache clearing.
|
||||
- gh-119452: Fix a potential memory denial of service in the
|
||||
http.server module. When a malicious user is connected to the
|
||||
CGI server on Windows, it could cause an arbitrary amount of
|
||||
memory to be allocated. This could have led to symptoms
|
||||
including a MemoryError, swapping, out of memory (OOM) killed
|
||||
processes or containers, or even system crashes.
|
||||
- Library
|
||||
- gh-140797: Revert changes to the undocumented re.Scanner
|
||||
class. Capturing groups are still allowed for backward
|
||||
compatibility, although using them can lead to incorrect
|
||||
result. They will be forbidden in future Python versions.
|
||||
- gh-142206: The resource tracker in the multiprocessing module
|
||||
now uses the original communication protocol, as in Python
|
||||
3.14.0 and below, by default. This avoids issues with
|
||||
upgrading Python while it is running. (Note that such
|
||||
‘in-place’ upgrades are not tested.) The tracker remains
|
||||
compatible with subprocesses that use new protocol (that is,
|
||||
subprocesses using Python 3.13.10, 3.14.1 and 3.15).
|
||||
- gh-142214: Fix two regressions in dataclasses in Python
|
||||
3.14.1 related to annotations. An exception is no longer
|
||||
raised if slots=True is used and the __init__ method does not
|
||||
have an __annotate__ attribute (likely because init=False was
|
||||
used). An exception is no longer raised if annotations are
|
||||
requested on the __init__ method and one of the fields is not
|
||||
present in the class annotations. This can occur in certain
|
||||
dynamic scenarios. Patch by Jelle Zijlstra.
|
||||
- Core and Builtins
|
||||
- gh-142218: Fix crash when inserting into a split table
|
||||
dictionary with a non str key that matches an existing key.
|
||||
- gh-116738: Fix cmath data race when initializing
|
||||
trigonometric tables with subinterpreters.
|
||||
* Update to 3.14.1:
|
||||
- Tools/Demos
|
||||
- gh-141692: Each slice of an iOS XCframework now contains
|
||||
a lib folder that contains a symlink to the libpython dylib.
|
||||
This allows binary modules to be compiled for iOS using
|
||||
dynamic libreary linking, rather than Framework linking.
|
||||
- gh-141442: The iOS testbed now correctly handles test
|
||||
arguments that contain spaces.
|
||||
- gh-140702: The iOS testbed app will now expose the
|
||||
GITHUB_ACTIONS environment variable to iOS apps being tested.
|
||||
- gh-137484: Have Tools/wasm/wasi put the build Python into
|
||||
a directory named after the build triple instead of “build”.
|
||||
- gh-137248: Add a --logdir option to Tools/wasm/wasi for
|
||||
specifying where to write log files.
|
||||
- gh-137243: Have Tools/wasm/wasi detect a WASI SDK install in
|
||||
/opt when it was directly extracted from a release tarball.
|
||||
- Tests
|
||||
- gh-140482: Preserve and restore the state of stty echo as
|
||||
part of the test environment.
|
||||
- gh-140082: Update python -m test to set FORCE_COLOR=1 when
|
||||
being run with color enabled so that unittest which is run by
|
||||
it with redirected output will output in color.
|
||||
- gh-139208: Fix regrtest --fast-ci --verbose: don’t ignore the
|
||||
--verbose option anymore. Patch by Victor Stinner.
|
||||
- gh-136442: Use exitcode 1 instead of 5 if
|
||||
unittest.TestCase.setUpClass() raises an exception
|
||||
- Security
|
||||
- gh-139700: Check consistency of the zip64 end of central
|
||||
directory record. Support records with “zip64 extensible
|
||||
data” if there are no bytes prepended to the ZIP file.
|
||||
- gh-139283: sqlite3: correctly handle maximum number of rows
|
||||
to fetch in Cursor.fetchmany and reject negative values for
|
||||
Cursor.arraysize. Patch by Bénédikt Tran. (CVE-2025-8291,
|
||||
bsc#1251305)
|
||||
- gh-137836: Add support of the “plaintext” element, RAWTEXT
|
||||
elements “xmp”, “iframe”, “noembed” and “noframes”, and
|
||||
optionally RAWTEXT element “noscript” in
|
||||
html.parser.HTMLParser.
|
||||
- gh-136063: email.message: ensure linear complexity for legacy
|
||||
HTTP parameters parsing. Patch by Bénédikt Tran.
|
||||
- gh-136065: Fix quadratic complexity in os.path.expandvars()
|
||||
(CVE-2025-6075, bsc#1252974)
|
||||
- gh-119451: Fix a potential memory denial of service in the
|
||||
http.client module. When connecting to a malicious server, it
|
||||
could cause an arbitrary amount of memory to be allocated.
|
||||
This could have led to symptoms including a MemoryError,
|
||||
swapping, out of memory (OOM) killed processes or containers,
|
||||
or even system crashes (CVE-2025-13836, bsc#1254400)
|
||||
- gh-119342: Fix a potential memory denial of service in the
|
||||
plistlib module. When reading a Plist file received from
|
||||
untrusted source, it could cause an arbitrary amount of
|
||||
memory to be allocated. This could have led to symptoms
|
||||
including a MemoryError, swapping, out of memory (OOM) killed
|
||||
processes or containers, or even system crashes
|
||||
(CVE-2025-13837, bsc#1254401).
|
||||
- Library
|
||||
- gh-74389: When the stdin being used by a subprocess.Popen
|
||||
instance is closed, this is now ignored in
|
||||
subprocess.Popen.communicate() instead of leaving the class
|
||||
in an inconsistent state.
|
||||
- gh-87512: Fix subprocess.Popen.communicate() timeout handling
|
||||
on Windows when writing large input. Previously, the timeout
|
||||
was ignored during stdin writing, causing the method to block
|
||||
indefinitely if the child process did not consume input
|
||||
quickly. The stdin write is now performed in a background
|
||||
thread, allowing the timeout to be properly enforced.
|
||||
- gh-141473: When subprocess.Popen.communicate() was called
|
||||
with input and a timeout and is called for a second time
|
||||
after a TimeoutExpired exception before the process has died,
|
||||
it should no longer hang.
|
||||
- gh-59000: Fix pdb breakpoint resolution for class methods
|
||||
when the module defining the class is not imported.
|
||||
- gh-141570: Support file-like object raising OSError from
|
||||
fileno() in color detection (_colorize.can_colorize()). This
|
||||
can occur when sys.stdout is redirected.
|
||||
- gh-141659: Fix bad file descriptor errors from
|
||||
_posixsubprocess on AIX.
|
||||
- gh-141600: Fix musl version detection on Void Linux.
|
||||
- gh-141497: ipaddress: ensure that the methods
|
||||
IPv4Network.hosts() and IPv6Network.hosts() always return an
|
||||
iterator.
|
||||
- gh-140938: The statistics.stdev() and statistics.pstdev()
|
||||
functions now raise a ValueError when the input contains an
|
||||
infinity or a NaN.
|
||||
- gh-124111: Updated Tcl threading configuration in _tkinter to
|
||||
assume that threads are always available in Tcl 9 and later.
|
||||
- gh-137109: The os.fork and related forking APIs will no
|
||||
longer warn in the common case where Linux or macOS platform
|
||||
APIs return the number of threads in a process and find the
|
||||
answer to be 1 even when a os.register_at_fork()
|
||||
after_in_parent= callback (re)starts a thread.
|
||||
- gh-141314: Fix assertion failure in io.TextIOWrapper.tell()
|
||||
when reading files with standalone carriage return (\r) line
|
||||
endings.
|
||||
- gh-141311: Fix assertion failure in io.BytesIO.readinto() and
|
||||
undefined behavior arising when read position is above
|
||||
capcity in io.BytesIO.
|
||||
- gh-141141: Fix a thread safety issue with base64.b85decode().
|
||||
Contributed by Benel Tayar.
|
||||
- gh-137969: Fix annotationlib.ForwardRef.evaluate() returning
|
||||
ForwardRef objects which don’t update with new globals.
|
||||
- gh-140911: collections: Ensure that the methods
|
||||
UserString.rindex() and UserString.index() accept
|
||||
collections.UserString instances as the sub argument.
|
||||
- gh-140797: The undocumented re.Scanner class now forbids
|
||||
regular expressions containing capturing groups in its
|
||||
lexicon patterns. Patterns using capturing groups could
|
||||
previously lead to crashes with segmentation fault. Use
|
||||
non-capturing groups (?:…) instead.
|
||||
- gh-125115: Refactor the pdb parsing issue so positional
|
||||
arguments can pass through intuitively.
|
||||
- gh-140815: faulthandler now detects if a frame or a code
|
||||
object is invalid or freed. Patch by Victor Stinner.
|
||||
- gh-100218: Correctly set errno when socket.if_nametoindex()
|
||||
or socket.if_indextoname() raise an OSError. Patch by
|
||||
Bénédikt Tran.
|
||||
- gh-140875: Fix handling of unclosed character references
|
||||
(named and numerical) followed by the end of file in
|
||||
html.parser.HTMLParser with convert_charrefs=False.
|
||||
- gh-140734: multiprocessing: fix off-by-one error when
|
||||
checking the length of a temporary socket file path. Patch by
|
||||
Bénédikt Tran.
|
||||
- gh-140874: Bump the version of pip bundled in ensurepip to
|
||||
version 25.3
|
||||
- gh-140691: In urllib.request, when opening a FTP URL fails
|
||||
because a data connection cannot be made, the control
|
||||
connection’s socket is now closed to avoid a ResourceWarning.
|
||||
- gh-103847: Fix hang when cancelling process created by
|
||||
asyncio.create_subprocess_exec() or
|
||||
asyncio.create_subprocess_shell(). Patch by Kumar Aditya.
|
||||
- gh-120057: Add os.reload_environ() to os.__all__.
|
||||
- gh-140228: Avoid making unnecessary filesystem calls for
|
||||
frozen modules in linecache when the global module cache is
|
||||
not present.
|
||||
- gh-140590: Fix arguments checking for the
|
||||
functools.partial.__setstate__() that may lead to internal
|
||||
state corruption and crash. Patch by Sergey Miryanov.
|
||||
- gh-125434: Display thread name in faulthandler on Windows.
|
||||
Patch by Victor Stinner.
|
||||
- gh-140634: Fix a reference counting bug in
|
||||
os.sched_param.__reduce__().
|
||||
- gh-140633: Ignore AttributeError when setting a module’s
|
||||
__file__ attribute when loading an extension module packaged
|
||||
as Apple Framework.
|
||||
- gh-140593: xml.parsers.expat: Fix a memory leak that could
|
||||
affect users with ElementDeclHandler() set to a custom
|
||||
element declaration handler. Patch by Sebastian Pipping.
|
||||
- gh-140607: Inside io.RawIOBase.read(), validate that the
|
||||
count of bytes returned by io.RawIOBase.readinto() is valid
|
||||
(inside the provided buffer).
|
||||
- gh-138162: Fix logging.LoggerAdapter with merge_extra=True
|
||||
and without the extra argument.
|
||||
- gh-138774: ast.unparse() now generates full source code when
|
||||
handling ast.Interpolation nodes that do not have a specified
|
||||
source.
|
||||
- gh-140474: Fix memory leak in array.array when creating
|
||||
arrays from an empty str and the u type code.
|
||||
- gh-137530: dataclasses Fix annotations for generated __init__
|
||||
methods by replacing the annotations that were in-line in the
|
||||
generated source code with __annotate__ functions attached to
|
||||
the methods.
|
||||
- gh-140348: Fix regression in Python 3.14.0 where using the
|
||||
| operator on a typing.Union object combined with an object
|
||||
that is not a type would raise an error.
|
||||
- gh-140272: Fix memory leak in the clear() method of the
|
||||
dbm.gnu database.
|
||||
- gh-140041: Fix import of ctypes on Android and Cygwin when
|
||||
ABI flags are present.
|
||||
- gh-140120: Fixed a memory leak in hmac when it was using the
|
||||
hacl-star backend. Discovered by @ashm-dev using
|
||||
AddressSanitizer.
|
||||
- gh-139905: Add suggestion to error message for typing.Generic
|
||||
subclasses when cls.__parameters__ is missing due to a parent
|
||||
class failing to call super().__init_subclass__() in its
|
||||
__init_subclass__.
|
||||
- gh-139894: Fix incorrect sharing of current task with the
|
||||
child process while forking in asyncio. Patch by Kumar
|
||||
Aditya.
|
||||
- gh-139845: Fix to not print KeyboardInterrupt twice in
|
||||
default asyncio REPL.
|
||||
- gh-139783: Fix inspect.getsourcelines() for the case when
|
||||
a decorator is followed by a comment or an empty line.
|
||||
- gh-139809: Prevent premature colorization of subparser prog
|
||||
in argparse.ArgumentParser.add_subparsers() to respect color
|
||||
environment variable changes after parser creation.
|
||||
- gh-139736: Fix excessive indentation in the default argparse
|
||||
HelpFormatter. Patch by Alexander Edland.
|
||||
- gh-70765: http.server: fix default handling of HTTP/0.9
|
||||
requests in BaseHTTPRequestHandler. Previously,
|
||||
BaseHTTPRequestHandler.parse_request() incorrectly waited for
|
||||
headers in the request although those are not supported in
|
||||
HTTP/0.9. Patch by Bénédikt Tran.
|
||||
- gh-63161: Fix tokenize.detect_encoding(). Support non-UTF-8
|
||||
shebang and comments if non-UTF-8 encoding is specified.
|
||||
Detect decoding error for non-UTF-8 encoding. Detect null
|
||||
bytes in source code.
|
||||
- gh-139391: Fix an issue when, on non-Windows platforms, it
|
||||
was not possible to gracefully exit a python -m asyncio
|
||||
process suspended by Ctrl+Z and later resumed by fg other
|
||||
than with kill.
|
||||
- gh-101828: Fix 'shift_jisx0213', 'shift_jis_2004',
|
||||
'euc_jisx0213' and 'euc_jis_2004' codecs truncating null
|
||||
chars as they were treated as part of multi-character
|
||||
sequences.
|
||||
- gh-139289: Do a real lazy-import on rlcompleter in pdb and
|
||||
restore the existing completer after importing rlcompleter.
|
||||
- gh-139246: fix: paste zero-width in default repl width is
|
||||
wrong.
|
||||
- gh-90949: Add SetAllocTrackerActivationThreshold() and
|
||||
SetAllocTrackerMaximumAmplification() to xmlparser objects to
|
||||
prevent use of disproportional amounts of dynamic memory from
|
||||
within an Expat parser. Patch by Bénédikt Tran.
|
||||
- gh-139210: Fix use-after-free when reporting unknown event in
|
||||
xml.etree.ElementTree.iterparse(). Patch by Ken Jin.
|
||||
- gh-138860: Lazy import rlcompleter in pdb to avoid deadlock
|
||||
in subprocess.
|
||||
- gh-112729: Fix crash when calling
|
||||
concurrent.interpreters.create() when the process is out of
|
||||
memory.
|
||||
- gh-135729: Fix unraisable exception during finalization when
|
||||
using concurrent.interpreters in the REPL.
|
||||
- gh-139076: Fix a bug in the pydoc module that was hiding
|
||||
functions in a Python module if they were implemented in an
|
||||
extension module and the module did not have __all__.
|
||||
- gh-139065: Fix trailing space before a wrapped long word if
|
||||
the line length is exactly width in textwrap.
|
||||
- gh-139001: Fix race condition in pathlib.Path on the internal
|
||||
_raw_paths field.
|
||||
- gh-138813: multiprocessing.BaseProcess defaults kwargs to
|
||||
None instead of a shared dictionary.
|
||||
- gh-138993: Dedent credits text.
|
||||
- gh-138891: Fix SyntaxError when inspect.get_annotations(f,
|
||||
eval_str=True) is called on a function annotated with a PEP
|
||||
646 star_expression
|
||||
- gh-130567: Fix possible crash in locale.strxfrm() due to
|
||||
a platform bug on macOS.
|
||||
- gh-138859: Fix generic type parameterization raising
|
||||
a TypeError when omitting a ParamSpec that has a default
|
||||
which is not a list of types.
|
||||
- gh-138764: Prevent annotationlib.call_annotate_function()
|
||||
from calling __annotate__ functions that don’t support
|
||||
VALUE_WITH_FAKE_GLOBALS in a fake globals namespace with
|
||||
empty globals. Make FORWARDREF and STRING annotations fall
|
||||
back to using VALUE annotations in the case that neither
|
||||
their own format, nor VALUE_WITH_FAKE_GLOBALS are supported.
|
||||
- gh-138775: Use of python -m with base64 has been fixed to
|
||||
detect input from a terminal so that it properly notices EOF.
|
||||
- gh-138779: Support device numbers larger than 2**63-1 for the
|
||||
st_rdev field of the os.stat_result structure.
|
||||
- gh-137706: Fix the partial evaluation of annotations that use
|
||||
typing.Annotated[T, x] where T is a forward reference.
|
||||
- gh-88375: Fix normalization of the robots.txt rules and URLs
|
||||
in the urllib.robotparser module. No longer ignore trailing
|
||||
?. Distinguish raw special characters ?, = and & from the
|
||||
percent-encoded ones.
|
||||
- gh-111788: Fix parsing errors in the urllib.robotparser
|
||||
module. Don’t fail trying to parse weird paths. Don’t fail
|
||||
trying to decode non-UTF-8 robots.txt files.
|
||||
- gh-98896: Fix a failure in multiprocessing resource_tracker
|
||||
when SharedMemory names contain colons. Patch by Rani
|
||||
Pinchuk.
|
||||
- gh-138425: Fix partial evaluation of annotationlib.ForwardRef
|
||||
objects which rely on names defined as globals.
|
||||
- gh-138432: zoneinfo.reset_tzpath() will now convert any
|
||||
os.PathLike objects it receives into strings before adding
|
||||
them to TZPATH. It will raise TypeError if anything other
|
||||
than a string is found after this conversion. If given an
|
||||
os.PathLike object that represents a relative path, it will
|
||||
now raise ValueError instead of TypeError, and present a more
|
||||
informative error message.
|
||||
- gh-138008: Fix segmentation faults in the ctypes module due
|
||||
to invalid argtypes. Patch by Dung Nguyen.
|
||||
- gh-60462: Fix locale.strxfrm() on Solaris (and possibly other
|
||||
platforms).
|
||||
- gh-138239: The REPL now highlights type as a soft keyword in
|
||||
type statements.
|
||||
- gh-138204: Forbid expansion of shared anonymous memory maps
|
||||
on Linux, which caused a bus error.
|
||||
- gh-138010: Fix an issue where defining a class with an
|
||||
@warnings.deprecated-decorated base class may not invoke the
|
||||
correct __init_subclass__() method in cases involving
|
||||
multiple inheritance. Patch by Brian Schubert.
|
||||
- gh-138151: In annotationlib, improve evaluation of forward
|
||||
references to nonlocal variables that are not yet defined
|
||||
when the annotations are initially evaluated.
|
||||
- gh-137317: inspect.signature() now correctly handles classes
|
||||
that use a descriptor on a wrapped __init__() or __new__()
|
||||
method. Contributed by Yongyu Yan.
|
||||
- gh-137754: Fix import of the zoneinfo module if the
|
||||
C implementation of the datetime module is not available.
|
||||
- gh-137490: Handle ECANCELED in the same way as EINTR in
|
||||
signal.sigwaitinfo() on NetBSD.
|
||||
- gh-137477: Fix inspect.getblock(), inspect.getsourcelines()
|
||||
and inspect.getsource() for generator expressions.
|
||||
- gh-137044: Return large limit values as positive integers
|
||||
instead of negative integers in resource.getrlimit(). Accept
|
||||
large values and reject negative values (except
|
||||
RLIM_INFINITY) for limits in resource.setrlimit().
|
||||
- gh-75989: tarfile.TarFile.extractall() and
|
||||
tarfile.TarFile.extract() now overwrite symlinks when
|
||||
extracting hardlinks. (Contributed by Alexander Enrique
|
||||
Urieles Nieto in gh-75989.)
|
||||
- gh-137017: Fix threading.Thread.is_alive to remain True until
|
||||
the underlying OS thread is fully cleaned up. This avoids
|
||||
false negatives in edge cases involving thread monitoring or
|
||||
premature threading.Thread.is_alive calls.
|
||||
- gh-137273: Fix debug assertion failure in locale.setlocale()
|
||||
on Windows.
|
||||
- gh-137239: heapq: Update heapq.__all__ with *_max functions.
|
||||
- gh-81325: tarfile.TarFile now accepts a path-like when
|
||||
working on a tar archive. (Contributed by Alexander Enrique
|
||||
Urieles Nieto in gh-81325.)
|
||||
- gh-137185: Fix a potential async-signal-safety issue in
|
||||
faulthandler when printing C stack traces.
|
||||
- gh-136914: Fix retrieval of doctest.DocTest.lineno for
|
||||
objects decorated with functools.cache() or
|
||||
functools.cached_property.
|
||||
- gh-136912: hmac.digest() now properly handles large keys and
|
||||
messages by falling back to the pure Python implementation
|
||||
when necessary. Patch by Bénédikt Tran.
|
||||
- gh-83424: Allows creating a ctypes.CDLL without name when
|
||||
passing a handle as an argument.
|
||||
- gh-136234: Fix asyncio.WriteTransport.writelines() to be
|
||||
robust to connection failure, by using the same behavior as
|
||||
write().
|
||||
- gh-136507: Fix mimetypes CLI to handle multiple file
|
||||
parameters.
|
||||
- gh-136057: Fixed the bug in pdb and bdb where next and step
|
||||
can’t go over the line if a loop exists in the line.
|
||||
- gh-135386: Fix opening a dbm.sqlite3 database for reading
|
||||
from read-only file or directory.
|
||||
- gh-135444: Fix asyncio.DatagramTransport.sendto() to account
|
||||
for datagram header size when data cannot be sent.
|
||||
- gh-126631: Fix multiprocessing forkserver bug which prevented
|
||||
__main__ from being preloaded.
|
||||
- gh-135307: email: Fix exception in set_content() when
|
||||
encoding text and max_line_length is set to 0 or None
|
||||
(unlimited).
|
||||
- gh-134453: Fixed subprocess.Popen.communicate() input=
|
||||
handling of memoryview instances that were non-byte shaped on
|
||||
POSIX platforms. Those are now properly cast to a byte shaped
|
||||
view instead of truncating the input. Windows platforms did
|
||||
not have this bug.
|
||||
- gh-134698: Fix a crash when calling methods of ssl.SSLContext
|
||||
or ssl.SSLSocket across multiple threads.
|
||||
- gh-125996: Fix thread safety of collections.OrderedDict.
|
||||
Patch by Kumar Aditya.
|
||||
- gh-133789: Fix unpickling of pathlib objects that were
|
||||
pickled in Python 3.13.
|
||||
- gh-127081: Fix libc thread safety issues with dbm by
|
||||
performing stateful operations in critical sections.
|
||||
- gh-132551: Make io.BytesIO safe in free-threaded build.
|
||||
- gh-131788: Make ResourceTracker.send from multiprocessing
|
||||
re-entrant safe
|
||||
- gh-118981: Fix potential hang in
|
||||
multiprocessing.popen_spawn_posix that can happen when the
|
||||
child proc dies early by closing the child fds right away.
|
||||
- gh-102431: Clarify constraints for “logical” arguments in
|
||||
methods of decimal.Context.
|
||||
- gh-78319: UTF8 support for the IMAP APPEND command has been
|
||||
made RFC compliant. bpo-38735: Fix failure when importing
|
||||
a module from the root directory on unix-like platforms with
|
||||
sys.pycache_prefix set. bpo-41839: Allow negative priority
|
||||
values from os.sched_get_priority_min() and
|
||||
os.sched_get_priority_max() functions.
|
||||
- IDLE
|
||||
- gh-96491: Deduplicate version number in IDLE shell title bar
|
||||
after saving to a file.
|
||||
- gh-139742: Colorize t-string prefixes for template strings in
|
||||
IDLE, as done for f-string prefixes.
|
||||
- Documentation
|
||||
- gh-141994: xml.sax.handler: Make Documentation of
|
||||
xml.sax.handler.feature_external_ges warn of opening up to
|
||||
external entity attacks. Patch by Sebastian Pipping.
|
||||
- gh-140578: Remove outdated sencence in the documentation for
|
||||
multiprocessing, that implied that
|
||||
concurrent.futures.ThreadPoolExecutor did not exist.
|
||||
- Core and Builtins
|
||||
- gh-142048: Fix quadratically increasing garbage collection
|
||||
delays in free-threaded build.
|
||||
- gh-116738: Fix thread safety issue with re scanner objects in
|
||||
free-threaded builds.
|
||||
- gh-141930: When importing a module, use Python’s regular file
|
||||
object to ensure that writes to .pyc files are complete or an
|
||||
appropriate error is raised.
|
||||
- gh-120158: Fix inconsistent state when enabling or disabling
|
||||
monitoring events too many times.
|
||||
- gh-139653: Only raise a RecursionError or trigger a fatal
|
||||
error if the stack pointer is both below the limit pointer
|
||||
and above the stack base. If outside of these bounds assume
|
||||
that it is OK. This prevents false positives when user-space
|
||||
threads swap stacks.
|
||||
- gh-139103: Improve multithreaded scaling of dataclasses on
|
||||
the free-threaded build.
|
||||
- gh-141579: Fix sys.activate_stack_trampoline() to properly
|
||||
support the perf_jit backend. Patch by Pablo Galindo.
|
||||
- gh-114203: Skip locking if object is already locked by
|
||||
two-mutex critical section.
|
||||
- gh-141528: Suggest using
|
||||
concurrent.interpreters.Interpreter.close() instead of the
|
||||
private _interpreters.destroy function when warning about
|
||||
remaining subinterpreters. Patch by Sergey Miryanov.
|
||||
- gh-141312: Fix the assertion failure in the __setstate__
|
||||
method of the range iterator when a non-integer argument is
|
||||
passed. Patch by Sergey Miryanov.
|
||||
- gh-116738: Make csv module thread-safe on the free threaded
|
||||
build.
|
||||
- gh-140939: Fix memory leak when bytearray or bytes is
|
||||
formated with the %*b format with a large width that results
|
||||
in a MemoryError.
|
||||
- gh-140260: Fix struct data race in endian table
|
||||
initialization with subinterpreters. Patch by Shamil
|
||||
Abdulaev.
|
||||
- gh-140530: Fix a reference leak when raise exc from cause
|
||||
fails. Patch by Bénédikt Tran.
|
||||
- gh-140373: Correctly emit PY_UNWIND event when generator
|
||||
object is closed. Patch by Mikhail Efimov.
|
||||
- gh-140576: Fixed crash in tokenize.generate_tokens() in case
|
||||
of specific incorrect input. Patch by Mikhail Efimov.
|
||||
- gh-140551: Fixed crash in dict if dict.clear() is called at
|
||||
the lookup stage. Patch by Mikhail Efimov and Inada Naoki.
|
||||
- gh-140517: Fixed a reference leak when iterating over the
|
||||
result of map() with strict=True when the input iterables
|
||||
have different lengths. Patch by Mikhail Efimov.
|
||||
- gh-140471: Fix potential buffer overflow in ast.AST node
|
||||
initialization when encountering malformed _fields containing
|
||||
non-str.
|
||||
- gh-140431: Fix a crash in Python’s garbage collector due to
|
||||
partially initialized coroutine objects when coroutine origin
|
||||
tracking depth is enabled
|
||||
(sys.set_coroutine_origin_tracking_depth()).
|
||||
- gh-140398: Fix memory leaks in readline functions
|
||||
read_init_file(), read_history_file(), write_history_file(),
|
||||
and append_history_file() when PySys_Audit() fails.
|
||||
- gh-140406: Fix memory leak when an object’s __hash__() method
|
||||
returns an object that isn’t an int.
|
||||
- gh-140358: Restore elapsed time and unreachable object count
|
||||
in GC debug output. These were inadvertently removed during
|
||||
a refactor of gc.c. The debug log now again reports elapsed
|
||||
collection time and the number of unreachable objects.
|
||||
Contributed by Pål Grønås Drange.
|
||||
- gh-140306: Fix memory leaks in cross-interpreter channel
|
||||
operations and shared namespace handling.
|
||||
- gh-140301: Fix memory leak of PyConfig in subinterpreters.
|
||||
- gh-140257: Fix data race between interpreter_clear() and
|
||||
take_gil() on eval_breaker during finalization with daemon
|
||||
threads.
|
||||
- gh-139951: Fixes a regression in GC performance for a growing
|
||||
heap composed mostly of small tuples. Counts number of
|
||||
actually tracked objects, instead of trackable objects. This
|
||||
ensures that untracking tuples has the desired effect of
|
||||
reducing GC overhead. Does not track most untrackable tuples
|
||||
during creation. This prevents large numbers of small tuples
|
||||
causing excessive GCs.
|
||||
- gh-140104: Fix a bug with exception handling in the JIT.
|
||||
Patch by Ken Jin. Bug reported by Daniel Diniz.
|
||||
- gh-140061: Fixing the checking of whether an object is
|
||||
uniquely referenced to ensure free-threaded compatibility.
|
||||
Patch by Sergey Miryanov.
|
||||
- gh-140067: Fix memory leak in sub-interpreter creation.
|
||||
- gh-140000: Fix potential memory leak when a reference cycle
|
||||
exists between an instance of typing.TypeAliasType,
|
||||
typing.TypeVar, typing.ParamSpec, or typing.TypeVarTuple and
|
||||
its __name__ attribute. Patch by Mikhail Efimov.
|
||||
- gh-139914: Restore support for HP PA-RISC, which has an
|
||||
upwards-growing stack.
|
||||
- gh-139988: Fix a memory leak when failing to create a Union
|
||||
type. Patch by Bénédikt Tran.
|
||||
- gh-139748: Fix reference leaks in error branches of functions
|
||||
accepting path strings or bytes such as compile() and
|
||||
os.system(). Patch by Bénédikt Tran.
|
||||
- gh-139516: Fix lambda colon erroneously start format spec in
|
||||
f-string in tokenizer.
|
||||
- gh-139640: ast.parse() no longer emits syntax warnings for
|
||||
return/break/continue in finally (see PEP 765) – they are
|
||||
only emitted during compilation.
|
||||
- gh-139640: Fix swallowing some syntax warnings in different
|
||||
modules if they accidentally have the same message and are
|
||||
emitted from the same line. Fix duplicated warnings in the
|
||||
finally block.
|
||||
- gh-63161: Support non-UTF-8 shebang and comments in Python
|
||||
source files if non-UTF-8 encoding is specified. Detect
|
||||
decoding error in comments for default (UTF-8) encoding. Show
|
||||
the line and position of decoding error for default encoding
|
||||
in a traceback. Show the line containing the coding cookie
|
||||
when it conflicts with the BOM in a traceback.
|
||||
- gh-116738: Make mmap thread-safe on the free threaded build.
|
||||
- gh-138558: Fix handling of unusual t-string annotations in
|
||||
annotationlib. Patch by Dave Peck.
|
||||
- gh-134466: Don’t run PyREPL in a degraded environment where
|
||||
setting termios attributes is not allowed.
|
||||
- gh-138944: Fix SyntaxError message when invalid syntax
|
||||
appears on the same line as a valid import ... as ... or from
|
||||
... import ... as ... statement. Patch by Brian Schubert.
|
||||
- gh-105487: Remove non-existent __copy__(), __deepcopy__(),
|
||||
and __bases__ from the __dir__() entries of
|
||||
types.GenericAlias.
|
||||
- gh-69605: Fix some standard library submodules missing from
|
||||
the REPL auto-completion of imports.
|
||||
- gh-116738: Make cProfile thread-safe on the free threaded
|
||||
build.
|
||||
- gh-138004: On Solaris/Illumos platforms, thread names are now
|
||||
encoded as ASCII to avoid errors on systems (e.g.
|
||||
OpenIndiana) that don’t support non-ASCII names.
|
||||
- gh-137433: Fix a potential deadlock in the free threading
|
||||
build when daemon threads enable or disable profiling or
|
||||
tracing while the main thread is shutting down the
|
||||
interpreter.
|
||||
- gh-137400: Fix a crash in the free threading build when
|
||||
disabling profiling or tracing across all threads with
|
||||
PyEval_SetProfileAllThreads() or PyEval_SetTraceAllThreads()
|
||||
or their Python equivalents threading.settrace_all_threads()
|
||||
and threading.setprofile_all_threads().
|
||||
- gh-58124: Fix name of the Python encoding in Unicode errors
|
||||
of the code page codec: use “cp65000” and “cp65001” instead
|
||||
of “CP_UTF7” and “CP_UTF8” which are not valid Python code
|
||||
names. Patch by Victor Stinner.
|
||||
- gh-132657: Improve performance of frozenset by removing locks
|
||||
in the free-threading build.
|
||||
- gh-133400: Fixed Ctrl+D (^D) behavior in _pyrepl module to
|
||||
match old pre-3.13 REPL behavior.
|
||||
- gh-128640: Fix a crash when using threads inside of
|
||||
a subinterpreter.
|
||||
- C API
|
||||
- gh-137422: Fix free threading race condition in
|
||||
PyImport_AddModuleRef(). It was previously possible for two
|
||||
calls to the function return two different objects, only one
|
||||
of which was stored in sys.modules.
|
||||
- gh-140042: Removed the sqlite3_shutdown call that could cause
|
||||
closing connections for sqlite when used with multiple sub
|
||||
interpreters.
|
||||
- gh-141042: Make qNaN in PyFloat_Pack2() and PyFloat_Pack4(),
|
||||
if while conversion to a narrower precision floating-point
|
||||
format — the remaining after truncation payload will be zero.
|
||||
Patch by Sergey B Kirpichev.
|
||||
- gh-140487: Fix Py_RETURN_NOTIMPLEMENTED in limited C API 3.11
|
||||
and older: don’t treat Py_NotImplemented as immortal. Patch
|
||||
by Victor Stinner.
|
||||
- gh-140153: Fix Py_REFCNT() definition on limited C API
|
||||
3.11-3.13. Patch by Victor Stinner.
|
||||
- gh-139653: Add PyUnstable_ThreadState_SetStackProtection()
|
||||
and PyUnstable_ThreadState_ResetStackProtection() functions
|
||||
to set the stack protection base address and stack protection
|
||||
size of a Python thread state. Patch by Victor Stinner.
|
||||
- Build
|
||||
- gh-141808: Do not generate the jit stencils twice in case of
|
||||
PGO builds on Windows.
|
||||
- gh-141784: Fix _remote_debugging_module.c compilation on
|
||||
32-bit Linux. Include Python.h before system headers to make
|
||||
sure that _remote_debugging_module.c uses the same types
|
||||
(ABI) than Python. Patch by Victor Stinner.
|
||||
- gh-140768: Warn when the WASI SDK version doesn’t match
|
||||
what’s supported.
|
||||
- gh-140513: Generate a clear compilation error when
|
||||
_Py_TAIL_CALL_INTERP is enabled but either preserve_none or
|
||||
musttail is not supported.
|
||||
- gh-140189: iOS builds were added to CI.
|
||||
- gh-138489: When cross-compiling for WASI by build_wasm or
|
||||
build_emscripten, the build-details.json step is now included
|
||||
in the build process, just like with native builds. This
|
||||
fixes the libinstall task which requires the
|
||||
build-details.json file during the process.
|
||||
- gh-137618: PYTHON_FOR_REGEN now requires Python 3.10 to
|
||||
Python 3.15. Patch by Adam Turner.
|
||||
- gh-123681: Check the strftime() behavior at runtime instead
|
||||
of at the compile time to support cross-compiling. Remove the
|
||||
internal macro _Py_NORMALIZE_CENTURY.
|
||||
- Remove upstreamed patches:
|
||||
- CVE-2025-6075-expandvars-perf-degrad.patch
|
||||
- CVE-2025-8291-consistency-zip64.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Thu Nov 13 17:13:03 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
|
||||
4
python314.rpmlintrc
Normal file
4
python314.rpmlintrc
Normal file
@@ -0,0 +1,4 @@
|
||||
addFilter("pem-certificate.*/usr/lib.*/python.*/test/*.pem")
|
||||
addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/tests/*.c")
|
||||
addFilter("devel-file-in-non-devel-package.*/usr/lib.*/python.*/test/*.cpp")
|
||||
addFilter("python-bytecode-inconsistent-mtime.*/usr/lib.*/python.*/*.pyc")
|
||||
@@ -54,6 +54,8 @@
|
||||
%bcond_with GIL
|
||||
%endif
|
||||
|
||||
%define llvm_version 21
|
||||
|
||||
%if 0%{?do_profiling} && !0%{?want_reproducible_builds}
|
||||
%bcond_without profileopt
|
||||
%else
|
||||
@@ -124,7 +126,7 @@
|
||||
# %%define tarversion %%{version}
|
||||
# %%endif
|
||||
# We don't process beta signs well
|
||||
%define folderversion 3.14.0
|
||||
%define folderversion 3.14.2
|
||||
%define sitedir %{_libdir}/python%{python_version}
|
||||
# three possible ABI kinds: m - pymalloc, d - debug build; see PEP 3149
|
||||
%define abi_kind %{nil}
|
||||
@@ -162,7 +164,7 @@
|
||||
# _md5.cpython-38m-x86_64-linux-gnu.so
|
||||
%define dynlib() %{sitedir}/lib-dynload/%{1}.cpython-%{abi_tag}-%{archname}-%{_os}%{?_gnu}%{?armsuffix}.so
|
||||
Name: %{python_pkg_name}%{psuffix}
|
||||
Version: 3.14.0
|
||||
Version: 3.14.2
|
||||
%define tarversion %{version}
|
||||
%define tarname Python-%{tarversion}
|
||||
Release: 0
|
||||
@@ -209,6 +211,8 @@ Patch07: bpo-31046_ensurepip_honours_prefix.patch
|
||||
# PATCH-FIX-SLE skip-test_pyobject_freed_is_freed.patch mcepl@suse.com
|
||||
# skip a test failing on SLE-15
|
||||
Patch09: skip-test_pyobject_freed_is_freed.patch
|
||||
# PATCH-FIX-UPSTREAM gh138498-llvm-version-config gh#python/cpython#138498 daniel.garcia@suse.com
|
||||
Patch10: gh138498-llvm-version-config.patch
|
||||
# PATCH-FIX-OPENSUSE CVE-2023-52425-libexpat-2.6.0-backport-15.6.patch
|
||||
# This problem on libexpat is patched on 15.6 without version
|
||||
# update, this patch changes the tests to match the libexpat provided
|
||||
@@ -224,12 +228,6 @@ Patch41: bsc1243155-sphinx-non-determinism.patch
|
||||
Patch44: gh138131-exclude-pycache-from-digest.patch
|
||||
# PATCH-FIX-OPENSUSE gh139257-Support-docutils-0.22.patch gh#python/cpython#139257 daniel.garcia@suse.com
|
||||
Patch45: gh139257-Support-docutils-0.22.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2025-8291-consistency-zip64.patch bsc#1251305 mcepl@suse.com
|
||||
# Check consistency of the zip64 end of central directory record
|
||||
Patch46: CVE-2025-8291-consistency-zip64.patch
|
||||
# PATCH-FIX-UPSTREAM CVE-2025-6075-expandvars-perf-degrad.patch bsc#1252974 mcepl@suse.com
|
||||
# Avoid potential quadratic complexity vulnerabilities in path modules
|
||||
Patch47: CVE-2025-6075-expandvars-perf-degrad.patch
|
||||
#### Python 3.14 DEVELOPMENT PATCHES
|
||||
BuildRequires: autoconf-archive
|
||||
BuildRequires: automake
|
||||
@@ -275,7 +273,7 @@ BuildRequires: python3-python-docs-theme >= 2022.1
|
||||
|
||||
%if %{with experimental_jit}
|
||||
# needed for experimental_jit
|
||||
BuildRequires: clang19 llvm19
|
||||
BuildRequires: clang%{llvm_version} llvm%{llvm_version}
|
||||
BuildRequires: llvm
|
||||
%endif
|
||||
|
||||
@@ -581,6 +579,7 @@ sed -e 's/-fprofile-correction//' -i Makefile.pre.in
|
||||
%endif
|
||||
|
||||
export CFLAGS="%{optflags} -IVendor/"
|
||||
export LLVM_VERSION=%{llvm_version}
|
||||
|
||||
%configure \
|
||||
--with-platlibdir=%{_lib} \
|
||||
|
||||
Reference in New Issue
Block a user