forked from pool/python310
Update to 3.10.20:
- Security
- gh-144125: BytesGenerator will now refuse to serialize
(write) headers that are unsafely folded or delimited; see
verify_generated_headers. (Contributed by Bas Bloemsaat and
Petr Viktorin in gh-121650).
- gh-143935: Fixed a bug in the folding of comments when
flattening an email message using a modern email policy.
Comments consisting of a very long sequence of non-foldable
characters could trigger a forced line wrap that omitted
the required leading space on the continuation line,
causing the remainder of the comment to be interpreted as
a new header field. This enabled header injection with
carefully crafted inputs (bsc#1257029 CVE-2025-11468).
- gh-143925: Reject control characters in data: URL media
types.
- gh-143919: Reject control characters in http.cookies.Morsel
fields and values (bsc#1257031, CVE-2026-0672).
- gh-143916: Reject C0 control characters within
wsgiref.headers.Headers fields, values, and parameters
(bsc#1257042, CVE-2026-0865).
- gh-142145: Remove quadratic behavior in xml.minidom node ID
cache clearing. In order to do this without breaking
existing users, we also add the ownerDocument attribute to
xml.dom.minidom elements and attributes created by directly
instantiating the Element or Attr class. Note that this way
of creating nodes is not supported; creator functions like
xml.dom.Document.documentElement() should be used instead
(bsc#1254997, CVE-2025-12084).
- 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() (bsc#1252974, CVE-2025-6075).
- 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-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.
- 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
(bsc#1254401, CVE-2025-13837).
- Library
- gh-144833: Fixed a use-after-free in ssl when SSL_new()
returns NULL in newPySSLSocket(). The error was reported
via a dangling pointer after the object had already been
freed.
- gh-144363: Update bundled libexpat to 2.7.4
- 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.
- Core and Builtins
- gh-120384: Fix an array out of bounds crash in
list_ass_subscript, which could be invoked via some
specificly tailored input: including concurrent
modification of a list object, where one thread assigns
a slice and another clears it.
- gh-120298: Fix use-after free in list_richcompare_impl
which can be invoked via some specificly tailored evil
input.
Remove upstreamed patches:
- CVE-2025-11468-email-hdr-fold-comment.patch
- CVE-2025-12084-minidom-quad-search.patch
- CVE-2025-13836-http-resp-cont-len.patch
- CVE-2025-13837-plistlib-mailicious-length.patch
- CVE-2025-6075-expandvars-perf-degrad.patch
- CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch
- CVE-2026-0865-wsgiref-ctrl-chars.patch
This commit is contained in:
@@ -4,11 +4,11 @@
|
||||
Lib/test/test_xml_etree.py | 7 +++++++
|
||||
3 files changed, 14 insertions(+)
|
||||
|
||||
Index: Python-3.10.19/Lib/test/test_pyexpat.py
|
||||
Index: Python-3.10.20/Lib/test/test_pyexpat.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_pyexpat.py 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Lib/test/test_pyexpat.py 2025-12-19 23:10:22.001497953 +0100
|
||||
@@ -802,6 +802,10 @@
|
||||
--- Python-3.10.20.orig/Lib/test/test_pyexpat.py 2026-03-05 19:42:14.505101236 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_pyexpat.py 2026-03-05 19:42:23.343680667 +0100
|
||||
@@ -807,6 +807,10 @@
|
||||
self.assertEqual(started, ['doc'])
|
||||
|
||||
def test_reparse_deferral_disabled(self):
|
||||
@@ -19,10 +19,10 @@ Index: Python-3.10.19/Lib/test/test_pyexpat.py
|
||||
started = []
|
||||
|
||||
def start_element(name, _):
|
||||
Index: Python-3.10.19/Lib/test/test_sax.py
|
||||
Index: Python-3.10.20/Lib/test/test_sax.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_sax.py 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Lib/test/test_sax.py 2025-12-19 23:10:22.002078897 +0100
|
||||
--- Python-3.10.20.orig/Lib/test/test_sax.py 2026-03-05 19:42:14.505101236 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_sax.py 2026-03-05 19:42:23.344649745 +0100
|
||||
@@ -1240,6 +1240,9 @@
|
||||
|
||||
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
|
||||
@@ -33,10 +33,10 @@ Index: Python-3.10.19/Lib/test/test_sax.py
|
||||
def test_flush_reparse_deferral_disabled(self):
|
||||
result = BytesIO()
|
||||
xmlgen = XMLGenerator(result)
|
||||
Index: Python-3.10.19/Lib/test/test_xml_etree.py
|
||||
Index: Python-3.10.20/Lib/test/test_xml_etree.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_xml_etree.py 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Lib/test/test_xml_etree.py 2025-12-19 23:10:22.002413090 +0100
|
||||
--- Python-3.10.20.orig/Lib/test/test_xml_etree.py 2026-03-05 19:42:14.505101236 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_xml_etree.py 2026-03-05 19:42:23.345531779 +0100
|
||||
@@ -1420,9 +1420,13 @@
|
||||
self.assert_event_tags(parser, [('end', 'root')])
|
||||
self.assertIsNone(parser.close())
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
From 2065aa5b8f2bcdea2f628686c57974793a62c42b Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
Date: Mon, 19 Jan 2026 06:38:22 -0600
|
||||
Subject: [PATCH] [3.10] gh-143935: Email preserve parens when folding comments
|
||||
(GH-143936)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Fix a bug in the folding of comments when flattening an email message
|
||||
using a modern email policy. Comments consisting of a very long sequence of
|
||||
non-foldable characters could trigger a forced line wrap that omitted the
|
||||
required leading space on the continuation line, causing the remainder of
|
||||
the comment to be interpreted as a new header field. This enabled header
|
||||
injection with carefully crafted inputs.
|
||||
(cherry picked from commit 17d1490)
|
||||
|
||||
Co-authored-by: Seth Michael Larson seth@python.org
|
||||
Co-authored-by: Denis Ledoux dle@odoo.com
|
||||
|
||||
- Issue: Fix folding of long comments of unfoldable characters in email headers #143935
|
||||
|
||||
Signed-off-by: Edgar Ramírez Mondragón <edgarrm358@gmail.com>
|
||||
---
|
||||
Lib/email/_header_value_parser.py | 15 +++++++++++-
|
||||
.../test_email/test__header_value_parser.py | 23 +++++++++++++++++++
|
||||
...-01-16-14-40-31.gh-issue-143935.U2YtKl.rst | 6 +++++
|
||||
3 files changed, 43 insertions(+), 1 deletion(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
|
||||
|
||||
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
|
||||
index dbc0bd8196af52..2c05abeadea22b 100644
|
||||
--- a/Lib/email/_header_value_parser.py
|
||||
+++ b/Lib/email/_header_value_parser.py
|
||||
@@ -101,6 +101,12 @@ def make_quoted_pairs(value):
|
||||
return str(value).replace('\\', '\\\\').replace('"', '\\"')
|
||||
|
||||
|
||||
+def make_parenthesis_pairs(value):
|
||||
+ """Escape parenthesis and backslash for use within a comment."""
|
||||
+ return str(value).replace('\\', '\\\\') \
|
||||
+ .replace('(', '\\(').replace(')', '\\)')
|
||||
+
|
||||
+
|
||||
def quote_string(value):
|
||||
escaped = make_quoted_pairs(value)
|
||||
return f'"{escaped}"'
|
||||
@@ -927,7 +933,7 @@ def value(self):
|
||||
return ' '
|
||||
|
||||
def startswith_fws(self):
|
||||
- return True
|
||||
+ return self and self[0] in WSP
|
||||
|
||||
|
||||
class ValueTerminal(Terminal):
|
||||
@@ -2865,6 +2871,13 @@ def _refold_parse_tree(parse_tree, *, policy):
|
||||
[ValueTerminal(make_quoted_pairs(p), 'ptext')
|
||||
for p in newparts] +
|
||||
[ValueTerminal('"', 'ptext')])
|
||||
+ if part.token_type == 'comment':
|
||||
+ newparts = (
|
||||
+ [ValueTerminal('(', 'ptext')] +
|
||||
+ [ValueTerminal(make_parenthesis_pairs(p), 'ptext')
|
||||
+ if p.token_type == 'ptext' else p
|
||||
+ for p in newparts] +
|
||||
+ [ValueTerminal(')', 'ptext')])
|
||||
if not part.as_ew_allowed:
|
||||
wrap_as_ew_blocked += 1
|
||||
newparts.append(end_ew_not_allowed)
|
||||
diff --git a/Lib/test/test_email/test__header_value_parser.py b/Lib/test/test_email/test__header_value_parser.py
|
||||
index 6a4ecafd68b4ab..2eaaaaef675284 100644
|
||||
--- a/Lib/test/test_email/test__header_value_parser.py
|
||||
+++ b/Lib/test/test_email/test__header_value_parser.py
|
||||
@@ -2973,6 +2973,29 @@ def test_address_list_with_specials_in_long_quoted_string(self):
|
||||
with self.subTest(to=to):
|
||||
self._test(parser.get_address_list(to)[0], folded, policy=policy)
|
||||
|
||||
+ def test_address_list_with_long_unwrapable_comment(self):
|
||||
+ policy = self.policy.clone(max_line_length=40)
|
||||
+ cases = [
|
||||
+ # (to, folded)
|
||||
+ ('(loremipsumdolorsitametconsecteturadipi)<spy@example.org>',
|
||||
+ '(loremipsumdolorsitametconsecteturadipi)<spy@example.org>\n'),
|
||||
+ ('<spy@example.org>(loremipsumdolorsitametconsecteturadipi)',
|
||||
+ '<spy@example.org>(loremipsumdolorsitametconsecteturadipi)\n'),
|
||||
+ ('(loremipsum dolorsitametconsecteturadipi)<spy@example.org>',
|
||||
+ '(loremipsum dolorsitametconsecteturadipi)<spy@example.org>\n'),
|
||||
+ ('<spy@example.org>(loremipsum dolorsitametconsecteturadipi)',
|
||||
+ '<spy@example.org>(loremipsum\n dolorsitametconsecteturadipi)\n'),
|
||||
+ ('(Escaped \\( \\) chars \\\\ in comments stay escaped)<spy@example.org>',
|
||||
+ '(Escaped \\( \\) chars \\\\ in comments stay\n escaped)<spy@example.org>\n'),
|
||||
+ ('((loremipsum)(loremipsum)(loremipsum)(loremipsum))<spy@example.org>',
|
||||
+ '((loremipsum)(loremipsum)(loremipsum)(loremipsum))<spy@example.org>\n'),
|
||||
+ ('((loremipsum)(loremipsum)(loremipsum) (loremipsum))<spy@example.org>',
|
||||
+ '((loremipsum)(loremipsum)(loremipsum)\n (loremipsum))<spy@example.org>\n'),
|
||||
+ ]
|
||||
+ for (to, folded) in cases:
|
||||
+ with self.subTest(to=to):
|
||||
+ self._test(parser.get_address_list(to)[0], folded, policy=policy)
|
||||
+
|
||||
def test_address_list_with_specials_in_encoded_word(self):
|
||||
# An encoded-word parsed from a structured header must remain
|
||||
# encoded when it contains specials. Regression for gh-121284.
|
||||
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..c3d864936884ac
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2026-01-16-14-40-31.gh-issue-143935.U2YtKl.rst
|
||||
@@ -0,0 +1,6 @@
|
||||
+Fixed a bug in the folding of comments when flattening an email message
|
||||
+using a modern email policy. Comments consisting of a very long sequence of
|
||||
+non-foldable characters could trigger a forced line wrap that omitted the
|
||||
+required leading space on the continuation line, causing the remainder of
|
||||
+the comment to be interpreted as a new header field. This enabled header
|
||||
+injection with carefully crafted inputs.
|
||||
@@ -1,93 +0,0 @@
|
||||
From f4eb9ab014545b521fb261b80adfa6d138e7e092 Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
Date: Wed, 3 Dec 2025 01:16:37 -0600
|
||||
Subject: [PATCH] gh-142145: Remove quadratic behavior in node ID cache
|
||||
clearing (GH-142146)
|
||||
|
||||
* Remove quadratic behavior in node ID cache clearing
|
||||
|
||||
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
|
||||
|
||||
* Add news fragment
|
||||
|
||||
---------
|
||||
(cherry picked from commit 08d8e18ad81cd45bc4a27d6da478b51ea49486e4)
|
||||
|
||||
Co-authored-by: Seth Michael Larson <seth@python.org>
|
||||
Co-authored-by: Jacob Walls <38668450+jacobtylerwalls@users.noreply.github.com>
|
||||
---
|
||||
Lib/test/test_minidom.py | 18 ++++++++++
|
||||
Lib/xml/dom/minidom.py | 9 -----
|
||||
Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst | 1
|
||||
3 files changed, 20 insertions(+), 8 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
|
||||
|
||||
Index: Python-3.10.19/Lib/test/test_minidom.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_minidom.py 2025-12-19 23:10:45.263295780 +0100
|
||||
+++ Python-3.10.19/Lib/test/test_minidom.py 2025-12-19 23:10:50.342493590 +0100
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import copy
|
||||
import pickle
|
||||
+import time
|
||||
import io
|
||||
from test import support
|
||||
import unittest
|
||||
@@ -176,6 +177,23 @@
|
||||
self.confirm(dom.documentElement.childNodes[-1].data == "Hello")
|
||||
dom.unlink()
|
||||
|
||||
+ def testAppendChildNoQuadraticComplexity(self):
|
||||
+ impl = getDOMImplementation()
|
||||
+
|
||||
+ newdoc = impl.createDocument(None, "some_tag", None)
|
||||
+ top_element = newdoc.documentElement
|
||||
+ children = [newdoc.createElement(f"child-{i}") for i in range(1, 2 ** 15 + 1)]
|
||||
+ element = top_element
|
||||
+
|
||||
+ start = time.time()
|
||||
+ for child in children:
|
||||
+ element.appendChild(child)
|
||||
+ element = child
|
||||
+ end = time.time()
|
||||
+
|
||||
+ # This example used to take at least 30 seconds.
|
||||
+ self.assertLess(end - start, 1)
|
||||
+
|
||||
def testAppendChildFragment(self):
|
||||
dom, orig, c1, c2, c3, frag = self._create_fragment_test_nodes()
|
||||
dom.documentElement.appendChild(frag)
|
||||
Index: Python-3.10.19/Lib/xml/dom/minidom.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/xml/dom/minidom.py 2025-12-19 23:10:45.263295780 +0100
|
||||
+++ Python-3.10.19/Lib/xml/dom/minidom.py 2025-12-19 23:10:50.342898393 +0100
|
||||
@@ -292,13 +292,6 @@
|
||||
childNodes.append(node)
|
||||
node.parentNode = self
|
||||
|
||||
-def _in_document(node):
|
||||
- # return True iff node is part of a document tree
|
||||
- while node is not None:
|
||||
- if node.nodeType == Node.DOCUMENT_NODE:
|
||||
- return True
|
||||
- node = node.parentNode
|
||||
- return False
|
||||
|
||||
def _write_data(writer, data):
|
||||
"Writes datachars to writer."
|
||||
@@ -1539,7 +1532,7 @@
|
||||
if node.nodeType == Node.DOCUMENT_NODE:
|
||||
node._id_cache.clear()
|
||||
node._id_search_stack = None
|
||||
- elif _in_document(node):
|
||||
+ elif node.ownerDocument:
|
||||
node.ownerDocument._id_cache.clear()
|
||||
node.ownerDocument._id_search_stack= None
|
||||
|
||||
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2025-12-01-09-36-45.gh-issue-142145.tcAUhg.rst 2025-12-19 23:10:50.343161277 +0100
|
||||
@@ -0,0 +1 @@
|
||||
+Remove quadratic behavior in ``xml.minidom`` node ID cache clearing.
|
||||
@@ -1,155 +0,0 @@
|
||||
From b3a7998115e195c40e00cfa662bcaa899d937c05 Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Mon, 1 Dec 2025 17:26:07 +0200
|
||||
Subject: [PATCH] gh-119451: Fix a potential denial of service in http.client
|
||||
(GH-119454)
|
||||
|
||||
Reading the whole body of the HTTP response could cause OOM if
|
||||
the Content-Length value is too large even if the server does not send
|
||||
a large amount of data. Now the HTTP client reads large data by chunks,
|
||||
therefore the amount of consumed memory is proportional to the amount
|
||||
of sent data.
|
||||
(cherry picked from commit 5a4c4a033a4a54481be6870aa1896fad732555b5)
|
||||
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
---
|
||||
Lib/http/client.py | 28 ++++++--
|
||||
Lib/test/test_httplib.py | 66 +++++++++++++++++++
|
||||
...-05-23-11-47-48.gh-issue-119451.qkJe9-.rst | 5 ++
|
||||
3 files changed, 95 insertions(+), 4 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
|
||||
|
||||
diff --git a/Lib/http/client.py b/Lib/http/client.py
|
||||
index d1b7b1048c9171..c8ab5b7662c334 100644
|
||||
--- a/Lib/http/client.py
|
||||
+++ b/Lib/http/client.py
|
||||
@@ -111,6 +111,11 @@
|
||||
_MAXLINE = 65536
|
||||
_MAXHEADERS = 100
|
||||
|
||||
+# Data larger than this will be read in chunks, to prevent extreme
|
||||
+# overallocation.
|
||||
+_MIN_READ_BUF_SIZE = 1 << 20
|
||||
+
|
||||
+
|
||||
# Header name/value ABNF (http://tools.ietf.org/html/rfc7230#section-3.2)
|
||||
#
|
||||
# VCHAR = %x21-7E
|
||||
@@ -628,10 +633,25 @@ def _safe_read(self, amt):
|
||||
reading. If the bytes are truly not available (due to EOF), then the
|
||||
IncompleteRead exception can be used to detect the problem.
|
||||
"""
|
||||
- data = self.fp.read(amt)
|
||||
- if len(data) < amt:
|
||||
- raise IncompleteRead(data, amt-len(data))
|
||||
- return data
|
||||
+ cursize = min(amt, _MIN_READ_BUF_SIZE)
|
||||
+ data = self.fp.read(cursize)
|
||||
+ if len(data) >= amt:
|
||||
+ return data
|
||||
+ if len(data) < cursize:
|
||||
+ raise IncompleteRead(data, amt - len(data))
|
||||
+
|
||||
+ data = io.BytesIO(data)
|
||||
+ data.seek(0, 2)
|
||||
+ while True:
|
||||
+ # This is a geometric increase in read size (never more than
|
||||
+ # doubling out the current length of data per loop iteration).
|
||||
+ delta = min(cursize, amt - cursize)
|
||||
+ data.write(self.fp.read(delta))
|
||||
+ if data.tell() >= amt:
|
||||
+ return data.getvalue()
|
||||
+ cursize += delta
|
||||
+ if data.tell() < cursize:
|
||||
+ raise IncompleteRead(data.getvalue(), amt - data.tell())
|
||||
|
||||
def _safe_readinto(self, b):
|
||||
"""Same as _safe_read, but for reading into a buffer."""
|
||||
diff --git a/Lib/test/test_httplib.py b/Lib/test/test_httplib.py
|
||||
index 77152cf64565e0..89ec5f6f1c5383 100644
|
||||
--- a/Lib/test/test_httplib.py
|
||||
+++ b/Lib/test/test_httplib.py
|
||||
@@ -1226,6 +1226,72 @@ def run_server():
|
||||
thread.join()
|
||||
self.assertEqual(result, b"proxied data\n")
|
||||
|
||||
+ def test_large_content_length(self):
|
||||
+ serv = socket.create_server((HOST, 0))
|
||||
+ self.addCleanup(serv.close)
|
||||
+
|
||||
+ def run_server():
|
||||
+ [conn, address] = serv.accept()
|
||||
+ with conn:
|
||||
+ while conn.recv(1024):
|
||||
+ conn.sendall(
|
||||
+ b"HTTP/1.1 200 Ok\r\n"
|
||||
+ b"Content-Length: %d\r\n"
|
||||
+ b"\r\n" % size)
|
||||
+ conn.sendall(b'A' * (size//3))
|
||||
+ conn.sendall(b'B' * (size - size//3))
|
||||
+
|
||||
+ thread = threading.Thread(target=run_server)
|
||||
+ thread.start()
|
||||
+ self.addCleanup(thread.join, 1.0)
|
||||
+
|
||||
+ conn = client.HTTPConnection(*serv.getsockname())
|
||||
+ try:
|
||||
+ for w in range(15, 27):
|
||||
+ size = 1 << w
|
||||
+ conn.request("GET", "/")
|
||||
+ with conn.getresponse() as response:
|
||||
+ self.assertEqual(len(response.read()), size)
|
||||
+ finally:
|
||||
+ conn.close()
|
||||
+ thread.join(1.0)
|
||||
+
|
||||
+ def test_large_content_length_truncated(self):
|
||||
+ serv = socket.create_server((HOST, 0))
|
||||
+ self.addCleanup(serv.close)
|
||||
+
|
||||
+ def run_server():
|
||||
+ while True:
|
||||
+ [conn, address] = serv.accept()
|
||||
+ with conn:
|
||||
+ conn.recv(1024)
|
||||
+ if not size:
|
||||
+ break
|
||||
+ conn.sendall(
|
||||
+ b"HTTP/1.1 200 Ok\r\n"
|
||||
+ b"Content-Length: %d\r\n"
|
||||
+ b"\r\n"
|
||||
+ b"Text" % size)
|
||||
+
|
||||
+ thread = threading.Thread(target=run_server)
|
||||
+ thread.start()
|
||||
+ self.addCleanup(thread.join, 1.0)
|
||||
+
|
||||
+ conn = client.HTTPConnection(*serv.getsockname())
|
||||
+ try:
|
||||
+ for w in range(18, 65):
|
||||
+ size = 1 << w
|
||||
+ conn.request("GET", "/")
|
||||
+ with conn.getresponse() as response:
|
||||
+ self.assertRaises(client.IncompleteRead, response.read)
|
||||
+ conn.close()
|
||||
+ finally:
|
||||
+ conn.close()
|
||||
+ size = 0
|
||||
+ conn.request("GET", "/")
|
||||
+ conn.close()
|
||||
+ thread.join(1.0)
|
||||
+
|
||||
def test_putrequest_override_domain_validation(self):
|
||||
"""
|
||||
It should be possible to override the default validation
|
||||
diff --git a/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..6d6f25cd2f8bf7
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2024-05-23-11-47-48.gh-issue-119451.qkJe9-.rst
|
||||
@@ -0,0 +1,5 @@
|
||||
+Fix a potential memory denial of service in the :mod:`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 :exc:`MemoryError`, swapping, out
|
||||
+of memory (OOM) killed processes or containers, or even system crashes.
|
||||
@@ -1,160 +0,0 @@
|
||||
From e99059d800b741504ef18693803927a0dc062be4 Mon Sep 17 00:00:00 2001
|
||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
||||
Date: Mon, 1 Dec 2025 17:28:15 +0200
|
||||
Subject: [PATCH] [3.10] gh-119342: Fix a potential denial of service in
|
||||
plistlib (GH-119343)
|
||||
|
||||
Reading a specially prepared small Plist file could cause OOM because file's
|
||||
read(n) preallocates a bytes object for reading the specified amount of
|
||||
data. Now plistlib reads large data by chunks, therefore the upper limit of
|
||||
consumed memory is proportional to the size of the input file.
|
||||
(cherry picked from commit 694922cf40aa3a28f898b5f5ee08b71b4922df70)
|
||||
|
||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
||||
---
|
||||
Lib/plistlib.py | 31 ++++++++++------
|
||||
Lib/test/test_plistlib.py | 37 +++++++++++++++++--
|
||||
...-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst | 5 +++
|
||||
3 files changed, 59 insertions(+), 14 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
|
||||
diff --git a/Lib/plistlib.py b/Lib/plistlib.py
|
||||
index d6c997efe9c5f5..c80dfee02a3335 100644
|
||||
--- a/Lib/plistlib.py
|
||||
+++ b/Lib/plistlib.py
|
||||
@@ -73,6 +73,9 @@
|
||||
PlistFormat = enum.Enum('PlistFormat', 'FMT_XML FMT_BINARY', module=__name__)
|
||||
globals().update(PlistFormat.__members__)
|
||||
|
||||
+# Data larger than this will be read in chunks, to prevent extreme
|
||||
+# overallocation.
|
||||
+_MIN_READ_BUF_SIZE = 1 << 20
|
||||
|
||||
class UID:
|
||||
def __init__(self, data):
|
||||
@@ -499,12 +502,24 @@ def _get_size(self, tokenL):
|
||||
|
||||
return tokenL
|
||||
|
||||
+ def _read(self, size):
|
||||
+ cursize = min(size, _MIN_READ_BUF_SIZE)
|
||||
+ data = self._fp.read(cursize)
|
||||
+ while True:
|
||||
+ if len(data) != cursize:
|
||||
+ raise InvalidFileException
|
||||
+ if cursize == size:
|
||||
+ return data
|
||||
+ delta = min(cursize, size - cursize)
|
||||
+ data += self._fp.read(delta)
|
||||
+ cursize += delta
|
||||
+
|
||||
def _read_ints(self, n, size):
|
||||
- data = self._fp.read(size * n)
|
||||
+ data = self._read(size * n)
|
||||
if size in _BINARY_FORMAT:
|
||||
return struct.unpack(f'>{n}{_BINARY_FORMAT[size]}', data)
|
||||
else:
|
||||
- if not size or len(data) != size * n:
|
||||
+ if not size:
|
||||
raise InvalidFileException()
|
||||
return tuple(int.from_bytes(data[i: i + size], 'big')
|
||||
for i in range(0, size * n, size))
|
||||
@@ -561,22 +576,16 @@ def _read_object(self, ref):
|
||||
|
||||
elif tokenH == 0x40: # data
|
||||
s = self._get_size(tokenL)
|
||||
- result = self._fp.read(s)
|
||||
- if len(result) != s:
|
||||
- raise InvalidFileException()
|
||||
+ result = self._read(s)
|
||||
|
||||
elif tokenH == 0x50: # ascii string
|
||||
s = self._get_size(tokenL)
|
||||
- data = self._fp.read(s)
|
||||
- if len(data) != s:
|
||||
- raise InvalidFileException()
|
||||
+ data = self._read(s)
|
||||
result = data.decode('ascii')
|
||||
|
||||
elif tokenH == 0x60: # unicode string
|
||||
s = self._get_size(tokenL) * 2
|
||||
- data = self._fp.read(s)
|
||||
- if len(data) != s:
|
||||
- raise InvalidFileException()
|
||||
+ data = self._read(s)
|
||||
result = data.decode('utf-16be')
|
||||
|
||||
elif tokenH == 0x80: # UID
|
||||
diff --git a/Lib/test/test_plistlib.py b/Lib/test/test_plistlib.py
|
||||
index ef96c6ceda21a2..d3836991d212cd 100644
|
||||
--- a/Lib/test/test_plistlib.py
|
||||
+++ b/Lib/test/test_plistlib.py
|
||||
@@ -838,8 +838,7 @@ def test_xml_plist_with_entity_decl(self):
|
||||
|
||||
class TestBinaryPlistlib(unittest.TestCase):
|
||||
|
||||
- @staticmethod
|
||||
- def decode(*objects, offset_size=1, ref_size=1):
|
||||
+ def build(self, *objects, offset_size=1, ref_size=1):
|
||||
data = [b'bplist00']
|
||||
offset = 8
|
||||
offsets = []
|
||||
@@ -851,7 +850,11 @@ def decode(*objects, offset_size=1, ref_size=1):
|
||||
len(objects), 0, offset)
|
||||
data.extend(offsets)
|
||||
data.append(tail)
|
||||
- return plistlib.loads(b''.join(data), fmt=plistlib.FMT_BINARY)
|
||||
+ return b''.join(data)
|
||||
+
|
||||
+ def decode(self, *objects, offset_size=1, ref_size=1):
|
||||
+ data = self.build(*objects, offset_size=offset_size, ref_size=ref_size)
|
||||
+ return plistlib.loads(data, fmt=plistlib.FMT_BINARY)
|
||||
|
||||
def test_nonstandard_refs_size(self):
|
||||
# Issue #21538: Refs and offsets are 24-bit integers
|
||||
@@ -959,6 +962,34 @@ def test_invalid_binary(self):
|
||||
with self.assertRaises(plistlib.InvalidFileException):
|
||||
plistlib.loads(b'bplist00' + data, fmt=plistlib.FMT_BINARY)
|
||||
|
||||
+ def test_truncated_large_data(self):
|
||||
+ self.addCleanup(os_helper.unlink, os_helper.TESTFN)
|
||||
+ def check(data):
|
||||
+ with open(os_helper.TESTFN, 'wb') as f:
|
||||
+ f.write(data)
|
||||
+ # buffered file
|
||||
+ with open(os_helper.TESTFN, 'rb') as f:
|
||||
+ with self.assertRaises(plistlib.InvalidFileException):
|
||||
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
|
||||
+ # unbuffered file
|
||||
+ with open(os_helper.TESTFN, 'rb', buffering=0) as f:
|
||||
+ with self.assertRaises(plistlib.InvalidFileException):
|
||||
+ plistlib.load(f, fmt=plistlib.FMT_BINARY)
|
||||
+ for w in range(20, 64):
|
||||
+ s = 1 << w
|
||||
+ # data
|
||||
+ check(self.build(b'\x4f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # ascii string
|
||||
+ check(self.build(b'\x5f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # unicode string
|
||||
+ check(self.build(b'\x6f\x13' + s.to_bytes(8, 'big')))
|
||||
+ # array
|
||||
+ check(self.build(b'\xaf\x13' + s.to_bytes(8, 'big')))
|
||||
+ # dict
|
||||
+ check(self.build(b'\xdf\x13' + s.to_bytes(8, 'big')))
|
||||
+ # number of objects
|
||||
+ check(b'bplist00' + struct.pack('>6xBBQQQ', 1, 1, s, 0, 8))
|
||||
+
|
||||
|
||||
class TestKeyedArchive(unittest.TestCase):
|
||||
def test_keyed_archive_data(self):
|
||||
diff --git a/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..04fd8faca4cf7e
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2024-05-21-22-11-31.gh-issue-119342.BTFj4Z.rst
|
||||
@@ -0,0 +1,5 @@
|
||||
+Fix a potential memory denial of service in the :mod:`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 :exc:`MemoryError`, swapping, out
|
||||
+of memory (OOM) killed processes or containers, or even system crashes.
|
||||
@@ -8,27 +8,19 @@ Subject: [PATCH] [3.10] gh-143925: Reject control characters in data: URL
|
||||
|
||||
Co-authored-by: Seth Michael Larson <seth@python.org>
|
||||
---
|
||||
Lib/test/test_urllib.py | 8 ++++++++
|
||||
Lib/test/test_urllib.py | 7 +++++++
|
||||
Lib/urllib/request.py | 5 +++++
|
||||
Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst | 1 +
|
||||
3 files changed, 14 insertions(+)
|
||||
3 files changed, 13 insertions(+)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
|
||||
|
||||
Index: Python-3.10.19/Lib/test/test_urllib.py
|
||||
Index: Python-3.10.20/Lib/test/test_urllib.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_urllib.py 2026-02-12 01:05:56.127447144 +0100
|
||||
+++ Python-3.10.19/Lib/test/test_urllib.py 2026-02-12 01:08:02.226352573 +0100
|
||||
@@ -11,6 +11,7 @@
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
from test.support import warnings_helper
|
||||
+from test.support import control_characters_c0
|
||||
import os
|
||||
try:
|
||||
import ssl
|
||||
@@ -683,6 +684,13 @@
|
||||
# missing padding character
|
||||
self.assertRaises(ValueError,urllib.request.urlopen,'data:;base64,Cg=')
|
||||
--- Python-3.10.20.orig/Lib/test/test_urllib.py 2026-03-05 19:39:02.061358156 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_urllib.py 2026-03-05 23:19:43.575732909 +0100
|
||||
@@ -607,6 +607,13 @@
|
||||
"https://localhost", cafile="/nonexistent/path", context=context
|
||||
)
|
||||
|
||||
+ def test_invalid_mediatype(self):
|
||||
+ for c0 in control_characters_c0():
|
||||
@@ -38,15 +30,15 @@ Index: Python-3.10.19/Lib/test/test_urllib.py
|
||||
+ self.assertRaises(ValueError,urllib.request.urlopen,
|
||||
+ f'data:text/html{c0};base64,ZGF0YQ==')
|
||||
|
||||
class urlretrieve_FileTests(unittest.TestCase):
|
||||
"""Test urllib.urlretrieve() on local files"""
|
||||
Index: Python-3.10.19/Lib/urllib/request.py
|
||||
class urlopen_DataTests(unittest.TestCase):
|
||||
"""Test urlopen() opening a data URL."""
|
||||
Index: Python-3.10.20/Lib/urllib/request.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/urllib/request.py 2026-02-12 01:05:56.627830069 +0100
|
||||
+++ Python-3.10.19/Lib/urllib/request.py 2026-02-12 01:08:02.226810828 +0100
|
||||
@@ -1654,6 +1654,11 @@
|
||||
scheme, data = url.split(":",1)
|
||||
mediatype, data = data.split(",",1)
|
||||
--- Python-3.10.20.orig/Lib/urllib/request.py 2026-03-05 19:39:02.551702670 +0100
|
||||
+++ Python-3.10.20/Lib/urllib/request.py 2026-03-05 23:19:43.576415166 +0100
|
||||
@@ -1659,6 +1659,11 @@
|
||||
raise ValueError(
|
||||
"Control characters not allowed in data: mediatype")
|
||||
|
||||
+ # Disallow control characters within mediatype.
|
||||
+ if re.search(r"[\x00-\x1F\x7F]", mediatype):
|
||||
@@ -56,9 +48,9 @@ Index: Python-3.10.19/Lib/urllib/request.py
|
||||
# even base64 encoded data URLs might be quoted so unquote in any case:
|
||||
data = unquote_to_bytes(data)
|
||||
if mediatype.endswith(";base64"):
|
||||
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
|
||||
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-02-12 01:08:02.227192287 +0100
|
||||
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-51-19.gh-issue-143925.mrtcHW.rst 2026-03-05 23:19:43.576850667 +0100
|
||||
@@ -0,0 +1 @@
|
||||
+Reject control characters in ``data:`` URL media types.
|
||||
|
||||
@@ -9,10 +9,10 @@ Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters
|
||||
Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst | 1 +
|
||||
3 files changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
Index: Python-3.10.19/Lib/imaplib.py
|
||||
Index: Python-3.10.20/Lib/imaplib.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/imaplib.py 2026-02-12 01:05:53.821319313 +0100
|
||||
+++ Python-3.10.19/Lib/imaplib.py 2026-02-12 01:06:28.558652908 +0100
|
||||
--- Python-3.10.20.orig/Lib/imaplib.py 2026-03-05 19:38:59.446918283 +0100
|
||||
+++ Python-3.10.20/Lib/imaplib.py 2026-03-05 23:19:20.515035897 +0100
|
||||
@@ -132,7 +132,7 @@
|
||||
# We compile these in _mode_xxx.
|
||||
_Literal = br'.*{(?P<size>\d+)}$'
|
||||
@@ -31,10 +31,10 @@ Index: Python-3.10.19/Lib/imaplib.py
|
||||
data = data + b' ' + arg
|
||||
|
||||
literal = self.literal
|
||||
Index: Python-3.10.19/Lib/test/test_imaplib.py
|
||||
Index: Python-3.10.20/Lib/test/test_imaplib.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_imaplib.py 2026-02-12 01:05:55.293033311 +0100
|
||||
+++ Python-3.10.19/Lib/test/test_imaplib.py 2026-02-12 01:07:45.387053336 +0100
|
||||
--- Python-3.10.20.orig/Lib/test/test_imaplib.py 2026-03-05 19:39:01.155920382 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_imaplib.py 2026-03-05 23:19:20.517235411 +0100
|
||||
@@ -538,6 +538,12 @@
|
||||
self.assertEqual(data[0], b'Returned to authenticated state. (Success)')
|
||||
self.assertEqual(client.state, 'AUTH')
|
||||
@@ -48,9 +48,9 @@ Index: Python-3.10.19/Lib/test/test_imaplib.py
|
||||
|
||||
class NewIMAPTests(NewIMAPTestsMixin, unittest.TestCase):
|
||||
imap_class = imaplib.IMAP4
|
||||
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
|
||||
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-02-12 01:06:28.559224837 +0100
|
||||
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-41-06.gh-issue-143921.AeCOor.rst 2026-03-05 23:19:20.517573599 +0100
|
||||
@@ -0,0 +1 @@
|
||||
+Reject control characters in IMAP commands.
|
||||
|
||||
@@ -9,10 +9,10 @@ Subject: [PATCH 1/2] Add 'test.support' fixture for C0 control characters
|
||||
Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst | 1 +
|
||||
3 files changed, 11 insertions(+)
|
||||
|
||||
Index: Python-3.10.19/Lib/poplib.py
|
||||
Index: Python-3.10.20/Lib/poplib.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/poplib.py 2026-02-12 01:05:54.262197434 +0100
|
||||
+++ Python-3.10.19/Lib/poplib.py 2026-02-12 01:12:02.945762019 +0100
|
||||
--- Python-3.10.20.orig/Lib/poplib.py 2026-03-05 19:38:59.939747453 +0100
|
||||
+++ Python-3.10.20/Lib/poplib.py 2026-03-05 23:21:23.043850896 +0100
|
||||
@@ -122,6 +122,8 @@
|
||||
def _putcmd(self, line):
|
||||
if self._debugging: print('*cmd*', repr(line))
|
||||
@@ -22,10 +22,10 @@ Index: Python-3.10.19/Lib/poplib.py
|
||||
self._putline(line)
|
||||
|
||||
|
||||
Index: Python-3.10.19/Lib/test/test_poplib.py
|
||||
Index: Python-3.10.20/Lib/test/test_poplib.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Lib/test/test_poplib.py 2026-02-12 01:05:55.796995175 +0100
|
||||
+++ Python-3.10.19/Lib/test/test_poplib.py 2026-02-12 01:12:32.837694637 +0100
|
||||
--- Python-3.10.20.orig/Lib/test/test_poplib.py 2026-03-05 19:39:01.686377763 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_poplib.py 2026-03-05 23:21:23.044538262 +0100
|
||||
@@ -15,6 +15,7 @@
|
||||
from test.support import hashlib_helper
|
||||
from test.support import socket_helper
|
||||
@@ -48,9 +48,9 @@ Index: Python-3.10.19/Lib/test/test_poplib.py
|
||||
@requires_ssl
|
||||
def test_stls_capa(self):
|
||||
capa = self.client.capa()
|
||||
Index: Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
|
||||
Index: Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst
|
||||
===================================================================
|
||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||||
+++ Python-3.10.19/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-02-12 01:12:02.946199975 +0100
|
||||
+++ Python-3.10.20/Misc/NEWS.d/next/Security/2026-01-16-11-43-47.gh-issue-143923.DuytMe.rst 2026-03-05 23:21:23.044905845 +0100
|
||||
@@ -0,0 +1 @@
|
||||
+Reject control characters in POP3 commands.
|
||||
|
||||
@@ -1,359 +0,0 @@
|
||||
From 20044636f0d9a802c42f907934c69d46e4019a0c 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.10] 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 | 14 ++
|
||||
Lib/test/test_ntpath.py | 20 ++-
|
||||
...-05-30-22-33-27.gh-issue-136065.bu337o.rst | 1 +
|
||||
5 files changed, 93 insertions(+), 111 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 9b0cca44727fd5..bd2b4e289c17b9 100644
|
||||
--- a/Lib/ntpath.py
|
||||
+++ b/Lib/ntpath.py
|
||||
@@ -374,17 +374,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'}'
|
||||
@@ -393,94 +399,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 b8dd563ada3880..75020eef477b5e 100644
|
||||
--- a/Lib/posixpath.py
|
||||
+++ b/Lib/posixpath.py
|
||||
@@ -279,42 +279,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:
|
||||
@@ -322,13 +321,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 1ff7f75ad3e614..b0a13265c98b4e 100644
|
||||
--- a/Lib/test/test_genericpath.py
|
||||
+++ b/Lib/test/test_genericpath.py
|
||||
@@ -7,6 +7,7 @@
|
||||
import sys
|
||||
import unittest
|
||||
import warnings
|
||||
+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
|
||||
@@ -430,6 +431,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():
|
||||
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
|
||||
index f790f771f2fb6d..161e57d62a06d3 100644
|
||||
--- a/Lib/test/test_ntpath.py
|
||||
+++ b/Lib/test/test_ntpath.py
|
||||
@@ -5,8 +5,8 @@
|
||||
import unittest
|
||||
import warnings
|
||||
from ntpath import ALLOW_MISSING
|
||||
+from test import support
|
||||
from test.support import os_helper
|
||||
-from test.support import TestFailed
|
||||
from test.support.os_helper import FakePath
|
||||
from test import test_genericpath
|
||||
from tempfile import TemporaryFile
|
||||
@@ -56,7 +56,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
|
||||
@@ -72,7 +72,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)))
|
||||
|
||||
|
||||
@@ -689,6 +689,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')
|
||||
|
||||
@@ -923,6 +936,7 @@ def test_nt_helpers(self):
|
||||
self.assertIsInstance(b_final_path, bytes)
|
||||
self.assertGreater(len(b_final_path), 0)
|
||||
|
||||
+
|
||||
class NtCommonTest(test_genericpath.CommonTest, unittest.TestCase):
|
||||
pathmodule = ntpath
|
||||
attributes = ['relpath']
|
||||
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,184 +0,0 @@
|
||||
From 57c5ecd7e61fbb24e7de76eafd95332bd0ae4dea Mon Sep 17 00:00:00 2001
|
||||
From: Seth Michael Larson <seth@python.org>
|
||||
Date: Tue, 20 Jan 2026 15:23:42 -0600
|
||||
Subject: [PATCH] [3.10] gh-143919: Reject control characters in http cookies
|
||||
(cherry picked from commit 95746b3a13a985787ef53b977129041971ed7f70)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Co-authored-by: Seth Michael Larson <seth@python.org>
|
||||
Co-authored-by: Bartosz Sławecki <bartosz@ilikepython.com>
|
||||
Co-authored-by: sobolevn <mail@sobolevn.me>
|
||||
---
|
||||
Doc/library/http.cookies.rst | 4 +-
|
||||
Lib/http/cookies.py | 25 +++++++--
|
||||
Lib/test/test_http_cookies.py | 52 +++++++++++++++++--
|
||||
...-01-16-11-13-15.gh-issue-143919.kchwZV.rst | 1 +
|
||||
4 files changed, 73 insertions(+), 9 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
|
||||
|
||||
diff --git a/Doc/library/http.cookies.rst b/Doc/library/http.cookies.rst
|
||||
index a2c1eb00d8b33d..4cb563c230ea5e 100644
|
||||
--- a/Doc/library/http.cookies.rst
|
||||
+++ b/Doc/library/http.cookies.rst
|
||||
@@ -270,9 +270,9 @@ The following example demonstrates how to use the :mod:`http.cookies` module.
|
||||
Set-Cookie: chips=ahoy
|
||||
Set-Cookie: vienna=finger
|
||||
>>> C = cookies.SimpleCookie()
|
||||
- >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
|
||||
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
|
||||
>>> print(C)
|
||||
- Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
|
||||
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
|
||||
>>> C = cookies.SimpleCookie()
|
||||
>>> C["oreo"] = "doublestuff"
|
||||
>>> C["oreo"]["path"] = "/"
|
||||
diff --git a/Lib/http/cookies.py b/Lib/http/cookies.py
|
||||
index 2c1f021d0abede..5cfa7a8072c7f7 100644
|
||||
--- a/Lib/http/cookies.py
|
||||
+++ b/Lib/http/cookies.py
|
||||
@@ -87,9 +87,9 @@
|
||||
such trickeries do not confuse it.
|
||||
|
||||
>>> C = cookies.SimpleCookie()
|
||||
- >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
|
||||
+ >>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
|
||||
>>> print(C)
|
||||
- Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
|
||||
+ Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
|
||||
|
||||
Each element of the Cookie also supports all of the RFC 2109
|
||||
Cookie attributes. Here's an example which sets the Path
|
||||
@@ -170,6 +170,15 @@ class CookieError(Exception):
|
||||
})
|
||||
|
||||
_is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch
|
||||
+_control_character_re = re.compile(r'[\x00-\x1F\x7F]')
|
||||
+
|
||||
+
|
||||
+def _has_control_character(*val):
|
||||
+ """Detects control characters within a value.
|
||||
+ Supports any type, as header values can be any type.
|
||||
+ """
|
||||
+ return any(_control_character_re.search(str(v)) for v in val)
|
||||
+
|
||||
|
||||
def _quote(str):
|
||||
r"""Quote a string for use in a cookie header.
|
||||
@@ -292,12 +301,16 @@ def __setitem__(self, K, V):
|
||||
K = K.lower()
|
||||
if not K in self._reserved:
|
||||
raise CookieError("Invalid attribute %r" % (K,))
|
||||
+ if _has_control_character(K, V):
|
||||
+ raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}")
|
||||
dict.__setitem__(self, K, V)
|
||||
|
||||
def setdefault(self, key, val=None):
|
||||
key = key.lower()
|
||||
if key not in self._reserved:
|
||||
raise CookieError("Invalid attribute %r" % (key,))
|
||||
+ if _has_control_character(key, val):
|
||||
+ raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,))
|
||||
return dict.setdefault(self, key, val)
|
||||
|
||||
def __eq__(self, morsel):
|
||||
@@ -333,6 +346,9 @@ def set(self, key, val, coded_val):
|
||||
raise CookieError('Attempt to set a reserved key %r' % (key,))
|
||||
if not _is_legal_key(key):
|
||||
raise CookieError('Illegal key %r' % (key,))
|
||||
+ if _has_control_character(key, val, coded_val):
|
||||
+ raise CookieError(
|
||||
+ "Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,))
|
||||
|
||||
# It's a good key, so save it.
|
||||
self._key = key
|
||||
@@ -484,7 +500,10 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
|
||||
result = []
|
||||
items = sorted(self.items())
|
||||
for key, value in items:
|
||||
- result.append(value.output(attrs, header))
|
||||
+ value_output = value.output(attrs, header)
|
||||
+ if _has_control_character(value_output):
|
||||
+ raise CookieError("Control characters are not allowed in cookies")
|
||||
+ result.append(value_output)
|
||||
return sep.join(result)
|
||||
|
||||
__str__ = output
|
||||
diff --git a/Lib/test/test_http_cookies.py b/Lib/test/test_http_cookies.py
|
||||
index 644e75cd5b742e..1f2c049fa811fa 100644
|
||||
--- a/Lib/test/test_http_cookies.py
|
||||
+++ b/Lib/test/test_http_cookies.py
|
||||
@@ -17,10 +17,10 @@ def test_basic(self):
|
||||
'repr': "<SimpleCookie: chips='ahoy' vienna='finger'>",
|
||||
'output': 'Set-Cookie: chips=ahoy\nSet-Cookie: vienna=finger'},
|
||||
|
||||
- {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"',
|
||||
- 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=\012;'},
|
||||
- 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=\\n;'>''',
|
||||
- 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'},
|
||||
+ {'data': 'keebler="E=mc2; L=\\"Loves\\"; fudge=;"',
|
||||
+ 'dict': {'keebler' : 'E=mc2; L="Loves"; fudge=;'},
|
||||
+ 'repr': '''<SimpleCookie: keebler='E=mc2; L="Loves"; fudge=;'>''',
|
||||
+ 'output': 'Set-Cookie: keebler="E=mc2; L=\\"Loves\\"; fudge=;"'},
|
||||
|
||||
# Check illegal cookies that have an '=' char in an unquoted value
|
||||
{'data': 'keebler=E=mc2',
|
||||
@@ -517,6 +517,50 @@ def test_repr(self):
|
||||
r'Set-Cookie: key=coded_val; '
|
||||
r'expires=\w+, \d+ \w+ \d+ \d+:\d+:\d+ \w+')
|
||||
|
||||
+ def test_control_characters(self):
|
||||
+ for c0 in support.control_characters_c0():
|
||||
+ morsel = cookies.Morsel()
|
||||
+
|
||||
+ # .__setitem__()
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel[c0] = "val"
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel["path"] = c0
|
||||
+
|
||||
+ # .setdefault()
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel.setdefault("path", c0)
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel.setdefault(c0, "val")
|
||||
+
|
||||
+ # .set()
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel.set(c0, "val", "coded-value")
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel.set("path", c0, "coded-value")
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ morsel.set("path", "val", c0)
|
||||
+
|
||||
+ def test_control_characters_output(self):
|
||||
+ # Tests that even if the internals of Morsel are modified
|
||||
+ # that a call to .output() has control character safeguards.
|
||||
+ for c0 in support.control_characters_c0():
|
||||
+ morsel = cookies.Morsel()
|
||||
+ morsel.set("key", "value", "coded-value")
|
||||
+ morsel._key = c0 # Override private variable.
|
||||
+ cookie = cookies.SimpleCookie()
|
||||
+ cookie["cookie"] = morsel
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ cookie.output()
|
||||
+
|
||||
+ morsel = cookies.Morsel()
|
||||
+ morsel.set("key", "value", "coded-value")
|
||||
+ morsel._coded_value = c0 # Override private variable.
|
||||
+ cookie = cookies.SimpleCookie()
|
||||
+ cookie["cookie"] = morsel
|
||||
+ with self.assertRaises(cookies.CookieError):
|
||||
+ cookie.output()
|
||||
+
|
||||
def test_main():
|
||||
run_unittest(CookieTests, MorselTests)
|
||||
run_doctest(cookies)
|
||||
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..788c3e4ac2ebf7
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-13-15.gh-issue-143919.kchwZV.rst
|
||||
@@ -0,0 +1 @@
|
||||
+Reject control characters in :class:`http.cookies.Morsel` fields and values.
|
||||
@@ -1,97 +0,0 @@
|
||||
From 123bfbbe9074ef7fa28e1e7b25575665296560fa Mon Sep 17 00:00:00 2001
|
||||
From: "Gregory P. Smith" <68491+gpshead@users.noreply.github.com>
|
||||
Date: Sat, 17 Jan 2026 10:23:57 -0800
|
||||
Subject: [PATCH] [3.10] gh-143916: Reject control characters in
|
||||
wsgiref.headers.Headers (GH-143917) (GH-143973)
|
||||
|
||||
gh-143916: Reject control characters in wsgiref.headers.Headers (GH-143917)
|
||||
|
||||
* Add 'test.support' fixture for C0 control characters
|
||||
* gh-143916: Reject control characters in wsgiref.headers.Headers
|
||||
|
||||
(cherry picked from commit f7fceed79ca1bceae8dbe5ba5bc8928564da7211)
|
||||
(cherry picked from commit 22e4d55285cee52bc4dbe061324e5f30bd4dee58)
|
||||
|
||||
Co-authored-by: Gregory P. Smith <68491+gpshead@users.noreply.github.com>
|
||||
Co-authored-by: Seth Michael Larson <seth@python.org>
|
||||
---
|
||||
Lib/test/support/__init__.py | 7 +++++++
|
||||
Lib/test/test_wsgiref.py | 12 +++++++++++-
|
||||
Lib/wsgiref/headers.py | 3 +++
|
||||
.../2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst | 2 ++
|
||||
4 files changed, 23 insertions(+), 1 deletion(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
|
||||
|
||||
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
|
||||
index 0d3b9634f10248..d0492fe1914343 100644
|
||||
--- a/Lib/test/support/__init__.py
|
||||
+++ b/Lib/test/support/__init__.py
|
||||
@@ -2157,3 +2157,10 @@ def adjust_int_max_str_digits(max_digits):
|
||||
yield
|
||||
finally:
|
||||
sys.set_int_max_str_digits(current)
|
||||
+
|
||||
+
|
||||
+def control_characters_c0() -> list[str]:
|
||||
+ """Returns a list of C0 control characters as strings.
|
||||
+ C0 control characters defined as the byte range 0x00-0x1F, and 0x7F.
|
||||
+ """
|
||||
+ return [chr(c) for c in range(0x00, 0x20)] + ["\x7F"]
|
||||
diff --git a/Lib/test/test_wsgiref.py b/Lib/test/test_wsgiref.py
|
||||
index 42094f467731d4..01ca51ba458587 100644
|
||||
--- a/Lib/test/test_wsgiref.py
|
||||
+++ b/Lib/test/test_wsgiref.py
|
||||
@@ -1,6 +1,6 @@
|
||||
from unittest import mock
|
||||
from test import support
|
||||
-from test.support import socket_helper
|
||||
+from test.support import socket_helper, control_characters_c0
|
||||
from test.support import warnings_helper
|
||||
from test.test_httpservers import NoLogRequestHandler
|
||||
from unittest import TestCase
|
||||
@@ -527,6 +527,16 @@ def testExtras(self):
|
||||
'\r\n'
|
||||
)
|
||||
|
||||
+ def testRaisesControlCharacters(self):
|
||||
+ headers = Headers()
|
||||
+ for c0 in control_characters_c0():
|
||||
+ self.assertRaises(ValueError, headers.__setitem__, f"key{c0}", "val")
|
||||
+ self.assertRaises(ValueError, headers.__setitem__, "key", f"val{c0}")
|
||||
+ self.assertRaises(ValueError, headers.add_header, f"key{c0}", "val", param="param")
|
||||
+ self.assertRaises(ValueError, headers.add_header, "key", f"val{c0}", param="param")
|
||||
+ self.assertRaises(ValueError, headers.add_header, "key", "val", param=f"param{c0}")
|
||||
+
|
||||
+
|
||||
class ErrorHandler(BaseCGIHandler):
|
||||
"""Simple handler subclass for testing BaseHandler"""
|
||||
|
||||
diff --git a/Lib/wsgiref/headers.py b/Lib/wsgiref/headers.py
|
||||
index fab851c5a44430..fd98e85d75492b 100644
|
||||
--- a/Lib/wsgiref/headers.py
|
||||
+++ b/Lib/wsgiref/headers.py
|
||||
@@ -9,6 +9,7 @@
|
||||
# existence of which force quoting of the parameter value.
|
||||
import re
|
||||
tspecials = re.compile(r'[ \(\)<>@,;:\\"/\[\]\?=]')
|
||||
+_control_chars_re = re.compile(r'[\x00-\x1F\x7F]')
|
||||
|
||||
def _formatparam(param, value=None, quote=1):
|
||||
"""Convenience function to format and return a key=value pair.
|
||||
@@ -41,6 +42,8 @@ def __init__(self, headers=None):
|
||||
def _convert_string_type(self, value):
|
||||
"""Convert/check value type."""
|
||||
if type(value) is str:
|
||||
+ if _control_chars_re.search(value):
|
||||
+ raise ValueError("Control characters not allowed in headers")
|
||||
return value
|
||||
raise AssertionError("Header names/values must be"
|
||||
" of type str (got {0})".format(repr(value)))
|
||||
diff --git a/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
|
||||
new file mode 100644
|
||||
index 00000000000000..44bd0b27059f94
|
||||
--- /dev/null
|
||||
+++ b/Misc/NEWS.d/next/Security/2026-01-16-11-07-36.gh-issue-143916.dpWeOD.rst
|
||||
@@ -0,0 +1,2 @@
|
||||
+Reject C0 control characters within wsgiref.headers.Headers fields, values,
|
||||
+and parameters.
|
||||
BIN
Python-3.10.19.tar.xz
LFS
BIN
Python-3.10.19.tar.xz
LFS
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Python-3.10.20.tar.xz
LFS
Normal file
BIN
Python-3.10.20.tar.xz
LFS
Normal file
Binary file not shown.
1
Python-3.10.20.tar.xz.sigstore
Normal file
1
Python-3.10.20.tar.xz.sigstore
Normal file
File diff suppressed because one or more lines are too long
@@ -3,10 +3,10 @@
|
||||
Misc/NEWS | 2 +-
|
||||
2 files changed, 1 insertion(+), 4 deletions(-)
|
||||
|
||||
Index: Python-3.10.19/Doc/using/configure.rst
|
||||
Index: Python-3.10.20/Doc/using/configure.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/using/configure.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/using/configure.rst 2025-12-19 23:10:08.779794344 +0100
|
||||
--- Python-3.10.20.orig/Doc/using/configure.rst 2026-03-03 01:49:35.000000000 +0100
|
||||
+++ Python-3.10.20/Doc/using/configure.rst 2026-03-05 19:41:57.289556663 +0100
|
||||
@@ -42,7 +42,6 @@
|
||||
|
||||
See :data:`sys.int_info.bits_per_digit <sys.int_info>`.
|
||||
@@ -29,11 +29,11 @@ Index: Python-3.10.19/Doc/using/configure.rst
|
||||
.. cmdoption:: --enable-framework=INSTALLDIR
|
||||
|
||||
Create a Python.framework rather than a traditional Unix install. Optional
|
||||
Index: Python-3.10.19/Misc/NEWS
|
||||
Index: Python-3.10.20/Misc/NEWS
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Misc/NEWS 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Misc/NEWS 2025-12-19 23:10:08.784479751 +0100
|
||||
@@ -4018,7 +4018,7 @@
|
||||
--- Python-3.10.20.orig/Misc/NEWS 2026-03-03 01:49:35.000000000 +0100
|
||||
+++ Python-3.10.20/Misc/NEWS 2026-03-05 19:41:57.302556681 +0100
|
||||
@@ -4112,7 +4112,7 @@
|
||||
-----
|
||||
|
||||
- bpo-43795: The list in :ref:`stable-abi-list` now shows the public name
|
||||
|
||||
@@ -1,3 +1,92 @@
|
||||
-------------------------------------------------------------------
|
||||
Thu Mar 5 18:38:39 UTC 2026 - Matej Cepl <mcepl@cepl.eu>
|
||||
|
||||
- Update to 3.10.20:
|
||||
- Security
|
||||
- gh-144125: BytesGenerator will now refuse to serialize
|
||||
(write) headers that are unsafely folded or delimited; see
|
||||
verify_generated_headers. (Contributed by Bas Bloemsaat and
|
||||
Petr Viktorin in gh-121650).
|
||||
- gh-143935: Fixed a bug in the folding of comments when
|
||||
flattening an email message using a modern email policy.
|
||||
Comments consisting of a very long sequence of non-foldable
|
||||
characters could trigger a forced line wrap that omitted
|
||||
the required leading space on the continuation line,
|
||||
causing the remainder of the comment to be interpreted as
|
||||
a new header field. This enabled header injection with
|
||||
carefully crafted inputs (bsc#1257029 CVE-2025-11468).
|
||||
- gh-143925: Reject control characters in data: URL media
|
||||
types.
|
||||
- gh-143919: Reject control characters in http.cookies.Morsel
|
||||
fields and values (bsc#1257031, CVE-2026-0672).
|
||||
- gh-143916: Reject C0 control characters within
|
||||
wsgiref.headers.Headers fields, values, and parameters
|
||||
(bsc#1257042, CVE-2026-0865).
|
||||
- gh-142145: Remove quadratic behavior in xml.minidom node ID
|
||||
cache clearing. In order to do this without breaking
|
||||
existing users, we also add the ownerDocument attribute to
|
||||
xml.dom.minidom elements and attributes created by directly
|
||||
instantiating the Element or Attr class. Note that this way
|
||||
of creating nodes is not supported; creator functions like
|
||||
xml.dom.Document.documentElement() should be used instead
|
||||
(bsc#1254997, CVE-2025-12084).
|
||||
- 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() (bsc#1252974, CVE-2025-6075).
|
||||
- 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-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.
|
||||
- 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
|
||||
(bsc#1254401, CVE-2025-13837).
|
||||
- Library
|
||||
- gh-144833: Fixed a use-after-free in ssl when SSL_new()
|
||||
returns NULL in newPySSLSocket(). The error was reported
|
||||
via a dangling pointer after the object had already been
|
||||
freed.
|
||||
- gh-144363: Update bundled libexpat to 2.7.4
|
||||
- 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.
|
||||
- Core and Builtins
|
||||
- gh-120384: Fix an array out of bounds crash in
|
||||
list_ass_subscript, which could be invoked via some
|
||||
specificly tailored input: including concurrent
|
||||
modification of a list object, where one thread assigns
|
||||
a slice and another clears it.
|
||||
- gh-120298: Fix use-after free in list_richcompare_impl
|
||||
which can be invoked via some specificly tailored evil
|
||||
input.
|
||||
- Remove upstreamed patches:
|
||||
- CVE-2025-11468-email-hdr-fold-comment.patch
|
||||
- CVE-2025-12084-minidom-quad-search.patch
|
||||
- CVE-2025-13836-http-resp-cont-len.patch
|
||||
- CVE-2025-13837-plistlib-mailicious-length.patch
|
||||
- CVE-2025-6075-expandvars-perf-degrad.patch
|
||||
- CVE-2026-0672-http-hdr-inject-cookie-Morsel.patch
|
||||
- CVE-2026-0865-wsgiref-ctrl-chars.patch
|
||||
|
||||
-------------------------------------------------------------------
|
||||
Wed Feb 11 23:49:49 CET 2026 - Matej Cepl <mcepl@suse.com>
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ Obsoletes: python39%{?1:-%{1}}
|
||||
# _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.10.19
|
||||
Version: 3.10.20
|
||||
Release: 0
|
||||
Summary: Python 3 Interpreter
|
||||
License: Python-2.0
|
||||
|
||||
434
sphinx-72.patch
434
sphinx-72.patch
@@ -73,10 +73,10 @@
|
||||
Doc/tutorial/stdlib.rst | 2
|
||||
72 files changed, 458 insertions(+), 427 deletions(-)
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/bytearray.rst
|
||||
Index: Python-3.10.20/Doc/c-api/bytearray.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/bytearray.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/bytearray.rst 2025-12-19 23:10:15.391446431 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/bytearray.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/bytearray.rst 2026-03-05 19:42:18.969673759 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Byte Array Objects
|
||||
------------------
|
||||
@@ -86,10 +86,10 @@ Index: Python-3.10.19/Doc/c-api/bytearray.rst
|
||||
|
||||
|
||||
.. c:type:: PyByteArrayObject
|
||||
Index: Python-3.10.19/Doc/c-api/bytes.rst
|
||||
Index: Python-3.10.20/Doc/c-api/bytes.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/bytes.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/bytes.rst 2025-12-19 23:10:15.391922542 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/bytes.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/bytes.rst 2026-03-05 19:42:18.970100765 +0100
|
||||
@@ -8,7 +8,7 @@
|
||||
These functions raise :exc:`TypeError` when expecting a bytes parameter and
|
||||
called with a non-bytes parameter.
|
||||
@@ -99,10 +99,10 @@ Index: Python-3.10.19/Doc/c-api/bytes.rst
|
||||
|
||||
|
||||
.. c:type:: PyBytesObject
|
||||
Index: Python-3.10.19/Doc/c-api/capsule.rst
|
||||
Index: Python-3.10.20/Doc/c-api/capsule.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/capsule.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/capsule.rst 2025-12-19 23:10:15.392109858 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/capsule.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/capsule.rst 2026-03-05 19:42:18.970312835 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Capsules
|
||||
--------
|
||||
@@ -112,10 +112,10 @@ Index: Python-3.10.19/Doc/c-api/capsule.rst
|
||||
|
||||
Refer to :ref:`using-capsules` for more information on using these objects.
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/complex.rst
|
||||
Index: Python-3.10.20/Doc/c-api/complex.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/complex.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/complex.rst 2025-12-19 23:10:15.392289421 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/complex.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/complex.rst 2026-03-05 19:42:18.970503093 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Complex Number Objects
|
||||
----------------------
|
||||
@@ -125,10 +125,10 @@ Index: Python-3.10.19/Doc/c-api/complex.rst
|
||||
|
||||
Python's complex number objects are implemented as two distinct types when
|
||||
viewed from the C API: one is the Python object exposed to Python programs, and
|
||||
Index: Python-3.10.19/Doc/c-api/concrete.rst
|
||||
Index: Python-3.10.20/Doc/c-api/concrete.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/concrete.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/concrete.rst 2025-12-19 23:10:15.392466051 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/concrete.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/concrete.rst 2026-03-05 19:42:18.970750049 +0100
|
||||
@@ -40,7 +40,7 @@
|
||||
Numeric Objects
|
||||
===============
|
||||
@@ -156,10 +156,10 @@ Index: Python-3.10.19/Doc/c-api/concrete.rst
|
||||
|
||||
.. toctree::
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/dict.rst
|
||||
Index: Python-3.10.20/Doc/c-api/dict.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/dict.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/dict.rst 2025-12-19 23:10:15.392652110 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/dict.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/dict.rst 2026-03-05 19:42:18.970944416 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Dictionary Objects
|
||||
------------------
|
||||
@@ -178,10 +178,10 @@ Index: Python-3.10.19/Doc/c-api/dict.rst
|
||||
|
||||
Return the number of items in the dictionary. This is equivalent to
|
||||
``len(p)`` on a dictionary.
|
||||
Index: Python-3.10.19/Doc/c-api/exceptions.rst
|
||||
Index: Python-3.10.20/Doc/c-api/exceptions.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/exceptions.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/exceptions.rst 2025-12-19 23:10:15.392896207 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/exceptions.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/exceptions.rst 2026-03-05 19:42:18.971230595 +0100
|
||||
@@ -503,7 +503,7 @@
|
||||
.. c:function:: int PyErr_CheckSignals()
|
||||
|
||||
@@ -209,10 +209,10 @@ Index: Python-3.10.19/Doc/c-api/exceptions.rst
|
||||
single: KeyboardInterrupt (built-in exception)
|
||||
|
||||
Simulate the effect of a signal arriving. The next time
|
||||
Index: Python-3.10.19/Doc/c-api/file.rst
|
||||
Index: Python-3.10.20/Doc/c-api/file.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/file.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/file.rst 2025-12-19 23:10:15.393159161 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/file.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/file.rst 2026-03-05 19:42:18.971537043 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
File Objects
|
||||
------------
|
||||
@@ -222,10 +222,10 @@ Index: Python-3.10.19/Doc/c-api/file.rst
|
||||
|
||||
These APIs are a minimal emulation of the Python 2 C API for built-in file
|
||||
objects, which used to rely on the buffered I/O (:c:expr:`FILE*`) support
|
||||
Index: Python-3.10.19/Doc/c-api/float.rst
|
||||
Index: Python-3.10.20/Doc/c-api/float.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/float.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/float.rst 2025-12-19 23:10:15.393330204 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/float.rst 2026-03-05 19:42:16.336584040 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/float.rst 2026-03-05 19:42:18.971720008 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Floating Point Objects
|
||||
----------------------
|
||||
@@ -235,10 +235,10 @@ Index: Python-3.10.19/Doc/c-api/float.rst
|
||||
|
||||
|
||||
.. c:type:: PyFloatObject
|
||||
Index: Python-3.10.19/Doc/c-api/function.rst
|
||||
Index: Python-3.10.20/Doc/c-api/function.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/function.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/function.rst 2025-12-19 23:10:15.393493494 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/function.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/function.rst 2026-03-05 19:42:18.971899246 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Function Objects
|
||||
----------------
|
||||
@@ -248,10 +248,10 @@ Index: Python-3.10.19/Doc/c-api/function.rst
|
||||
|
||||
There are a few functions specific to Python functions.
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/import.rst
|
||||
Index: Python-3.10.20/Doc/c-api/import.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/import.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/import.rst 2025-12-19 23:10:15.393679483 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/import.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/import.rst 2026-03-05 19:42:18.972099725 +0100
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
.. c:function:: PyObject* PyImport_ImportModuleEx(const char *name, PyObject *globals, PyObject *locals, PyObject *fromlist)
|
||||
@@ -270,10 +270,10 @@ Index: Python-3.10.19/Doc/c-api/import.rst
|
||||
|
||||
Given a module name (possibly of the form ``package.module``) and a code object
|
||||
read from a Python bytecode file or obtained from the built-in function
|
||||
Index: Python-3.10.19/Doc/c-api/init.rst
|
||||
Index: Python-3.10.20/Doc/c-api/init.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/init.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/init.rst 2025-12-19 23:10:15.393955078 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/init.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/init.rst 2026-03-05 19:42:18.972397676 +0100
|
||||
@@ -233,9 +233,9 @@
|
||||
single: PyEval_InitThreads()
|
||||
single: modules (in module sys)
|
||||
@@ -309,10 +309,10 @@ Index: Python-3.10.19/Doc/c-api/init.rst
|
||||
single: stdout (in module sys)
|
||||
single: stderr (in module sys)
|
||||
single: stdin (in module sys)
|
||||
Index: Python-3.10.19/Doc/c-api/intro.rst
|
||||
Index: Python-3.10.20/Doc/c-api/intro.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/intro.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/intro.rst 2025-12-19 23:10:15.394470650 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/intro.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/intro.rst 2026-03-05 19:42:18.972771231 +0100
|
||||
@@ -226,7 +226,7 @@
|
||||
Objects, Types and Reference Counts
|
||||
===================================
|
||||
@@ -335,10 +335,10 @@ Index: Python-3.10.19/Doc/c-api/intro.rst
|
||||
triple: module; search; path
|
||||
single: path (in module sys)
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/list.rst
|
||||
Index: Python-3.10.20/Doc/c-api/list.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/list.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/list.rst 2025-12-19 23:10:15.394763148 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/list.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/list.rst 2026-03-05 19:42:18.973088189 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
List Objects
|
||||
------------
|
||||
@@ -366,10 +366,10 @@ Index: Python-3.10.19/Doc/c-api/list.rst
|
||||
|
||||
Return a new tuple object containing the contents of *list*; equivalent to
|
||||
``tuple(list)``.
|
||||
Index: Python-3.10.19/Doc/c-api/long.rst
|
||||
Index: Python-3.10.20/Doc/c-api/long.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/long.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/long.rst 2025-12-19 23:10:15.394948159 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/long.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/long.rst 2026-03-05 19:42:18.973340364 +0100
|
||||
@@ -5,8 +5,8 @@
|
||||
Integer Objects
|
||||
---------------
|
||||
@@ -381,10 +381,10 @@ Index: Python-3.10.19/Doc/c-api/long.rst
|
||||
|
||||
All integers are implemented as "long" integer objects of arbitrary size.
|
||||
|
||||
Index: Python-3.10.19/Doc/c-api/mapping.rst
|
||||
Index: Python-3.10.20/Doc/c-api/mapping.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/mapping.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/mapping.rst 2025-12-19 23:10:15.395138967 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/mapping.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/mapping.rst 2026-03-05 19:42:18.973549118 +0100
|
||||
@@ -20,7 +20,7 @@
|
||||
.. c:function:: Py_ssize_t PyMapping_Size(PyObject *o)
|
||||
Py_ssize_t PyMapping_Length(PyObject *o)
|
||||
@@ -394,10 +394,10 @@ Index: Python-3.10.19/Doc/c-api/mapping.rst
|
||||
|
||||
Returns the number of keys in object *o* on success, and ``-1`` on failure.
|
||||
This is equivalent to the Python expression ``len(o)``.
|
||||
Index: Python-3.10.19/Doc/c-api/memoryview.rst
|
||||
Index: Python-3.10.20/Doc/c-api/memoryview.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/memoryview.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/memoryview.rst 2025-12-19 23:10:15.395300231 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/memoryview.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/memoryview.rst 2026-03-05 19:42:18.973728286 +0100
|
||||
@@ -3,7 +3,7 @@
|
||||
.. _memoryview-objects:
|
||||
|
||||
@@ -407,10 +407,10 @@ Index: Python-3.10.19/Doc/c-api/memoryview.rst
|
||||
|
||||
MemoryView objects
|
||||
------------------
|
||||
Index: Python-3.10.19/Doc/c-api/method.rst
|
||||
Index: Python-3.10.20/Doc/c-api/method.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/method.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/method.rst 2025-12-19 23:10:15.395505706 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/method.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/method.rst 2026-03-05 19:42:18.973936919 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Instance Method Objects
|
||||
-----------------------
|
||||
@@ -429,10 +429,10 @@ Index: Python-3.10.19/Doc/c-api/method.rst
|
||||
|
||||
Methods are bound function objects. Methods are always bound to an instance of
|
||||
a user-defined class. Unbound methods (methods bound to a class object) are
|
||||
Index: Python-3.10.19/Doc/c-api/module.rst
|
||||
Index: Python-3.10.20/Doc/c-api/module.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/module.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/module.rst 2025-12-19 23:10:15.395739397 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/module.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/module.rst 2026-03-05 19:42:18.974150622 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Module Objects
|
||||
--------------
|
||||
@@ -442,10 +442,10 @@ Index: Python-3.10.19/Doc/c-api/module.rst
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyModule_Type
|
||||
Index: Python-3.10.19/Doc/c-api/none.rst
|
||||
Index: Python-3.10.20/Doc/c-api/none.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/none.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/none.rst 2025-12-19 23:10:15.395955557 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/none.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/none.rst 2026-03-05 19:42:18.974386076 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
The ``None`` Object
|
||||
-------------------
|
||||
@@ -455,10 +455,10 @@ Index: Python-3.10.19/Doc/c-api/none.rst
|
||||
|
||||
Note that the :c:type:`PyTypeObject` for ``None`` is not directly exposed in the
|
||||
Python/C API. Since ``None`` is a singleton, testing for object identity (using
|
||||
Index: Python-3.10.19/Doc/c-api/number.rst
|
||||
Index: Python-3.10.20/Doc/c-api/number.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/number.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/number.rst 2025-12-19 23:10:15.396155514 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/number.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/number.rst 2026-03-05 19:42:18.974581886 +0100
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
.. c:function:: PyObject* PyNumber_Divmod(PyObject *o1, PyObject *o2)
|
||||
@@ -513,10 +513,10 @@ Index: Python-3.10.19/Doc/c-api/number.rst
|
||||
|
||||
Returns the *o* converted to a float object on success, or ``NULL`` on failure.
|
||||
This is the equivalent of the Python expression ``float(o)``.
|
||||
Index: Python-3.10.19/Doc/c-api/object.rst
|
||||
Index: Python-3.10.20/Doc/c-api/object.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/object.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/object.rst 2025-12-19 23:10:15.396357217 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/object.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/object.rst 2026-03-05 19:42:18.974799656 +0100
|
||||
@@ -172,7 +172,7 @@
|
||||
|
||||
.. c:function:: PyObject* PyObject_Repr(PyObject *o)
|
||||
@@ -571,10 +571,10 @@ Index: Python-3.10.19/Doc/c-api/object.rst
|
||||
|
||||
Return the length of object *o*. If the object *o* provides either the sequence
|
||||
and mapping protocols, the sequence length is returned. On error, ``-1`` is
|
||||
Index: Python-3.10.19/Doc/c-api/sequence.rst
|
||||
Index: Python-3.10.20/Doc/c-api/sequence.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/sequence.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/sequence.rst 2025-12-19 23:10:15.396594610 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/sequence.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/sequence.rst 2026-03-05 19:42:18.975049317 +0100
|
||||
@@ -18,7 +18,7 @@
|
||||
.. c:function:: Py_ssize_t PySequence_Size(PyObject *o)
|
||||
Py_ssize_t PySequence_Length(PyObject *o)
|
||||
@@ -593,10 +593,10 @@ Index: Python-3.10.19/Doc/c-api/sequence.rst
|
||||
|
||||
Return a tuple object with the same contents as the sequence or iterable *o*,
|
||||
or ``NULL`` on failure. If *o* is a tuple, a new reference will be returned,
|
||||
Index: Python-3.10.19/Doc/c-api/set.rst
|
||||
Index: Python-3.10.20/Doc/c-api/set.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/set.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/set.rst 2025-12-19 23:10:15.396771519 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/set.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/set.rst 2026-03-05 19:42:18.975306692 +0100
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
|
||||
@@ -617,10 +617,10 @@ Index: Python-3.10.19/Doc/c-api/set.rst
|
||||
|
||||
Return the length of a :class:`set` or :class:`frozenset` object. Equivalent to
|
||||
``len(anyset)``. Raises a :exc:`PyExc_SystemError` if *anyset* is not a
|
||||
Index: Python-3.10.19/Doc/c-api/structures.rst
|
||||
Index: Python-3.10.20/Doc/c-api/structures.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/structures.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/structures.rst 2025-12-19 23:10:15.396945495 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/structures.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/structures.rst 2026-03-05 19:42:18.975635963 +0100
|
||||
@@ -351,7 +351,7 @@
|
||||
|
||||
.. data:: METH_CLASS
|
||||
@@ -639,10 +639,10 @@ Index: Python-3.10.19/Doc/c-api/structures.rst
|
||||
|
||||
The method will be passed ``NULL`` as the first parameter rather than an
|
||||
instance of the type. This is used to create *static methods*, similar to
|
||||
Index: Python-3.10.19/Doc/c-api/tuple.rst
|
||||
Index: Python-3.10.20/Doc/c-api/tuple.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/tuple.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/tuple.rst 2025-12-19 23:10:15.397144544 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/tuple.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/tuple.rst 2026-03-05 19:42:18.975888880 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Tuple Objects
|
||||
-------------
|
||||
@@ -652,10 +652,10 @@ Index: Python-3.10.19/Doc/c-api/tuple.rst
|
||||
|
||||
|
||||
.. c:type:: PyTupleObject
|
||||
Index: Python-3.10.19/Doc/c-api/type.rst
|
||||
Index: Python-3.10.20/Doc/c-api/type.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/type.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/type.rst 2025-12-19 23:10:15.397329764 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/type.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/type.rst 2026-03-05 19:42:18.976188766 +0100
|
||||
@@ -5,7 +5,7 @@
|
||||
Type Objects
|
||||
------------
|
||||
@@ -665,10 +665,10 @@ Index: Python-3.10.19/Doc/c-api/type.rst
|
||||
|
||||
|
||||
.. c:type:: PyTypeObject
|
||||
Index: Python-3.10.19/Doc/c-api/typeobj.rst
|
||||
Index: Python-3.10.20/Doc/c-api/typeobj.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/c-api/typeobj.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/c-api/typeobj.rst 2025-12-19 23:10:15.397446400 +0100
|
||||
--- Python-3.10.20.orig/Doc/c-api/typeobj.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/c-api/typeobj.rst 2026-03-05 19:42:18.976565316 +0100
|
||||
@@ -803,7 +803,7 @@
|
||||
|
||||
.. c:member:: reprfunc PyTypeObject.tp_repr
|
||||
@@ -687,10 +687,10 @@ Index: Python-3.10.19/Doc/c-api/typeobj.rst
|
||||
|
||||
An optional pointer to a function that implements the built-in function
|
||||
:func:`hash`.
|
||||
Index: Python-3.10.19/Doc/conf.py
|
||||
Index: Python-3.10.20/Doc/conf.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/conf.py 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/conf.py 2025-12-19 23:10:15.398083707 +0100
|
||||
--- Python-3.10.20.orig/Doc/conf.py 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/conf.py 2026-03-05 19:42:18.977099103 +0100
|
||||
@@ -61,6 +61,11 @@
|
||||
# Avoid a warning with Sphinx >= 2.0
|
||||
master_doc = 'contents'
|
||||
@@ -703,10 +703,10 @@ Index: Python-3.10.19/Doc/conf.py
|
||||
# Options for HTML output
|
||||
# -----------------------
|
||||
|
||||
Index: Python-3.10.19/Doc/extending/newtypes.rst
|
||||
Index: Python-3.10.20/Doc/extending/newtypes.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/extending/newtypes.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/extending/newtypes.rst 2025-12-19 23:10:15.398298470 +0100
|
||||
--- Python-3.10.20.orig/Doc/extending/newtypes.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/extending/newtypes.rst 2026-03-05 19:42:18.977417513 +0100
|
||||
@@ -149,7 +149,7 @@
|
||||
|
||||
.. index::
|
||||
@@ -716,10 +716,10 @@ Index: Python-3.10.19/Doc/extending/newtypes.rst
|
||||
|
||||
Object Presentation
|
||||
-------------------
|
||||
Index: Python-3.10.19/Doc/library/_thread.rst
|
||||
Index: Python-3.10.20/Doc/library/_thread.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/_thread.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/_thread.rst 2025-12-19 23:10:15.398608428 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/_thread.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/_thread.rst 2026-03-05 19:42:18.977812839 +0100
|
||||
@@ -204,7 +204,7 @@
|
||||
|
||||
**Caveats:**
|
||||
@@ -729,10 +729,10 @@ Index: Python-3.10.19/Doc/library/_thread.rst
|
||||
|
||||
* Threads interact strangely with interrupts: the :exc:`KeyboardInterrupt`
|
||||
exception will be received by an arbitrary thread. (When the :mod:`signal`
|
||||
Index: Python-3.10.19/Doc/library/binascii.rst
|
||||
Index: Python-3.10.20/Doc/library/binascii.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/binascii.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/binascii.rst 2025-12-19 23:10:15.398847287 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/binascii.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/binascii.rst 2026-03-05 19:42:18.978168049 +0100
|
||||
@@ -6,9 +6,9 @@
|
||||
representations.
|
||||
|
||||
@@ -746,10 +746,10 @@ Index: Python-3.10.19/Doc/library/binascii.rst
|
||||
|
||||
--------------
|
||||
|
||||
Index: Python-3.10.19/Doc/library/cmath.rst
|
||||
Index: Python-3.10.20/Doc/library/cmath.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/cmath.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/cmath.rst 2025-12-19 23:10:15.399084959 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/cmath.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/cmath.rst 2026-03-05 19:42:18.978445211 +0100
|
||||
@@ -301,7 +301,7 @@
|
||||
.. versionadded:: 3.6
|
||||
|
||||
@@ -759,10 +759,10 @@ Index: Python-3.10.19/Doc/library/cmath.rst
|
||||
|
||||
Note that the selection of functions is similar, but not identical, to that in
|
||||
module :mod:`math`. The reason for having two modules is that some users aren't
|
||||
Index: Python-3.10.19/Doc/library/copy.rst
|
||||
Index: Python-3.10.20/Doc/library/copy.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/copy.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/copy.rst 2025-12-19 23:10:15.399270528 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/copy.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/copy.rst 2026-03-05 19:42:18.978728956 +0100
|
||||
@@ -68,7 +68,7 @@
|
||||
of lists by assigning a slice of the entire list, for example,
|
||||
``copied_list = original_list[:]``.
|
||||
@@ -772,10 +772,10 @@ Index: Python-3.10.19/Doc/library/copy.rst
|
||||
|
||||
Classes can use the same interfaces to control copying that they use to control
|
||||
pickling. See the description of module :mod:`pickle` for information on these
|
||||
Index: Python-3.10.19/Doc/library/copyreg.rst
|
||||
Index: Python-3.10.20/Doc/library/copyreg.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/copyreg.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/copyreg.rst 2025-12-19 23:10:15.399461755 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/copyreg.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/copyreg.rst 2026-03-05 19:42:18.978924325 +0100
|
||||
@@ -7,8 +7,8 @@
|
||||
**Source code:** :source:`Lib/copyreg.py`
|
||||
|
||||
@@ -787,10 +787,10 @@ Index: Python-3.10.19/Doc/library/copyreg.rst
|
||||
|
||||
--------------
|
||||
|
||||
Index: Python-3.10.19/Doc/library/dis.rst
|
||||
Index: Python-3.10.20/Doc/library/dis.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/dis.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/dis.rst 2025-12-19 23:10:15.399767732 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/dis.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/dis.rst 2026-03-05 19:42:18.979174547 +0100
|
||||
@@ -1207,7 +1207,7 @@
|
||||
|
||||
.. opcode:: BUILD_SLICE (argc)
|
||||
@@ -800,10 +800,10 @@ Index: Python-3.10.19/Doc/library/dis.rst
|
||||
|
||||
Pushes a slice object on the stack. *argc* must be 2 or 3. If it is 2,
|
||||
``slice(TOS1, TOS)`` is pushed; if it is 3, ``slice(TOS2, TOS1, TOS)`` is
|
||||
Index: Python-3.10.19/Doc/library/email.compat32-message.rst
|
||||
Index: Python-3.10.20/Doc/library/email.compat32-message.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/email.compat32-message.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/email.compat32-message.rst 2025-12-19 23:10:15.400042699 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/email.compat32-message.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/email.compat32-message.rst 2026-03-05 19:42:18.979546769 +0100
|
||||
@@ -7,6 +7,7 @@
|
||||
:synopsis: The base class representing email messages in a fashion
|
||||
backward compatible with Python 3.2
|
||||
@@ -812,10 +812,10 @@ Index: Python-3.10.19/Doc/library/email.compat32-message.rst
|
||||
|
||||
|
||||
The :class:`Message` class is very similar to the
|
||||
Index: Python-3.10.19/Doc/library/exceptions.rst
|
||||
Index: Python-3.10.20/Doc/library/exceptions.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/exceptions.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/exceptions.rst 2025-12-19 23:10:15.400305095 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/exceptions.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/exceptions.rst 2026-03-05 19:42:18.979875649 +0100
|
||||
@@ -4,8 +4,8 @@
|
||||
===================
|
||||
|
||||
@@ -854,10 +854,10 @@ Index: Python-3.10.19/Doc/library/exceptions.rst
|
||||
|
||||
This exception is raised when a system function returns a system-related
|
||||
error, including I/O failures such as "file not found" or "disk full"
|
||||
Index: Python-3.10.19/Doc/library/fnmatch.rst
|
||||
Index: Python-3.10.20/Doc/library/fnmatch.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/fnmatch.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/fnmatch.rst 2025-12-19 23:10:15.400595567 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/fnmatch.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/fnmatch.rst 2026-03-05 19:42:18.980208527 +0100
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
.. index:: single: filenames; wildcard expansion
|
||||
@@ -876,10 +876,10 @@ Index: Python-3.10.19/Doc/library/fnmatch.rst
|
||||
|
||||
Note that the filename separator (``'/'`` on Unix) is *not* special to this
|
||||
module. See module :mod:`glob` for pathname expansion (:mod:`glob` uses
|
||||
Index: Python-3.10.19/Doc/library/functions.rst
|
||||
Index: Python-3.10.20/Doc/library/functions.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/functions.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/functions.rst 2025-12-19 23:10:15.400828071 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/functions.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/functions.rst 2026-03-05 19:42:18.980496911 +0100
|
||||
@@ -548,7 +548,7 @@
|
||||
Raises an :ref:`auditing event <auditing>` ``exec`` with the code object
|
||||
as the argument. Code compilation events may also be raised.
|
||||
@@ -918,10 +918,10 @@ Index: Python-3.10.19/Doc/library/functions.rst
|
||||
|
||||
.. note::
|
||||
|
||||
Index: Python-3.10.19/Doc/library/http.client.rst
|
||||
Index: Python-3.10.20/Doc/library/http.client.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/http.client.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/http.client.rst 2025-12-19 23:10:15.401177908 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/http.client.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/http.client.rst 2026-03-05 19:42:18.980925559 +0100
|
||||
@@ -10,7 +10,7 @@
|
||||
pair: HTTP; protocol
|
||||
single: HTTP; http.client (standard module)
|
||||
@@ -931,10 +931,10 @@ Index: Python-3.10.19/Doc/library/http.client.rst
|
||||
|
||||
--------------
|
||||
|
||||
Index: Python-3.10.19/Doc/library/imp.rst
|
||||
Index: Python-3.10.20/Doc/library/imp.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/imp.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/imp.rst 2025-12-19 23:10:15.401419561 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/imp.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/imp.rst 2026-03-05 19:42:18.981246615 +0100
|
||||
@@ -10,7 +10,7 @@
|
||||
.. deprecated:: 3.4
|
||||
The :mod:`imp` module is deprecated in favor of :mod:`importlib`.
|
||||
@@ -944,10 +944,10 @@ Index: Python-3.10.19/Doc/library/imp.rst
|
||||
|
||||
--------------
|
||||
|
||||
Index: Python-3.10.19/Doc/library/internet.rst
|
||||
Index: Python-3.10.20/Doc/library/internet.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/internet.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/internet.rst 2025-12-19 23:10:15.401643543 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/internet.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/internet.rst 2026-03-05 19:42:18.981489052 +0100
|
||||
@@ -9,7 +9,7 @@
|
||||
single: Internet
|
||||
single: World Wide Web
|
||||
@@ -957,10 +957,10 @@ Index: Python-3.10.19/Doc/library/internet.rst
|
||||
|
||||
The modules described in this chapter implement internet protocols and support
|
||||
for related technology. They are all implemented in Python. Most of these
|
||||
Index: Python-3.10.19/Doc/library/locale.rst
|
||||
Index: Python-3.10.20/Doc/library/locale.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/locale.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/locale.rst 2025-12-19 23:10:15.401831697 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/locale.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/locale.rst 2026-03-05 19:42:18.981763630 +0100
|
||||
@@ -16,7 +16,7 @@
|
||||
certain cultural issues in an application, without requiring the programmer to
|
||||
know all the specifics of each country where the software is executed.
|
||||
@@ -979,10 +979,10 @@ Index: Python-3.10.19/Doc/library/locale.rst
|
||||
|
||||
Locale category for the character type functions. Depending on the settings of
|
||||
this category, the functions of module :mod:`string` dealing with case change
|
||||
Index: Python-3.10.19/Doc/library/marshal.rst
|
||||
Index: Python-3.10.20/Doc/library/marshal.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/marshal.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/marshal.rst 2025-12-19 23:10:15.402080194 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/marshal.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/marshal.rst 2026-03-05 19:42:18.982052574 +0100
|
||||
@@ -15,8 +15,8 @@
|
||||
rarely does). [#]_
|
||||
|
||||
@@ -994,11 +994,11 @@ Index: Python-3.10.19/Doc/library/marshal.rst
|
||||
|
||||
This is not a general "persistence" module. For general persistence and
|
||||
transfer of Python objects through RPC calls, see the modules :mod:`pickle` and
|
||||
Index: Python-3.10.19/Doc/library/os.path.rst
|
||||
Index: Python-3.10.20/Doc/library/os.path.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/os.path.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/os.path.rst 2025-12-19 23:10:15.402271561 +0100
|
||||
@@ -159,7 +159,7 @@
|
||||
--- Python-3.10.20.orig/Doc/library/os.path.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/os.path.rst 2026-03-05 19:42:18.982385091 +0100
|
||||
@@ -161,7 +161,7 @@
|
||||
On Unix and Windows, return the argument with an initial component of ``~`` or
|
||||
``~user`` replaced by that *user*'s home directory.
|
||||
|
||||
@@ -1007,10 +1007,10 @@ Index: Python-3.10.19/Doc/library/os.path.rst
|
||||
|
||||
On Unix, an initial ``~`` is replaced by the environment variable :envvar:`HOME`
|
||||
if it is set; otherwise the current user's home directory is looked up in the
|
||||
Index: Python-3.10.19/Doc/library/os.rst
|
||||
Index: Python-3.10.20/Doc/library/os.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/os.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/os.rst 2025-12-19 23:10:15.402446375 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/os.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/os.rst 2026-03-05 19:42:18.982587843 +0100
|
||||
@@ -1136,7 +1136,7 @@
|
||||
|
||||
.. function:: openpty()
|
||||
@@ -1029,10 +1029,10 @@ Index: Python-3.10.19/Doc/library/os.rst
|
||||
|
||||
Example::
|
||||
|
||||
Index: Python-3.10.19/Doc/library/pdb.rst
|
||||
Index: Python-3.10.20/Doc/library/pdb.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/pdb.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/pdb.rst 2025-12-19 23:10:15.403432541 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/pdb.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/pdb.rst 2026-03-05 19:42:18.983778239 +0100
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
.. index::
|
||||
@@ -1044,10 +1044,10 @@ Index: Python-3.10.19/Doc/library/pdb.rst
|
||||
|
||||
The debugger is extensible -- it is actually defined as the class :class:`Pdb`.
|
||||
This is currently undocumented but easily understood by reading the source. The
|
||||
Index: Python-3.10.19/Doc/library/posix.rst
|
||||
Index: Python-3.10.20/Doc/library/posix.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/posix.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/posix.rst 2025-12-19 23:10:15.403681946 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/posix.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/posix.rst 2026-03-05 19:42:18.984101268 +0100
|
||||
@@ -11,7 +11,7 @@
|
||||
standardized by the C Standard and the POSIX standard (a thinly disguised Unix
|
||||
interface).
|
||||
@@ -1057,10 +1057,10 @@ Index: Python-3.10.19/Doc/library/posix.rst
|
||||
|
||||
**Do not import this module directly.** Instead, import the module :mod:`os`,
|
||||
which provides a *portable* version of this interface. On Unix, the :mod:`os`
|
||||
Index: Python-3.10.19/Doc/library/pprint.rst
|
||||
Index: Python-3.10.20/Doc/library/pprint.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/pprint.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/pprint.rst 2025-12-19 23:10:15.403862208 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/pprint.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/pprint.rst 2026-03-05 19:42:18.984325922 +0100
|
||||
@@ -171,7 +171,7 @@
|
||||
|
||||
.. function:: isreadable(object)
|
||||
@@ -1079,10 +1079,10 @@ Index: Python-3.10.19/Doc/library/pprint.rst
|
||||
|
||||
Determine if the formatted representation of the object is "readable," or can be
|
||||
used to reconstruct the value using :func:`eval`. Note that this returns
|
||||
Index: Python-3.10.19/Doc/library/pwd.rst
|
||||
Index: Python-3.10.20/Doc/library/pwd.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/pwd.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/pwd.rst 2025-12-19 23:10:15.404074457 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/pwd.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/pwd.rst 2026-03-05 19:42:18.984577957 +0100
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
.. note::
|
||||
@@ -1092,10 +1092,10 @@ Index: Python-3.10.19/Doc/library/pwd.rst
|
||||
|
||||
In traditional Unix the field ``pw_passwd`` usually contains a password
|
||||
encrypted with a DES derived algorithm (see module :mod:`crypt`). However most
|
||||
Index: Python-3.10.19/Doc/library/pyexpat.rst
|
||||
Index: Python-3.10.20/Doc/library/pyexpat.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/pyexpat.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/pyexpat.rst 2025-12-19 23:10:15.404269595 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/pyexpat.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/pyexpat.rst 2026-03-05 19:42:18.984818931 +0100
|
||||
@@ -33,7 +33,7 @@
|
||||
parser, the handler functions are called for the character data and markup in
|
||||
the XML document.
|
||||
@@ -1105,10 +1105,10 @@ Index: Python-3.10.19/Doc/library/pyexpat.rst
|
||||
|
||||
This module uses the :mod:`pyexpat` module to provide access to the Expat
|
||||
parser. Direct use of the :mod:`pyexpat` module is deprecated.
|
||||
Index: Python-3.10.19/Doc/library/runpy.rst
|
||||
Index: Python-3.10.20/Doc/library/runpy.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/runpy.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/runpy.rst 2025-12-19 23:10:15.404446365 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/runpy.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/runpy.rst 2026-03-05 19:42:18.985177187 +0100
|
||||
@@ -30,7 +30,7 @@
|
||||
.. function:: run_module(mod_name, init_globals=None, run_name=None, alter_sys=False)
|
||||
|
||||
@@ -1127,10 +1127,10 @@ Index: Python-3.10.19/Doc/library/runpy.rst
|
||||
|
||||
Execute the code at the named filesystem location and return the resulting
|
||||
module globals dictionary. As with a script name supplied to the CPython
|
||||
Index: Python-3.10.19/Doc/library/shelve.rst
|
||||
Index: Python-3.10.20/Doc/library/shelve.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/shelve.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/shelve.rst 2025-12-19 23:10:15.404878127 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/shelve.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/shelve.rst 2026-03-05 19:42:18.985415677 +0100
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
**Source code:** :source:`Lib/shelve.py`
|
||||
@@ -1151,10 +1151,10 @@ Index: Python-3.10.19/Doc/library/shelve.rst
|
||||
|
||||
* The choice of which database package will be used (such as :mod:`dbm.ndbm` or
|
||||
:mod:`dbm.gnu`) depends on which interface is available. Therefore it is not
|
||||
Index: Python-3.10.19/Doc/library/site.rst
|
||||
Index: Python-3.10.20/Doc/library/site.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/site.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/site.rst 2025-12-19 23:10:15.405113354 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/site.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/site.rst 2026-03-05 19:42:18.985669245 +0100
|
||||
@@ -51,7 +51,7 @@
|
||||
|
||||
.. index::
|
||||
@@ -1182,10 +1182,10 @@ Index: Python-3.10.19/Doc/library/site.rst
|
||||
|
||||
After this, an attempt is made to import a module named :mod:`usercustomize`,
|
||||
which can perform arbitrary user-specific customizations, if
|
||||
Index: Python-3.10.19/Doc/library/socket.rst
|
||||
Index: Python-3.10.20/Doc/library/socket.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/socket.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/socket.rst 2025-12-19 23:10:15.405446360 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/socket.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/socket.rst 2026-03-05 19:42:18.986046306 +0100
|
||||
@@ -16,7 +16,7 @@
|
||||
Some behavior may be platform dependent, since calls are made to the operating
|
||||
system socket APIs.
|
||||
@@ -1204,10 +1204,10 @@ Index: Python-3.10.19/Doc/library/socket.rst
|
||||
|
||||
Set the value of the given socket option (see the Unix manual page
|
||||
:manpage:`setsockopt(2)`). The needed symbolic constants are defined in the
|
||||
Index: Python-3.10.19/Doc/library/stdtypes.rst
|
||||
Index: Python-3.10.20/Doc/library/stdtypes.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/stdtypes.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/stdtypes.rst 2025-12-19 23:10:15.406446355 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/stdtypes.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/stdtypes.rst 2026-03-05 19:42:18.986972964 +0100
|
||||
@@ -32,8 +32,8 @@
|
||||
===================
|
||||
|
||||
@@ -1583,10 +1583,10 @@ Index: Python-3.10.19/Doc/library/stdtypes.rst
|
||||
|
||||
Type objects represent the various object types. An object's type is accessed
|
||||
by the built-in function :func:`type`. There are no special operations on
|
||||
Index: Python-3.10.19/Doc/library/sys.rst
|
||||
Index: Python-3.10.20/Doc/library/sys.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/sys.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/sys.rst 2025-12-19 23:10:15.406880072 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/sys.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/sys.rst 2026-03-05 19:42:18.987990342 +0100
|
||||
@@ -398,7 +398,7 @@
|
||||
an except clause." For any stack frame, only information about the exception
|
||||
being currently handled is accessible.
|
||||
@@ -1596,10 +1596,10 @@ Index: Python-3.10.19/Doc/library/sys.rst
|
||||
|
||||
If no exception is being handled anywhere on the stack, a tuple containing
|
||||
three ``None`` values is returned. Otherwise, the values returned are
|
||||
Index: Python-3.10.19/Doc/library/traceback.rst
|
||||
Index: Python-3.10.20/Doc/library/traceback.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/traceback.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/traceback.rst 2025-12-19 23:10:15.407220202 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/traceback.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/traceback.rst 2026-03-05 19:42:18.988443998 +0100
|
||||
@@ -14,7 +14,7 @@
|
||||
stack traces under program control, such as in a "wrapper" around the
|
||||
interpreter.
|
||||
@@ -1609,10 +1609,10 @@ Index: Python-3.10.19/Doc/library/traceback.rst
|
||||
|
||||
The module uses traceback objects --- this is the object type that is stored in
|
||||
the :data:`sys.last_traceback` variable and returned as the third item from
|
||||
Index: Python-3.10.19/Doc/library/types.rst
|
||||
Index: Python-3.10.20/Doc/library/types.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/library/types.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/library/types.rst 2025-12-19 23:10:15.407463391 +0100
|
||||
--- Python-3.10.20.orig/Doc/library/types.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/library/types.rst 2026-03-05 19:42:18.988791784 +0100
|
||||
@@ -146,7 +146,7 @@
|
||||
|
||||
.. class:: CodeType(**kwargs)
|
||||
@@ -1622,10 +1622,10 @@ Index: Python-3.10.19/Doc/library/types.rst
|
||||
|
||||
The type for code objects such as returned by :func:`compile`.
|
||||
|
||||
Index: Python-3.10.19/Doc/reference/compound_stmts.rst
|
||||
Index: Python-3.10.20/Doc/reference/compound_stmts.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/compound_stmts.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/compound_stmts.rst 2025-12-19 23:10:15.407774397 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/compound_stmts.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/compound_stmts.rst 2026-03-05 19:42:18.989240841 +0100
|
||||
@@ -84,9 +84,9 @@
|
||||
============================
|
||||
|
||||
@@ -1855,10 +1855,10 @@ Index: Python-3.10.19/Doc/reference/compound_stmts.rst
|
||||
.. _`async with`:
|
||||
|
||||
The :keyword:`!async with` statement
|
||||
Index: Python-3.10.19/Doc/reference/datamodel.rst
|
||||
Index: Python-3.10.20/Doc/reference/datamodel.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/datamodel.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/datamodel.rst 2025-12-19 23:10:15.408446345 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/datamodel.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/datamodel.rst 2026-03-05 19:42:18.989869737 +0100
|
||||
@@ -21,8 +21,8 @@
|
||||
represented by objects.)
|
||||
|
||||
@@ -2371,10 +2371,10 @@ Index: Python-3.10.19/Doc/reference/datamodel.rst
|
||||
single: context manager
|
||||
|
||||
Typical uses of context managers include saving and restoring various kinds of
|
||||
Index: Python-3.10.19/Doc/reference/executionmodel.rst
|
||||
Index: Python-3.10.20/Doc/reference/executionmodel.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/executionmodel.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/executionmodel.rst 2025-12-19 23:10:15.408910164 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/executionmodel.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/executionmodel.rst 2026-03-05 19:42:18.990617928 +0100
|
||||
@@ -151,7 +151,7 @@
|
||||
:exc:`SyntaxError` is raised at compile time if the given name does not
|
||||
exist in any enclosing function scope.
|
||||
@@ -2384,10 +2384,10 @@ Index: Python-3.10.19/Doc/reference/executionmodel.rst
|
||||
|
||||
The namespace for a module is automatically created the first time a module is
|
||||
imported. The main module for a script is always called :mod:`__main__`.
|
||||
Index: Python-3.10.19/Doc/reference/expressions.rst
|
||||
Index: Python-3.10.20/Doc/reference/expressions.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/expressions.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/expressions.rst 2025-12-19 23:10:15.409155938 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/expressions.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/expressions.rst 2026-03-05 19:42:18.990933533 +0100
|
||||
@@ -71,7 +71,7 @@
|
||||
for lexical definition and section :ref:`naming` for documentation of naming and
|
||||
binding.
|
||||
@@ -2794,10 +2794,10 @@ Index: Python-3.10.19/Doc/reference/expressions.rst
|
||||
|
||||
Except when part of a list or set display, an expression list
|
||||
containing at least one comma yields a tuple. The length of
|
||||
Index: Python-3.10.19/Doc/reference/simple_stmts.rst
|
||||
Index: Python-3.10.20/Doc/reference/simple_stmts.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/simple_stmts.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/simple_stmts.rst 2025-12-19 23:10:15.409656983 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/simple_stmts.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/simple_stmts.rst 2026-03-05 19:42:18.991596393 +0100
|
||||
@@ -53,8 +53,8 @@
|
||||
expression).
|
||||
|
||||
@@ -3039,10 +3039,10 @@ Index: Python-3.10.19/Doc/reference/simple_stmts.rst
|
||||
single: , (comma); identifier list
|
||||
|
||||
.. productionlist:: python-grammar
|
||||
Index: Python-3.10.19/Doc/reference/toplevel_components.rst
|
||||
Index: Python-3.10.20/Doc/reference/toplevel_components.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/reference/toplevel_components.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/reference/toplevel_components.rst 2025-12-19 23:10:15.409991385 +0100
|
||||
--- Python-3.10.20.orig/Doc/reference/toplevel_components.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/reference/toplevel_components.rst 2026-03-05 19:42:18.991994343 +0100
|
||||
@@ -21,9 +21,9 @@
|
||||
.. index:: single: program
|
||||
|
||||
@@ -3074,10 +3074,10 @@ Index: Python-3.10.19/Doc/reference/toplevel_components.rst
|
||||
|
||||
:func:`eval` is used for expression input. It ignores leading whitespace. The
|
||||
string argument to :func:`eval` must have the following form:
|
||||
Index: Python-3.10.19/Doc/tools/extensions/pyspecific.py
|
||||
Index: Python-3.10.20/Doc/tools/extensions/pyspecific.py
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tools/extensions/pyspecific.py 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tools/extensions/pyspecific.py 2025-12-19 23:10:15.410328302 +0100
|
||||
--- Python-3.10.20.orig/Doc/tools/extensions/pyspecific.py 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tools/extensions/pyspecific.py 2026-03-05 19:42:18.992268971 +0100
|
||||
@@ -644,6 +644,30 @@
|
||||
node.replace_self(table)
|
||||
|
||||
@@ -3117,10 +3117,10 @@ Index: Python-3.10.19/Doc/tools/extensions/pyspecific.py
|
||||
app.connect('doctree-resolved', process_audit_events)
|
||||
app.connect('env-merge-info', audit_events_merge)
|
||||
app.connect('env-purge-doc', audit_events_purge)
|
||||
Index: Python-3.10.19/Doc/tutorial/classes.rst
|
||||
Index: Python-3.10.20/Doc/tutorial/classes.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tutorial/classes.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tutorial/classes.rst 2025-12-19 23:10:15.410720534 +0100
|
||||
--- Python-3.10.20.orig/Doc/tutorial/classes.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tutorial/classes.rst 2026-03-05 19:42:18.992758014 +0100
|
||||
@@ -344,7 +344,7 @@
|
||||
However, in the following discussion, we'll use the term method exclusively to
|
||||
mean methods of class instance objects, unless explicitly stated otherwise.)
|
||||
@@ -3130,10 +3130,10 @@ Index: Python-3.10.19/Doc/tutorial/classes.rst
|
||||
|
||||
Valid method names of an instance object depend on its class. By definition,
|
||||
all attributes of a class that are function objects define corresponding
|
||||
Index: Python-3.10.19/Doc/tutorial/controlflow.rst
|
||||
Index: Python-3.10.20/Doc/tutorial/controlflow.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tutorial/controlflow.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tutorial/controlflow.rst 2025-12-19 23:10:15.411043971 +0100
|
||||
--- Python-3.10.20.orig/Doc/tutorial/controlflow.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tutorial/controlflow.rst 2026-03-05 19:42:18.993212891 +0100
|
||||
@@ -46,7 +46,7 @@
|
||||
==========================
|
||||
|
||||
@@ -3143,10 +3143,10 @@ Index: Python-3.10.19/Doc/tutorial/controlflow.rst
|
||||
|
||||
The :keyword:`for` statement in Python differs a bit from what you may be used
|
||||
to in C or Pascal. Rather than always iterating over an arithmetic progression
|
||||
Index: Python-3.10.19/Doc/tutorial/inputoutput.rst
|
||||
Index: Python-3.10.20/Doc/tutorial/inputoutput.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tutorial/inputoutput.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tutorial/inputoutput.rst 2025-12-19 23:10:15.411308183 +0100
|
||||
--- Python-3.10.20.orig/Doc/tutorial/inputoutput.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tutorial/inputoutput.rst 2026-03-05 19:42:18.993527254 +0100
|
||||
@@ -285,8 +285,8 @@
|
||||
=========================
|
||||
|
||||
@@ -3167,10 +3167,10 @@ Index: Python-3.10.19/Doc/tutorial/inputoutput.rst
|
||||
|
||||
Strings can easily be written to and read from a file. Numbers take a bit more
|
||||
effort, since the :meth:`read` method only returns strings, which will have to
|
||||
Index: Python-3.10.19/Doc/tutorial/modules.rst
|
||||
Index: Python-3.10.20/Doc/tutorial/modules.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tutorial/modules.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tutorial/modules.rst 2025-12-19 23:10:15.411539499 +0100
|
||||
--- Python-3.10.20.orig/Doc/tutorial/modules.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tutorial/modules.rst 2026-03-05 19:42:18.993796923 +0100
|
||||
@@ -260,7 +260,7 @@
|
||||
Standard Modules
|
||||
================
|
||||
@@ -3189,10 +3189,10 @@ Index: Python-3.10.19/Doc/tutorial/modules.rst
|
||||
|
||||
:func:`dir` does not list the names of built-in functions and variables. If you
|
||||
want a list of those, they are defined in the standard module
|
||||
Index: Python-3.10.19/Doc/tutorial/stdlib.rst
|
||||
Index: Python-3.10.20/Doc/tutorial/stdlib.rst
|
||||
===================================================================
|
||||
--- Python-3.10.19.orig/Doc/tutorial/stdlib.rst 2025-10-09 17:25:03.000000000 +0200
|
||||
+++ Python-3.10.19/Doc/tutorial/stdlib.rst 2025-12-19 23:10:15.411769907 +0100
|
||||
--- Python-3.10.20.orig/Doc/tutorial/stdlib.rst 2026-03-05 19:42:16.337584041 +0100
|
||||
+++ Python-3.10.20/Doc/tutorial/stdlib.rst 2026-03-05 19:42:18.994160168 +0100
|
||||
@@ -24,7 +24,7 @@
|
||||
will keep :func:`os.open` from shadowing the built-in :func:`open` function which
|
||||
operates much differently.
|
||||
|
||||
@@ -27,17 +27,19 @@ Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
|
||||
1 file changed, 9 insertions(+), 14 deletions(-)
|
||||
create mode 100644 Misc/NEWS.d/next/Library/2022-02-20-21-03-31.bpo-46811.8BxgdQ.rst
|
||||
|
||||
--- a/Lib/test/test_minidom.py
|
||||
+++ b/Lib/test/test_minidom.py
|
||||
@@ -6,7 +6,6 @@ import io
|
||||
Index: Python-3.10.20/Lib/test/test_minidom.py
|
||||
===================================================================
|
||||
--- Python-3.10.20.orig/Lib/test/test_minidom.py 2026-03-05 19:39:01.567696516 +0100
|
||||
+++ Python-3.10.20/Lib/test/test_minidom.py 2026-03-05 19:42:02.323563898 +0100
|
||||
@@ -7,7 +7,6 @@
|
||||
from test import support
|
||||
import unittest
|
||||
|
||||
-import pyexpat
|
||||
import xml.dom.minidom
|
||||
|
||||
from xml.dom.minidom import parse, Attr, Node, Document, parseString
|
||||
@@ -1163,13 +1162,11 @@ class MinidomTest(unittest.TestCase):
|
||||
from xml.dom.minidom import parse, Attr, Node, Document, Element, parseString
|
||||
@@ -1194,13 +1193,11 @@
|
||||
|
||||
# Verify that character decoding errors raise exceptions instead
|
||||
# of crashing
|
||||
@@ -56,7 +58,7 @@ Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
|
||||
b'<fran\xe7ais>Comment \xe7a va ? Tr\xe8s bien ?</fran\xe7ais>')
|
||||
|
||||
doc.unlink()
|
||||
@@ -1631,12 +1628,10 @@ class MinidomTest(unittest.TestCase):
|
||||
@@ -1662,12 +1659,10 @@
|
||||
self.confirm(doc2.namespaceURI == xml.dom.EMPTY_NAMESPACE)
|
||||
|
||||
def testExceptionOnSpacesInXMLNSValue(self):
|
||||
|
||||
Reference in New Issue
Block a user