forked from pool/python313
Compare commits
115 Commits
| Author | SHA256 | Date | |
|---|---|---|---|
| b1df85c06b | |||
| 976c4e0cef | |||
| 871f5c3f10 | |||
| 37d407017e | |||
| 92b79e3223 | |||
| 3a1acd0d11 | |||
| adca6dee9d | |||
| 2abd69687b | |||
| 9a9b32e012 | |||
| 07a0902464 | |||
| 0bf1e0de48 | |||
| eb5e4cd13f | |||
| a5239f3134 | |||
| eaae274dc4 | |||
| 719d910757 | |||
| 836ffcda65 | |||
| dc9a88a0ec | |||
| a10fb63256 | |||
| e4f03691c0 | |||
| 3def3a278d | |||
| 6ccd98d9bb | |||
| 9ca0c40ae3 | |||
| 395f30367f | |||
| 6efef2d138 | |||
| d2b706c283 | |||
| 6b8c3a8e15 | |||
| e09d046cb9 | |||
| 8966bd89d2 | |||
| 30fabf621d | |||
| d1dd8decb1 | |||
| 4e7fbe78f1 | |||
| 6c5ffdb7d1 | |||
| fb81f0c95c | |||
| 7697c02d21 | |||
| 12f6ddbda4 | |||
| 8412211e61 | |||
| 3375f039d6 | |||
| 45096711fd | |||
| 3ab9737306 | |||
| 47d752bbc6 | |||
| 12d36f6d19 | |||
| cf22122d9a | |||
| 7775db5668 | |||
| 1a68b995e6 | |||
| a5731deb52 | |||
| d4c1e47d44 | |||
| 03c870434a | |||
| abfd0ea83d | |||
| e5ccabe5d6 | |||
| 45b3270bb2 | |||
| 8ea0be1078 | |||
| 5017722c2b | |||
| b4ab74738f | |||
| 07a89b44e8 | |||
| 162040ca05 | |||
| d35133fd4e | |||
| 537e68d716 | |||
| a53af73990 | |||
| 1e2a0f61a9 | |||
| a5a443b789 | |||
| 32830d09d0 | |||
| d4b9fa2439 | |||
| e781d820b1 | |||
| 78ba84f9b1 | |||
| 0da0cdfdf4 | |||
| 888af93a0c | |||
| 308255a772 | |||
| a3ff8ce797 | |||
| 608d0c1bfd | |||
| 48b8355786 | |||
| 4352698329 | |||
| 001d1a2a20 | |||
| 6787a9f29d | |||
| 1221d1c8e1 | |||
| 59a4965535 | |||
| 0a0564a0e9 | |||
| c7b43c0f60 | |||
| b97ac57404 | |||
| 041b675fd8 | |||
| 5886778811 | |||
| 11a8661cb2 | |||
| 1ef6a75b82 | |||
| 74a0bc0ca2 | |||
| b1061c18e5 | |||
| b154095872 | |||
| 069357c85b | |||
| 2a2ec95344 | |||
| 517ba388ca | |||
| a80b53565d | |||
| 8e7a85bd98 | |||
| 45a1da448a | |||
| ed93a74c21 | |||
| 8be8178387 | |||
| 8f89a6f1a9 | |||
| 58dda96c93 | |||
| 5a06fe7d3f | |||
| 2a85f6bbe8 | |||
| ed786f6cde | |||
| 4e91415a72 | |||
| f99fa3b4a5 | |||
| 2120051248 | |||
| 7eaae69a60 | |||
| a4dc42ba84 | |||
| ee738c9b79 | |||
| 447b043d69 | |||
| d51b4f3c7a | |||
| 46a04323e0 | |||
| 4dc8935b4f | |||
| 4a63e4ee14 | |||
| 8e49b262ea | |||
| edaef6893c | |||
| 5eff57c396 | |||
| cf67592415 | |||
| 9bce840ac0 | |||
| c9d84fa1ca |
@@ -1,67 +0,0 @@
|
|||||||
---
|
|
||||||
Lib/test/test_pyexpat.py | 4 ++++
|
|
||||||
Lib/test/test_sax.py | 3 +++
|
|
||||||
Lib/test/test_xml_etree.py | 10 ++++++++++
|
|
||||||
3 files changed, 17 insertions(+)
|
|
||||||
|
|
||||||
--- a/Lib/test/test_pyexpat.py
|
|
||||||
+++ b/Lib/test/test_pyexpat.py
|
|
||||||
@@ -791,6 +791,10 @@ class ReparseDeferralTest(unittest.TestC
|
|
||||||
self.assertEqual(started, ['doc'])
|
|
||||||
|
|
||||||
def test_reparse_deferral_disabled(self):
|
|
||||||
+ if expat.version_info < (2, 6, 0):
|
|
||||||
+ self.skipTest(f'Expat {expat.version_info} does not '
|
|
||||||
+ 'support reparse deferral')
|
|
||||||
+
|
|
||||||
started = []
|
|
||||||
|
|
||||||
def start_element(name, _):
|
|
||||||
--- a/Lib/test/test_sax.py
|
|
||||||
+++ b/Lib/test/test_sax.py
|
|
||||||
@@ -1240,6 +1240,9 @@ class ExpatReaderTest(XmlTestBase):
|
|
||||||
|
|
||||||
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
|
|
||||||
|
|
||||||
+ @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
|
|
||||||
+ f'Expat {pyexpat.version_info} does not '
|
|
||||||
+ 'support reparse deferral')
|
|
||||||
def test_flush_reparse_deferral_disabled(self):
|
|
||||||
result = BytesIO()
|
|
||||||
xmlgen = XMLGenerator(result)
|
|
||||||
--- a/Lib/test/test_xml_etree.py
|
|
||||||
+++ b/Lib/test/test_xml_etree.py
|
|
||||||
@@ -121,6 +121,11 @@ ATTLIST_XML = """\
|
|
||||||
</foo>
|
|
||||||
"""
|
|
||||||
|
|
||||||
+IS_SLE_15_7 = os.environ.get("SLE_VERSION", "") == "0150700"
|
|
||||||
+fails_with_expat_2_6_0 = (unittest.expectedFailure
|
|
||||||
+ # 2.4 version patched in SLE
|
|
||||||
+ if IS_SLE_15_7 and pyexpat.version_info >= (2, 4, 0) else
|
|
||||||
+ lambda test: test)
|
|
||||||
def checkwarnings(*filters, quiet=False):
|
|
||||||
def decorator(test):
|
|
||||||
def newtest(*args, **kwargs):
|
|
||||||
@@ -1504,9 +1509,11 @@ class XMLPullParserTest(unittest.TestCas
|
|
||||||
self.assert_event_tags(parser, [('end', 'root')])
|
|
||||||
self.assertIsNone(parser.close())
|
|
||||||
|
|
||||||
+ @fails_with_expat_2_6_0
|
|
||||||
def test_simple_xml_chunk_1(self):
|
|
||||||
self.test_simple_xml(chunk_size=1, flush=True)
|
|
||||||
|
|
||||||
+ @fails_with_expat_2_6_0
|
|
||||||
def test_simple_xml_chunk_5(self):
|
|
||||||
self.test_simple_xml(chunk_size=5, flush=True)
|
|
||||||
|
|
||||||
@@ -1731,6 +1738,9 @@ class XMLPullParserTest(unittest.TestCas
|
|
||||||
|
|
||||||
self.assert_event_tags(parser, [('end', 'doc')])
|
|
||||||
|
|
||||||
+ @unittest.skipIf(pyexpat.version_info < (2, 6, 0),
|
|
||||||
+ f'Expat {pyexpat.version_info} does not '
|
|
||||||
+ 'support reparse deferral')
|
|
||||||
def test_flush_reparse_deferral_disabled(self):
|
|
||||||
parser = ET.XMLPullParser(events=('start', 'end'))
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
From bfc2e93d755bf496e5ef4cae9609d2823122c909 Mon Sep 17 00:00:00 2001
|
|
||||||
From: "J. Nick Koston" <nick@koston.org>
|
|
||||||
Date: Thu, 5 Dec 2024 10:01:10 -0600
|
|
||||||
Subject: [PATCH 01/10] Ensure writelines pauses the protocol if needed
|
|
||||||
|
|
||||||
---
|
|
||||||
Lib/asyncio/selector_events.py | 1
|
|
||||||
Lib/test/test_asyncio/test_selector_events.py | 12 ++++++++++
|
|
||||||
Misc/NEWS.d/next/Security/2024-12-05-21-35-19.gh-issue-127655.xpPoOf.rst | 1
|
|
||||||
3 files changed, 14 insertions(+)
|
|
||||||
|
|
||||||
--- a/Lib/asyncio/selector_events.py
|
|
||||||
+++ b/Lib/asyncio/selector_events.py
|
|
||||||
@@ -1175,6 +1175,7 @@ class _SelectorSocketTransport(_Selector
|
|
||||||
# If the entire buffer couldn't be written, register a write handler
|
|
||||||
if self._buffer:
|
|
||||||
self._loop._add_writer(self._sock_fd, self._write_ready)
|
|
||||||
+ self._maybe_pause_protocol()
|
|
||||||
|
|
||||||
def can_write_eof(self):
|
|
||||||
return True
|
|
||||||
--- a/Lib/test/test_asyncio/test_selector_events.py
|
|
||||||
+++ b/Lib/test/test_asyncio/test_selector_events.py
|
|
||||||
@@ -805,6 +805,18 @@ class SelectorSocketTransportTests(test_
|
|
||||||
self.assertTrue(self.sock.send.called)
|
|
||||||
self.assertTrue(self.loop.writers)
|
|
||||||
|
|
||||||
+ def test_writelines_pauses_protocol(self):
|
|
||||||
+ data = memoryview(b'data')
|
|
||||||
+ self.sock.send.return_value = 2
|
|
||||||
+ self.sock.send.fileno.return_value = 7
|
|
||||||
+
|
|
||||||
+ transport = self.socket_transport()
|
|
||||||
+ transport._high_water = 1
|
|
||||||
+ transport.writelines([data])
|
|
||||||
+ self.assertTrue(self.protocol.pause_writing.called)
|
|
||||||
+ self.assertTrue(self.sock.send.called)
|
|
||||||
+ self.assertTrue(self.loop.writers)
|
|
||||||
+
|
|
||||||
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
|
|
||||||
def test_write_sendmsg_full(self):
|
|
||||||
data = memoryview(b'data')
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/Misc/NEWS.d/next/Security/2024-12-05-21-35-19.gh-issue-127655.xpPoOf.rst
|
|
||||||
@@ -0,0 +1 @@
|
|
||||||
+Fixed the :class:`!asyncio.selector_events._SelectorSocketTransport` transport not pausing writes for the protocol when the buffer reaches the high water mark when using :meth:`asyncio.WriteTransport.writelines`.
|
|
||||||
@@ -1,483 +0,0 @@
|
|||||||
From 0afcdf15f64273dc5e4ed12ea63a01f7f1136d71 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
|
||||||
Date: Mon, 12 May 2025 20:42:23 +0300
|
|
||||||
Subject: [PATCH] [3.13] gh-133767: Fix use-after-free in the unicode-escape
|
|
||||||
decoder with an error handler (GH-129648)
|
|
||||||
|
|
||||||
If the error handler is used, a new bytes object is created to set as
|
|
||||||
the object attribute of UnicodeDecodeError, and that bytes object then
|
|
||||||
replaces the original data. A pointer to the decoded data will became invalid
|
|
||||||
after destroying that temporary bytes object. So we need other way to return
|
|
||||||
the first invalid escape from _PyUnicode_DecodeUnicodeEscapeInternal().
|
|
||||||
|
|
||||||
_PyBytes_DecodeEscape() does not have such issue, because it does not
|
|
||||||
use the error handlers registry, but it should be changed for compatibility
|
|
||||||
with _PyUnicode_DecodeUnicodeEscapeInternal().
|
|
||||||
(cherry picked from commit 9f69a58623bd01349a18ba0c7a9cb1dad6a51e8e)
|
|
||||||
|
|
||||||
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
|
|
||||||
---
|
|
||||||
Include/internal/pycore_bytesobject.h | 5
|
|
||||||
Include/internal/pycore_unicodeobject.h | 12 +-
|
|
||||||
Lib/test/test_codeccallbacks.py | 39 +++++++
|
|
||||||
Lib/test/test_codecs.py | 52 ++++++++--
|
|
||||||
Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst | 2
|
|
||||||
Objects/bytesobject.c | 41 ++++---
|
|
||||||
Objects/unicodeobject.c | 46 +++++---
|
|
||||||
Parser/string_parser.c | 26 +++--
|
|
||||||
8 files changed, 160 insertions(+), 63 deletions(-)
|
|
||||||
create mode 100644 Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
|
|
||||||
|
|
||||||
Index: Python-3.13.3/Include/internal/pycore_bytesobject.h
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Include/internal/pycore_bytesobject.h 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Include/internal/pycore_bytesobject.h 2025-05-17 07:33:22.001814947 +0000
|
|
||||||
@@ -20,8 +20,9 @@
|
|
||||||
|
|
||||||
// Helper for PyBytes_DecodeEscape that detects invalid escape chars.
|
|
||||||
// Export for test_peg_generator.
|
|
||||||
-PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape(const char *, Py_ssize_t,
|
|
||||||
- const char *, const char **);
|
|
||||||
+PyAPI_FUNC(PyObject*) _PyBytes_DecodeEscape2(const char *, Py_ssize_t,
|
|
||||||
+ const char *,
|
|
||||||
+ int *, const char **);
|
|
||||||
|
|
||||||
|
|
||||||
// Substring Search.
|
|
||||||
Index: Python-3.13.3/Include/internal/pycore_unicodeobject.h
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Include/internal/pycore_unicodeobject.h 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Include/internal/pycore_unicodeobject.h 2025-05-17 07:33:22.001974979 +0000
|
|
||||||
@@ -142,14 +142,18 @@
|
|
||||||
// Helper for PyUnicode_DecodeUnicodeEscape that detects invalid escape
|
|
||||||
// chars.
|
|
||||||
// Export for test_peg_generator.
|
|
||||||
-PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal(
|
|
||||||
+PyAPI_FUNC(PyObject*) _PyUnicode_DecodeUnicodeEscapeInternal2(
|
|
||||||
const char *string, /* Unicode-Escape encoded string */
|
|
||||||
Py_ssize_t length, /* size of string */
|
|
||||||
const char *errors, /* error handling */
|
|
||||||
Py_ssize_t *consumed, /* bytes consumed */
|
|
||||||
- const char **first_invalid_escape); /* on return, points to first
|
|
||||||
- invalid escaped char in
|
|
||||||
- string. */
|
|
||||||
+ int *first_invalid_escape_char, /* on return, if not -1, contain the first
|
|
||||||
+ invalid escaped char (<= 0xff) or invalid
|
|
||||||
+ octal escape (> 0xff) in string. */
|
|
||||||
+ const char **first_invalid_escape_ptr); /* on return, if not NULL, may
|
|
||||||
+ point to the first invalid escaped
|
|
||||||
+ char in string.
|
|
||||||
+ May be NULL if errors is not NULL. */
|
|
||||||
|
|
||||||
/* --- Raw-Unicode-Escape Codecs ---------------------------------------------- */
|
|
||||||
|
|
||||||
Index: Python-3.13.3/Lib/test/test_codeccallbacks.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Lib/test/test_codeccallbacks.py 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Lib/test/test_codeccallbacks.py 2025-05-17 07:33:22.002185827 +0000
|
|
||||||
@@ -1,6 +1,7 @@
|
|
||||||
import codecs
|
|
||||||
import html.entities
|
|
||||||
import itertools
|
|
||||||
+import re
|
|
||||||
import sys
|
|
||||||
import unicodedata
|
|
||||||
import unittest
|
|
||||||
@@ -1124,7 +1125,7 @@
|
|
||||||
text = 'abc<def>ghi'*n
|
|
||||||
text.translate(charmap)
|
|
||||||
|
|
||||||
- def test_mutatingdecodehandler(self):
|
|
||||||
+ def test_mutating_decode_handler(self):
|
|
||||||
baddata = [
|
|
||||||
("ascii", b"\xff"),
|
|
||||||
("utf-7", b"++"),
|
|
||||||
@@ -1159,6 +1160,42 @@
|
|
||||||
for (encoding, data) in baddata:
|
|
||||||
self.assertEqual(data.decode(encoding, "test.mutating"), "\u4242")
|
|
||||||
|
|
||||||
+ def test_mutating_decode_handler_unicode_escape(self):
|
|
||||||
+ decode = codecs.unicode_escape_decode
|
|
||||||
+ def mutating(exc):
|
|
||||||
+ if isinstance(exc, UnicodeDecodeError):
|
|
||||||
+ r = data.get(exc.object[:exc.end])
|
|
||||||
+ if r is not None:
|
|
||||||
+ exc.object = r[0] + exc.object[exc.end:]
|
|
||||||
+ return ('\u0404', r[1])
|
|
||||||
+ raise AssertionError("don't know how to handle %r" % exc)
|
|
||||||
+
|
|
||||||
+ codecs.register_error('test.mutating2', mutating)
|
|
||||||
+ data = {
|
|
||||||
+ br'\x0': (b'\\', 0),
|
|
||||||
+ br'\x3': (b'xxx\\', 3),
|
|
||||||
+ br'\x5': (b'x\\', 1),
|
|
||||||
+ }
|
|
||||||
+ def check(input, expected, msg):
|
|
||||||
+ with self.assertWarns(DeprecationWarning) as cm:
|
|
||||||
+ self.assertEqual(decode(input, 'test.mutating2'), (expected, len(input)))
|
|
||||||
+ self.assertIn(msg, str(cm.warning))
|
|
||||||
+
|
|
||||||
+ check(br'\x0n\z', '\u0404\n\\z', r"invalid escape sequence '\z'")
|
|
||||||
+ check(br'\x0n\501', '\u0404\n\u0141', r"invalid octal escape sequence '\501'")
|
|
||||||
+ check(br'\x0z', '\u0404\\z', r"invalid escape sequence '\z'")
|
|
||||||
+
|
|
||||||
+ check(br'\x3n\zr', '\u0404\n\\zr', r"invalid escape sequence '\z'")
|
|
||||||
+ check(br'\x3zr', '\u0404\\zr', r"invalid escape sequence '\z'")
|
|
||||||
+ check(br'\x3z5', '\u0404\\z5', r"invalid escape sequence '\z'")
|
|
||||||
+ check(memoryview(br'\x3z5x')[:-1], '\u0404\\z5', r"invalid escape sequence '\z'")
|
|
||||||
+ check(memoryview(br'\x3z5xy')[:-2], '\u0404\\z5', r"invalid escape sequence '\z'")
|
|
||||||
+
|
|
||||||
+ check(br'\x5n\z', '\u0404\n\\z', r"invalid escape sequence '\z'")
|
|
||||||
+ check(br'\x5n\501', '\u0404\n\u0141', r"invalid octal escape sequence '\501'")
|
|
||||||
+ check(br'\x5z', '\u0404\\z', r"invalid escape sequence '\z'")
|
|
||||||
+ check(memoryview(br'\x5zy')[:-1], '\u0404\\z', r"invalid escape sequence '\z'")
|
|
||||||
+
|
|
||||||
# issue32583
|
|
||||||
def test_crashing_decode_handler(self):
|
|
||||||
# better generating one more character to fill the extra space slot
|
|
||||||
Index: Python-3.13.3/Lib/test/test_codecs.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Lib/test/test_codecs.py 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Lib/test/test_codecs.py 2025-05-17 07:33:22.002507164 +0000
|
|
||||||
@@ -1196,23 +1196,39 @@
|
|
||||||
check(br"[\1010]", b"[A0]")
|
|
||||||
check(br"[\x41]", b"[A]")
|
|
||||||
check(br"[\x410]", b"[A0]")
|
|
||||||
+
|
|
||||||
+ def test_warnings(self):
|
|
||||||
+ decode = codecs.escape_decode
|
|
||||||
+ check = coding_checker(self, decode)
|
|
||||||
for i in range(97, 123):
|
|
||||||
b = bytes([i])
|
|
||||||
if b not in b'abfnrtvx':
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\%c'" % i):
|
|
||||||
check(b"\\" + b, b"\\" + b)
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\%c'" % (i-32)):
|
|
||||||
check(b"\\" + b.upper(), b"\\" + b.upper())
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\8'"):
|
|
||||||
check(br"\8", b"\\8")
|
|
||||||
with self.assertWarns(DeprecationWarning):
|
|
||||||
check(br"\9", b"\\9")
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\\xfa'") as cm:
|
|
||||||
check(b"\\\xfa", b"\\\xfa")
|
|
||||||
for i in range(0o400, 0o1000):
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid octal escape sequence '\\%o'" % i):
|
|
||||||
check(rb'\%o' % i, bytes([i & 0o377]))
|
|
||||||
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\z'"):
|
|
||||||
+ self.assertEqual(decode(br'\x\z', 'ignore'), (b'\\z', 4))
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid octal escape sequence '\\501'"):
|
|
||||||
+ self.assertEqual(decode(br'\x\501', 'ignore'), (b'A', 6))
|
|
||||||
+
|
|
||||||
def test_errors(self):
|
|
||||||
decode = codecs.escape_decode
|
|
||||||
self.assertRaises(ValueError, decode, br"\x")
|
|
||||||
@@ -2661,24 +2677,40 @@
|
|
||||||
check(br"[\x410]", "[A0]")
|
|
||||||
check(br"\u20ac", "\u20ac")
|
|
||||||
check(br"\U0001d120", "\U0001d120")
|
|
||||||
+
|
|
||||||
+ def test_decode_warnings(self):
|
|
||||||
+ decode = codecs.unicode_escape_decode
|
|
||||||
+ check = coding_checker(self, decode)
|
|
||||||
for i in range(97, 123):
|
|
||||||
b = bytes([i])
|
|
||||||
if b not in b'abfnrtuvx':
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\%c'" % i):
|
|
||||||
check(b"\\" + b, "\\" + chr(i))
|
|
||||||
if b.upper() not in b'UN':
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\%c'" % (i-32)):
|
|
||||||
check(b"\\" + b.upper(), "\\" + chr(i-32))
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\8'"):
|
|
||||||
check(br"\8", "\\8")
|
|
||||||
with self.assertWarns(DeprecationWarning):
|
|
||||||
check(br"\9", "\\9")
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\\xfa'") as cm:
|
|
||||||
check(b"\\\xfa", "\\\xfa")
|
|
||||||
for i in range(0o400, 0o1000):
|
|
||||||
- with self.assertWarns(DeprecationWarning):
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid octal escape sequence '\\%o'" % i):
|
|
||||||
check(rb'\%o' % i, chr(i))
|
|
||||||
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid escape sequence '\\z'"):
|
|
||||||
+ self.assertEqual(decode(br'\x\z', 'ignore'), ('\\z', 4))
|
|
||||||
+ with self.assertWarnsRegex(DeprecationWarning,
|
|
||||||
+ r"invalid octal escape sequence '\\501'"):
|
|
||||||
+ self.assertEqual(decode(br'\x\501', 'ignore'), ('\u0141', 6))
|
|
||||||
+
|
|
||||||
def test_decode_errors(self):
|
|
||||||
decode = codecs.unicode_escape_decode
|
|
||||||
for c, d in (b'x', 2), (b'u', 4), (b'U', 4):
|
|
||||||
Index: Python-3.13.3/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst 2025-05-17 07:33:22.002786511 +0000
|
|
||||||
@@ -0,0 +1,2 @@
|
|
||||||
+Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error
|
|
||||||
+handler.
|
|
||||||
Index: Python-3.13.3/Objects/bytesobject.c
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Objects/bytesobject.c 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Objects/bytesobject.c 2025-05-17 07:33:22.003325939 +0000
|
|
||||||
@@ -1065,10 +1065,11 @@
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Unescape a backslash-escaped string. */
|
|
||||||
-PyObject *_PyBytes_DecodeEscape(const char *s,
|
|
||||||
+PyObject *_PyBytes_DecodeEscape2(const char *s,
|
|
||||||
Py_ssize_t len,
|
|
||||||
const char *errors,
|
|
||||||
- const char **first_invalid_escape)
|
|
||||||
+ int *first_invalid_escape_char,
|
|
||||||
+ const char **first_invalid_escape_ptr)
|
|
||||||
{
|
|
||||||
int c;
|
|
||||||
char *p;
|
|
||||||
@@ -1082,7 +1083,8 @@
|
|
||||||
return NULL;
|
|
||||||
writer.overallocate = 1;
|
|
||||||
|
|
||||||
- *first_invalid_escape = NULL;
|
|
||||||
+ *first_invalid_escape_char = -1;
|
|
||||||
+ *first_invalid_escape_ptr = NULL;
|
|
||||||
|
|
||||||
end = s + len;
|
|
||||||
while (s < end) {
|
|
||||||
@@ -1120,9 +1122,10 @@
|
|
||||||
c = (c<<3) + *s++ - '0';
|
|
||||||
}
|
|
||||||
if (c > 0377) {
|
|
||||||
- if (*first_invalid_escape == NULL) {
|
|
||||||
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
|
|
||||||
- already incremented s. */
|
|
||||||
+ if (*first_invalid_escape_char == -1) {
|
|
||||||
+ *first_invalid_escape_char = c;
|
|
||||||
+ /* Back up 3 chars, since we've already incremented s. */
|
|
||||||
+ *first_invalid_escape_ptr = s - 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p++ = c;
|
|
||||||
@@ -1163,9 +1166,10 @@
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
- if (*first_invalid_escape == NULL) {
|
|
||||||
- *first_invalid_escape = s-1; /* Back up one char, since we've
|
|
||||||
- already incremented s. */
|
|
||||||
+ if (*first_invalid_escape_char == -1) {
|
|
||||||
+ *first_invalid_escape_char = (unsigned char)s[-1];
|
|
||||||
+ /* Back up one char, since we've already incremented s. */
|
|
||||||
+ *first_invalid_escape_ptr = s - 1;
|
|
||||||
}
|
|
||||||
*p++ = '\\';
|
|
||||||
s--;
|
|
||||||
@@ -1185,17 +1189,18 @@
|
|
||||||
Py_ssize_t Py_UNUSED(unicode),
|
|
||||||
const char *Py_UNUSED(recode_encoding))
|
|
||||||
{
|
|
||||||
- const char* first_invalid_escape;
|
|
||||||
- PyObject *result = _PyBytes_DecodeEscape(s, len, errors,
|
|
||||||
- &first_invalid_escape);
|
|
||||||
+ int first_invalid_escape_char;
|
|
||||||
+ const char *first_invalid_escape_ptr;
|
|
||||||
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, errors,
|
|
||||||
+ &first_invalid_escape_char,
|
|
||||||
+ &first_invalid_escape_ptr);
|
|
||||||
if (result == NULL)
|
|
||||||
return NULL;
|
|
||||||
- if (first_invalid_escape != NULL) {
|
|
||||||
- unsigned char c = *first_invalid_escape;
|
|
||||||
- if ('4' <= c && c <= '7') {
|
|
||||||
+ if (first_invalid_escape_char != -1) {
|
|
||||||
+ if (first_invalid_escape_char > 0xff) {
|
|
||||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
||||||
- "invalid octal escape sequence '\\%.3s'",
|
|
||||||
- first_invalid_escape) < 0)
|
|
||||||
+ "invalid octal escape sequence '\\%o'",
|
|
||||||
+ first_invalid_escape_char) < 0)
|
|
||||||
{
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
@@ -1204,7 +1209,7 @@
|
|
||||||
else {
|
|
||||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
||||||
"invalid escape sequence '\\%c'",
|
|
||||||
- c) < 0)
|
|
||||||
+ first_invalid_escape_char) < 0)
|
|
||||||
{
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
Index: Python-3.13.3/Objects/unicodeobject.c
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Objects/unicodeobject.c 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Objects/unicodeobject.c 2025-05-17 07:33:22.004748214 +0000
|
|
||||||
@@ -6177,13 +6177,15 @@
|
|
||||||
/* --- Unicode Escape Codec ----------------------------------------------- */
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
-_PyUnicode_DecodeUnicodeEscapeInternal(const char *s,
|
|
||||||
+_PyUnicode_DecodeUnicodeEscapeInternal2(const char *s,
|
|
||||||
Py_ssize_t size,
|
|
||||||
const char *errors,
|
|
||||||
Py_ssize_t *consumed,
|
|
||||||
- const char **first_invalid_escape)
|
|
||||||
+ int *first_invalid_escape_char,
|
|
||||||
+ const char **first_invalid_escape_ptr)
|
|
||||||
{
|
|
||||||
const char *starts = s;
|
|
||||||
+ const char *initial_starts = starts;
|
|
||||||
_PyUnicodeWriter writer;
|
|
||||||
const char *end;
|
|
||||||
PyObject *errorHandler = NULL;
|
|
||||||
@@ -6191,7 +6193,8 @@
|
|
||||||
_PyUnicode_Name_CAPI *ucnhash_capi;
|
|
||||||
|
|
||||||
// so we can remember if we've seen an invalid escape char or not
|
|
||||||
- *first_invalid_escape = NULL;
|
|
||||||
+ *first_invalid_escape_char = -1;
|
|
||||||
+ *first_invalid_escape_ptr = NULL;
|
|
||||||
|
|
||||||
if (size == 0) {
|
|
||||||
if (consumed) {
|
|
||||||
@@ -6279,9 +6282,12 @@
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ch > 0377) {
|
|
||||||
- if (*first_invalid_escape == NULL) {
|
|
||||||
- *first_invalid_escape = s-3; /* Back up 3 chars, since we've
|
|
||||||
- already incremented s. */
|
|
||||||
+ if (*first_invalid_escape_char == -1) {
|
|
||||||
+ *first_invalid_escape_char = ch;
|
|
||||||
+ if (starts == initial_starts) {
|
|
||||||
+ /* Back up 3 chars, since we've already incremented s. */
|
|
||||||
+ *first_invalid_escape_ptr = s - 3;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
WRITE_CHAR(ch);
|
|
||||||
@@ -6376,9 +6382,12 @@
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
default:
|
|
||||||
- if (*first_invalid_escape == NULL) {
|
|
||||||
- *first_invalid_escape = s-1; /* Back up one char, since we've
|
|
||||||
- already incremented s. */
|
|
||||||
+ if (*first_invalid_escape_char == -1) {
|
|
||||||
+ *first_invalid_escape_char = c;
|
|
||||||
+ if (starts == initial_starts) {
|
|
||||||
+ /* Back up one char, since we've already incremented s. */
|
|
||||||
+ *first_invalid_escape_ptr = s - 1;
|
|
||||||
+ }
|
|
||||||
}
|
|
||||||
WRITE_ASCII_CHAR('\\');
|
|
||||||
WRITE_CHAR(c);
|
|
||||||
@@ -6423,18 +6432,19 @@
|
|
||||||
const char *errors,
|
|
||||||
Py_ssize_t *consumed)
|
|
||||||
{
|
|
||||||
- const char *first_invalid_escape;
|
|
||||||
- PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal(s, size, errors,
|
|
||||||
+ int first_invalid_escape_char;
|
|
||||||
+ const char *first_invalid_escape_ptr;
|
|
||||||
+ PyObject *result = _PyUnicode_DecodeUnicodeEscapeInternal2(s, size, errors,
|
|
||||||
consumed,
|
|
||||||
- &first_invalid_escape);
|
|
||||||
+ &first_invalid_escape_char,
|
|
||||||
+ &first_invalid_escape_ptr);
|
|
||||||
if (result == NULL)
|
|
||||||
return NULL;
|
|
||||||
- if (first_invalid_escape != NULL) {
|
|
||||||
- unsigned char c = *first_invalid_escape;
|
|
||||||
- if ('4' <= c && c <= '7') {
|
|
||||||
+ if (first_invalid_escape_char != -1) {
|
|
||||||
+ if (first_invalid_escape_char > 0xff) {
|
|
||||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
||||||
- "invalid octal escape sequence '\\%.3s'",
|
|
||||||
- first_invalid_escape) < 0)
|
|
||||||
+ "invalid octal escape sequence '\\%o'",
|
|
||||||
+ first_invalid_escape_char) < 0)
|
|
||||||
{
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
@@ -6443,7 +6453,7 @@
|
|
||||||
else {
|
|
||||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
|
||||||
"invalid escape sequence '\\%c'",
|
|
||||||
- c) < 0)
|
|
||||||
+ first_invalid_escape_char) < 0)
|
|
||||||
{
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
Index: Python-3.13.3/Parser/string_parser.c
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Parser/string_parser.c 2025-04-08 13:54:08.000000000 +0000
|
|
||||||
+++ Python-3.13.3/Parser/string_parser.c 2025-05-17 07:33:22.005519309 +0000
|
|
||||||
@@ -184,15 +184,18 @@
|
|
||||||
len = (size_t)(p - buf);
|
|
||||||
s = buf;
|
|
||||||
|
|
||||||
- const char *first_invalid_escape;
|
|
||||||
- v = _PyUnicode_DecodeUnicodeEscapeInternal(s, (Py_ssize_t)len, NULL, NULL, &first_invalid_escape);
|
|
||||||
+ int first_invalid_escape_char;
|
|
||||||
+ const char *first_invalid_escape_ptr;
|
|
||||||
+ v = _PyUnicode_DecodeUnicodeEscapeInternal2(s, (Py_ssize_t)len, NULL, NULL,
|
|
||||||
+ &first_invalid_escape_char,
|
|
||||||
+ &first_invalid_escape_ptr);
|
|
||||||
|
|
||||||
// HACK: later we can simply pass the line no, since we don't preserve the tokens
|
|
||||||
// when we are decoding the string but we preserve the line numbers.
|
|
||||||
- if (v != NULL && first_invalid_escape != NULL && t != NULL) {
|
|
||||||
- if (warn_invalid_escape_sequence(parser, s, first_invalid_escape, t) < 0) {
|
|
||||||
- /* We have not decref u before because first_invalid_escape points
|
|
||||||
- inside u. */
|
|
||||||
+ if (v != NULL && first_invalid_escape_ptr != NULL && t != NULL) {
|
|
||||||
+ if (warn_invalid_escape_sequence(parser, s, first_invalid_escape_ptr, t) < 0) {
|
|
||||||
+ /* We have not decref u before because first_invalid_escape_ptr
|
|
||||||
+ points inside u. */
|
|
||||||
Py_XDECREF(u);
|
|
||||||
Py_DECREF(v);
|
|
||||||
return NULL;
|
|
||||||
@@ -205,14 +208,17 @@
|
|
||||||
static PyObject *
|
|
||||||
decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
|
|
||||||
{
|
|
||||||
- const char *first_invalid_escape;
|
|
||||||
- PyObject *result = _PyBytes_DecodeEscape(s, len, NULL, &first_invalid_escape);
|
|
||||||
+ int first_invalid_escape_char;
|
|
||||||
+ const char *first_invalid_escape_ptr;
|
|
||||||
+ PyObject *result = _PyBytes_DecodeEscape2(s, len, NULL,
|
|
||||||
+ &first_invalid_escape_char,
|
|
||||||
+ &first_invalid_escape_ptr);
|
|
||||||
if (result == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (first_invalid_escape != NULL) {
|
|
||||||
- if (warn_invalid_escape_sequence(p, s, first_invalid_escape, t) < 0) {
|
|
||||||
+ if (first_invalid_escape_ptr != NULL) {
|
|
||||||
+ if (warn_invalid_escape_sequence(p, s, first_invalid_escape_ptr, t) < 0) {
|
|
||||||
Py_DECREF(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
@@ -1,212 +0,0 @@
|
|||||||
From fd29bcd380150035ef825b762d8cd085bdab6e53 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Alexander Urieles <aeurielesn@users.noreply.github.com>
|
|
||||||
Date: Mon, 28 Jul 2025 17:37:26 +0200
|
|
||||||
Subject: [PATCH] gh-130577: tarfile now validates archives to ensure member
|
|
||||||
offsets are non-negative (GH-137027) (cherry picked from commit
|
|
||||||
7040aa54f14676938970e10c5f74ea93cd56aa38)
|
|
||||||
|
|
||||||
Co-authored-by: Alexander Urieles <aeurielesn@users.noreply.github.com>
|
|
||||||
Co-authored-by: Gregory P. Smith <greg@krypto.org>
|
|
||||||
---
|
|
||||||
Lib/tarfile.py | 3
|
|
||||||
Lib/test/test_tarfile.py | 156 ++++++++++
|
|
||||||
Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst | 3
|
|
||||||
3 files changed, 162 insertions(+)
|
|
||||||
create mode 100644 Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst
|
|
||||||
|
|
||||||
Index: Python-3.13.5/Lib/tarfile.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.5.orig/Lib/tarfile.py 2025-08-01 22:13:44.185826095 +0200
|
|
||||||
+++ Python-3.13.5/Lib/tarfile.py 2025-08-01 22:13:45.524140183 +0200
|
|
||||||
@@ -1636,6 +1636,9 @@
|
|
||||||
"""Round up a byte count by BLOCKSIZE and return it,
|
|
||||||
e.g. _block(834) => 1024.
|
|
||||||
"""
|
|
||||||
+ # Only non-negative offsets are allowed
|
|
||||||
+ if count < 0:
|
|
||||||
+ raise InvalidHeaderError("invalid offset")
|
|
||||||
blocks, remainder = divmod(count, BLOCKSIZE)
|
|
||||||
if remainder:
|
|
||||||
blocks += 1
|
|
||||||
Index: Python-3.13.5/Lib/test/test_tarfile.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.5.orig/Lib/test/test_tarfile.py 2025-06-11 17:36:57.000000000 +0200
|
|
||||||
+++ Python-3.13.5/Lib/test/test_tarfile.py 2025-08-01 22:13:45.524778259 +0200
|
|
||||||
@@ -50,6 +50,7 @@
|
|
||||||
xzname = os.path.join(TEMPDIR, "testtar.tar.xz")
|
|
||||||
tmpname = os.path.join(TEMPDIR, "tmp.tar")
|
|
||||||
dotlessname = os.path.join(TEMPDIR, "testtar")
|
|
||||||
+SPACE = b" "
|
|
||||||
|
|
||||||
sha256_regtype = (
|
|
||||||
"e09e4bc8b3c9d9177e77256353b36c159f5f040531bbd4b024a8f9b9196c71ce"
|
|
||||||
@@ -4578,6 +4579,161 @@
|
|
||||||
ar.extractall(self.testdir, filter='fully_trusted')
|
|
||||||
|
|
||||||
|
|
||||||
+class OffsetValidationTests(unittest.TestCase):
|
|
||||||
+ tarname = tmpname
|
|
||||||
+ invalid_posix_header = (
|
|
||||||
+ # name: 100 bytes
|
|
||||||
+ tarfile.NUL * tarfile.LENGTH_NAME
|
|
||||||
+ # mode, space, null terminator: 8 bytes
|
|
||||||
+ + b"000755" + SPACE + tarfile.NUL
|
|
||||||
+ # uid, space, null terminator: 8 bytes
|
|
||||||
+ + b"000001" + SPACE + tarfile.NUL
|
|
||||||
+ # gid, space, null terminator: 8 bytes
|
|
||||||
+ + b"000001" + SPACE + tarfile.NUL
|
|
||||||
+ # size, space: 12 bytes
|
|
||||||
+ + b"\xff" * 11 + SPACE
|
|
||||||
+ # mtime, space: 12 bytes
|
|
||||||
+ + tarfile.NUL * 11 + SPACE
|
|
||||||
+ # chksum: 8 bytes
|
|
||||||
+ + b"0011407" + tarfile.NUL
|
|
||||||
+ # type: 1 byte
|
|
||||||
+ + tarfile.REGTYPE
|
|
||||||
+ # linkname: 100 bytes
|
|
||||||
+ + tarfile.NUL * tarfile.LENGTH_LINK
|
|
||||||
+ # magic: 6 bytes, version: 2 bytes
|
|
||||||
+ + tarfile.POSIX_MAGIC
|
|
||||||
+ # uname: 32 bytes
|
|
||||||
+ + tarfile.NUL * 32
|
|
||||||
+ # gname: 32 bytes
|
|
||||||
+ + tarfile.NUL * 32
|
|
||||||
+ # devmajor, space, null terminator: 8 bytes
|
|
||||||
+ + tarfile.NUL * 6 + SPACE + tarfile.NUL
|
|
||||||
+ # devminor, space, null terminator: 8 bytes
|
|
||||||
+ + tarfile.NUL * 6 + SPACE + tarfile.NUL
|
|
||||||
+ # prefix: 155 bytes
|
|
||||||
+ + tarfile.NUL * tarfile.LENGTH_PREFIX
|
|
||||||
+ # padding: 12 bytes
|
|
||||||
+ + tarfile.NUL * 12
|
|
||||||
+ )
|
|
||||||
+ invalid_gnu_header = (
|
|
||||||
+ # name: 100 bytes
|
|
||||||
+ tarfile.NUL * tarfile.LENGTH_NAME
|
|
||||||
+ # mode, null terminator: 8 bytes
|
|
||||||
+ + b"0000755" + tarfile.NUL
|
|
||||||
+ # uid, null terminator: 8 bytes
|
|
||||||
+ + b"0000001" + tarfile.NUL
|
|
||||||
+ # gid, space, null terminator: 8 bytes
|
|
||||||
+ + b"0000001" + tarfile.NUL
|
|
||||||
+ # size, space: 12 bytes
|
|
||||||
+ + b"\xff" * 11 + SPACE
|
|
||||||
+ # mtime, space: 12 bytes
|
|
||||||
+ + tarfile.NUL * 11 + SPACE
|
|
||||||
+ # chksum: 8 bytes
|
|
||||||
+ + b"0011327" + tarfile.NUL
|
|
||||||
+ # type: 1 byte
|
|
||||||
+ + tarfile.REGTYPE
|
|
||||||
+ # linkname: 100 bytes
|
|
||||||
+ + tarfile.NUL * tarfile.LENGTH_LINK
|
|
||||||
+ # magic: 8 bytes
|
|
||||||
+ + tarfile.GNU_MAGIC
|
|
||||||
+ # uname: 32 bytes
|
|
||||||
+ + tarfile.NUL * 32
|
|
||||||
+ # gname: 32 bytes
|
|
||||||
+ + tarfile.NUL * 32
|
|
||||||
+ # devmajor, null terminator: 8 bytes
|
|
||||||
+ + tarfile.NUL * 8
|
|
||||||
+ # devminor, null terminator: 8 bytes
|
|
||||||
+ + tarfile.NUL * 8
|
|
||||||
+ # padding: 167 bytes
|
|
||||||
+ + tarfile.NUL * 167
|
|
||||||
+ )
|
|
||||||
+ invalid_v7_header = (
|
|
||||||
+ # name: 100 bytes
|
|
||||||
+ tarfile.NUL * tarfile.LENGTH_NAME
|
|
||||||
+ # mode, space, null terminator: 8 bytes
|
|
||||||
+ + b"000755" + SPACE + tarfile.NUL
|
|
||||||
+ # uid, space, null terminator: 8 bytes
|
|
||||||
+ + b"000001" + SPACE + tarfile.NUL
|
|
||||||
+ # gid, space, null terminator: 8 bytes
|
|
||||||
+ + b"000001" + SPACE + tarfile.NUL
|
|
||||||
+ # size, space: 12 bytes
|
|
||||||
+ + b"\xff" * 11 + SPACE
|
|
||||||
+ # mtime, space: 12 bytes
|
|
||||||
+ + tarfile.NUL * 11 + SPACE
|
|
||||||
+ # chksum: 8 bytes
|
|
||||||
+ + b"0010070" + tarfile.NUL
|
|
||||||
+ # type: 1 byte
|
|
||||||
+ + tarfile.REGTYPE
|
|
||||||
+ # linkname: 100 bytes
|
|
||||||
+ + tarfile.NUL * tarfile.LENGTH_LINK
|
|
||||||
+ # padding: 255 bytes
|
|
||||||
+ + tarfile.NUL * 255
|
|
||||||
+ )
|
|
||||||
+ valid_gnu_header = tarfile.TarInfo("filename").tobuf(tarfile.GNU_FORMAT)
|
|
||||||
+ data_block = b"\xff" * tarfile.BLOCKSIZE
|
|
||||||
+
|
|
||||||
+ def _write_buffer(self, buffer):
|
|
||||||
+ with open(self.tarname, "wb") as f:
|
|
||||||
+ f.write(buffer)
|
|
||||||
+
|
|
||||||
+ def _get_members(self, ignore_zeros=None):
|
|
||||||
+ with open(self.tarname, "rb") as f:
|
|
||||||
+ with tarfile.open(
|
|
||||||
+ mode="r", fileobj=f, ignore_zeros=ignore_zeros
|
|
||||||
+ ) as tar:
|
|
||||||
+ return tar.getmembers()
|
|
||||||
+
|
|
||||||
+ def _assert_raises_read_error_exception(self):
|
|
||||||
+ with self.assertRaisesRegex(
|
|
||||||
+ tarfile.ReadError, "file could not be opened successfully"
|
|
||||||
+ ):
|
|
||||||
+ self._get_members()
|
|
||||||
+
|
|
||||||
+ def test_invalid_offset_header_validations(self):
|
|
||||||
+ for tar_format, invalid_header in (
|
|
||||||
+ ("posix", self.invalid_posix_header),
|
|
||||||
+ ("gnu", self.invalid_gnu_header),
|
|
||||||
+ ("v7", self.invalid_v7_header),
|
|
||||||
+ ):
|
|
||||||
+ with self.subTest(format=tar_format):
|
|
||||||
+ self._write_buffer(invalid_header)
|
|
||||||
+ self._assert_raises_read_error_exception()
|
|
||||||
+
|
|
||||||
+ def test_early_stop_at_invalid_offset_header(self):
|
|
||||||
+ buffer = self.valid_gnu_header + self.invalid_gnu_header + self.valid_gnu_header
|
|
||||||
+ self._write_buffer(buffer)
|
|
||||||
+ members = self._get_members()
|
|
||||||
+ self.assertEqual(len(members), 1)
|
|
||||||
+ self.assertEqual(members[0].name, "filename")
|
|
||||||
+ self.assertEqual(members[0].offset, 0)
|
|
||||||
+
|
|
||||||
+ def test_ignore_invalid_archive(self):
|
|
||||||
+ # 3 invalid headers with their respective data
|
|
||||||
+ buffer = (self.invalid_gnu_header + self.data_block) * 3
|
|
||||||
+ self._write_buffer(buffer)
|
|
||||||
+ members = self._get_members(ignore_zeros=True)
|
|
||||||
+ self.assertEqual(len(members), 0)
|
|
||||||
+
|
|
||||||
+ def test_ignore_invalid_offset_headers(self):
|
|
||||||
+ for first_block, second_block, expected_offset in (
|
|
||||||
+ (
|
|
||||||
+ (self.valid_gnu_header),
|
|
||||||
+ (self.invalid_gnu_header + self.data_block),
|
|
||||||
+ 0,
|
|
||||||
+ ),
|
|
||||||
+ (
|
|
||||||
+ (self.invalid_gnu_header + self.data_block),
|
|
||||||
+ (self.valid_gnu_header),
|
|
||||||
+ 1024,
|
|
||||||
+ ),
|
|
||||||
+ ):
|
|
||||||
+ self._write_buffer(first_block + second_block)
|
|
||||||
+ members = self._get_members(ignore_zeros=True)
|
|
||||||
+ self.assertEqual(len(members), 1)
|
|
||||||
+ self.assertEqual(members[0].name, "filename")
|
|
||||||
+ self.assertEqual(members[0].offset, expected_offset)
|
|
||||||
+
|
|
||||||
+
|
|
||||||
def setUpModule():
|
|
||||||
os_helper.unlink(TEMPDIR)
|
|
||||||
os.makedirs(TEMPDIR)
|
|
||||||
Index: Python-3.13.5/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst
|
|
||||||
===================================================================
|
|
||||||
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
||||||
+++ Python-3.13.5/Misc/NEWS.d/next/Library/2025-07-23-00-35-29.gh-issue-130577.c7EITy.rst 2025-08-01 22:13:45.525174751 +0200
|
|
||||||
@@ -0,0 +1,3 @@
|
|
||||||
+:mod:`tarfile` now validates archives to ensure member offsets are
|
|
||||||
+non-negative. (Contributed by Alexander Enrique Urieles Nieto in
|
|
||||||
+:gh:`130577`.)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:3be094ad08b11dc2a065463524239c78dc9f2b342b01dcd4e1e606dbbc5c78a5
|
|
||||||
size 20841504
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmZ9d85fFIAAAAAALgAo
|
|
||||||
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
|
|
||||||
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
|
|
||||||
YwWXBA//TeNtOZTRpGM4pWnY9GBOvXH+WFyT5k5GQM6AE5ITYhLPkz+Refj3kwPV
|
|
||||||
uF32neYXIJIO3v+vyfFTYyj5jNS5gvGRvjPXe2K5p0K9cv5HpTncob9p8FnTJQRY
|
|
||||||
hqXpzs2q8gjU9YN54wz3SqAFE1ensB2qHlq7EJUABbB+HNWk929TXh+cQwSybRT1
|
|
||||||
XMzdKHc4IO3WCVPKIsMngqglUrj7FhlEgx/C8hmu81zpLVkCzxDXLuEDt7nnHoCG
|
|
||||||
HHcmF8B7kGK6py8KD7n/RZgriXli37tyFHJ0wwCtzwyko73khWVayYyJ53s4Pa5H
|
|
||||||
C6A9eNJMBxAQU/M2uPed+io5xZ8IvzSPs4vJCS8YL+NHTQGubexo5QIIHTP5b7ta
|
|
||||||
JW6s3TDHA8g/b3rGum76ZelJ4dsUJ8TPxNl4fORtsltVLJwol1FLGzb7vK7r/ZTM
|
|
||||||
NBnYFjNjEfe4uWHwsZoLdZzH90Z8bKsUXWz/h4EMjUL3NLgORSE8vbPhpjscmEB/
|
|
||||||
x+DM9IJHQat/s8ijtELuOx9SLpUuFBAmzVkmWVWvlPjFrQ5nw5pWLRzADpEV7/IU
|
|
||||||
XOucXhV4hrc8fJ57dGv0mtpP37DbF/cPMdOC0kA9X4icr1sLwN6MVmQJcFoBcNge
|
|
||||||
LvKvNW8lXxWbdOj0+fIymIXoH+bzJUp8g8l79Hp6QYBM5EOxfso=
|
|
||||||
=KNpM
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
BIN
Python-3.13.0b4.tar.xz
LFS
BIN
Python-3.13.0b4.tar.xz
LFS
Binary file not shown.
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmaY/fpfFIAAAAAALgAo
|
|
||||||
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
|
|
||||||
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
|
|
||||||
YwV7ExAAkdc0QjTfb4xrTBdKdOkpPk6vsM0tDpA1XnsaCDBwHRertRXKGrHivDfK
|
|
||||||
vDxHQqnXXVa+1PiQYGqFLR4DKUCebYs2RjUlZfULiXwv7SxBWTR1AEpzNyNuzfPU
|
|
||||||
+NXz0Wrs2hlEVo6LFIjCqwN3j0e96gEoIOA3BuuCorw4SeRfzc2Fw/essHYL85MQ
|
|
||||||
kyvzhRcjoyWFGoyDv52OUuP81u8v0OaW1EImkKzG65QnXVSPmihTKWvnHxgUBI95
|
|
||||||
rTu2s5/w5gKUDDhQyBl5SLjb+bsMjgoUY8bDkvy9yTi3bWGVFOCD2VFK8cGOGUP0
|
|
||||||
lz8g3aSPBTbfieKqghoIpPjyttqOt4gJg/twXZaxpv3f5nO2ErixYR3El/RzGdGk
|
|
||||||
uui7GJbX4fKoNsmSqM8FV6QfJ+sO3CV+3XVOyfMdrq3WrEGCpR9dYJ7BwOVfcYuD
|
|
||||||
hxMGchhMBJsj3gb25QgEVmFR/DOTnXoWNowbPkmkb7vv6lEp5j5JI47xfNqdxpID
|
|
||||||
Tyn7OQYGqKu7hzhMXTQ5HkL9AvERNUujtGHrN3uND+1ypiEFSuY6ahCmVWoAeSkJ
|
|
||||||
/TMkUiBEj1wBIMi7U0zAoyHN63zshq0DHYkaGDpb24GPAww1VmMls2pBy7vLSKO1
|
|
||||||
Ggzr4WWIN/EVNB9zulhqVxX750idYWBJrP/kLNubEn0Z/iOchrg=
|
|
||||||
=knpx
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
BIN
Python-3.13.0rc2.tar.xz
LFS
BIN
Python-3.13.0rc2.tar.xz
LFS
Binary file not shown.
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmbbgTdfFIAAAAAALgAo
|
|
||||||
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
|
|
||||||
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
|
|
||||||
YwUUpBAAnxUxwaFw3/XLw+5v3k2cbtzPtRmLtg81LlJ2bD5VG+RlCjbwHK03FghH
|
|
||||||
kr4YILbFXN51mT0p2XtrXnd1WRYOIWTxXQ7jji02KY6OBlIordpa0KL415R+Y0O6
|
|
||||||
fvS4sn9r5Ww8TMGHthGeN1boMjtFUHHRZKNUmIzVWihjxQX6UiPVcb9ezM2WDbhI
|
|
||||||
hmGtyEq7KLYwl9GTW/YlsAQXyVvveePgr6PrMjRRquOSVL2vD+ZA8qrQvzWYCza6
|
|
||||||
jDa2+6jrFlE6PpbCUDoRMDagjU2gEG9DllSziayh3aqMHG2fVbEqzLtBHl9EJ7IL
|
|
||||||
yOkhgVVmqus52O5P0YhDDp2fkSxs2JgrXiF2Dd2UTIKKrFQkxmknoj/ScyyeajAj
|
|
||||||
ymqf1CZf3ydhpEng+HGpnU+vWBnQA+v7BZBQXaoPGvMzTeNy1cn5JPTFFkcKXKDE
|
|
||||||
jX8AzV82+OHnZ/80tLNTNCyFQNStKF2CNrHR1gnMAcgQTaJOlp4NMD3nC88WQlpx
|
|
||||||
M4HC/yXq4556AaAzv0CctfzMLejvwmszMxbADHI4FcS7BJO85WsSXH3pnAx3Gfgg
|
|
||||||
5NSEMB1ZAsoS9WbkxTkgaJOT9fHmf86S/sdx4W1zBetmag11bTVWHJwbE9z5V0YQ
|
|
||||||
+fwQYVsi+ecgs3mL7vJzg8vEpJ33O2/y4vqySQYZRA4aIKn9Ks0=
|
|
||||||
=dHr3
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
BIN
Python-3.13.0rc3.tar.xz
LFS
BIN
Python-3.13.0rc3.tar.xz
LFS
Binary file not shown.
@@ -1,18 +0,0 @@
|
|||||||
-----BEGIN PGP SIGNATURE-----
|
|
||||||
|
|
||||||
iQKTBAABCgB9FiEEcWlgX2LHUTVtBUomqCHmgOX6YwUFAmb7fRlfFIAAAAAALgAo
|
|
||||||
aXNzdWVyLWZwckBub3RhdGlvbnMub3BlbnBncC5maWZ0aGhvcnNlbWFuLm5ldDcx
|
|
||||||
Njk2MDVGNjJDNzUxMzU2RDA1NEEyNkE4MjFFNjgwRTVGQTYzMDUACgkQqCHmgOX6
|
|
||||||
YwUnFA/9FXmPquEtA/iRT0ODfuU8WoJhevG7qGnKMuRstNhj4xIaOu93HnjtYcAb
|
|
||||||
EUxOIZvMbIXIv364jDbxL+r/8iUlGYsEW0KbJpZ8c0pJ0Rz+ENewdSUVzcbRwtTJ
|
|
||||||
GG5OCbB8TgjhKclhOVlBhSoJCcU9ZFgco2Arylcn982OkZiDqHQAjk242kpy+E86
|
|
||||||
8tvPf51v3bXR9RZOon2R88KfuAXUESItUtQKzj0tAIEKPMT0+9VJUtZm855phxml
|
|
||||||
dv9pPq11dLshHuSMbfIEKB/3zixPxnN2v9HI7mminFjvAUlPMbCX8Pc9SgEszVzF
|
|
||||||
tEoYSmMioG+yAc4I2EW2AgIjUH+Z5a3OiMDjEFMReL5KrujvT4MpyTdf+b/Vk3Nx
|
|
||||||
2x1Vg/XIWQtaZbjiMmBtwsCfGkaDSbAmi0vU4vTY5ATr45BpRXKb/thpnluFE53T
|
|
||||||
BQza+Cr0cJvUJo+N2JSpIOhoRyjqSwKDMcVDAv7UIF97KH0UidJhuTR6MZ9Jp4SF
|
|
||||||
ko5EtIpTrKfZto+UIdt8qaTjvO5oyNt9ZydKdRgRtvyaGrpD4mzWKUhqJlbwX8pW
|
|
||||||
m+4fbOK/kTFQEHS5J0h36oayiXmEzZ5TU4e9e1eT91Vi96vPVQL9oM374MEeDSEM
|
|
||||||
zpVdIHo6BbVbh1gzaAhG+bGU+BaUSRjn6rhYfPu6FItRB63P3K4=
|
|
||||||
=bHdr
|
|
||||||
-----END PGP SIGNATURE-----
|
|
||||||
BIN
Python-3.13.1.tar.xz
LFS
BIN
Python-3.13.1.tar.xz
LFS
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Python-3.13.3.tar.xz
LFS
BIN
Python-3.13.3.tar.xz
LFS
Binary file not shown.
File diff suppressed because one or more lines are too long
BIN
Python-3.13.5.tar.xz
LFS
BIN
Python-3.13.5.tar.xz
LFS
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1,45 +0,0 @@
|
|||||||
From a4b73ddc0d395ec2e4d2e15637be8e1b51f35f22 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Sergey B Kirpichev <skirpichev@gmail.com>
|
|
||||||
Date: Fri, 13 Sep 2024 13:10:39 +0300
|
|
||||||
Subject: [PATCH 1/4] gh-124040: simplify two hypot tests
|
|
||||||
|
|
||||||
One-argument form is enough to test L2636 and compare computed
|
|
||||||
values exactly.
|
|
||||||
---
|
|
||||||
Lib/test/test_math.py | 4 ++--
|
|
||||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
|
||||||
|
|
||||||
Index: Python-3.13.0rc2/Lib/test/test_math.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.0rc2.orig/Lib/test/test_math.py
|
|
||||||
+++ Python-3.13.0rc2/Lib/test/test_math.py
|
|
||||||
@@ -809,11 +809,13 @@ class MathTests(unittest.TestCase):
|
|
||||||
# Test allowable types (those with __float__)
|
|
||||||
self.assertEqual(hypot(12.0, 5.0), 13.0)
|
|
||||||
self.assertEqual(hypot(12, 5), 13)
|
|
||||||
- self.assertEqual(hypot(1, -1), math.sqrt(2))
|
|
||||||
- self.assertEqual(hypot(1, FloatLike(-1.)), math.sqrt(2))
|
|
||||||
+ self.assertEqual(hypot(0.75, -1), 1.25)
|
|
||||||
+ self.assertEqual(hypot(-1, 0.75), 1.25)
|
|
||||||
+ self.assertEqual(hypot(0.75, FloatLike(-1.)), 1.25)
|
|
||||||
+ self.assertEqual(hypot(FloatLike(-1.), 0.75), 1.25)
|
|
||||||
self.assertEqual(hypot(Decimal(12), Decimal(5)), 13)
|
|
||||||
self.assertEqual(hypot(Fraction(12, 32), Fraction(5, 32)), Fraction(13, 32))
|
|
||||||
- self.assertEqual(hypot(bool(1), bool(0), bool(1), bool(1)), math.sqrt(3))
|
|
||||||
+ self.assertEqual(hypot(True, False, True, True, True), 2.0)
|
|
||||||
|
|
||||||
# Test corner cases
|
|
||||||
self.assertEqual(hypot(0.0, 0.0), 0.0) # Max input is zero
|
|
||||||
@@ -969,9 +971,9 @@ class MathTests(unittest.TestCase):
|
|
||||||
self.assertEqual(dist((D(14), D(1)), (D(2), D(-4))), D(13))
|
|
||||||
self.assertEqual(dist((F(14, 32), F(1, 32)), (F(2, 32), F(-4, 32))),
|
|
||||||
F(13, 32))
|
|
||||||
- self.assertEqual(dist((True, True, False, True, False),
|
|
||||||
- (True, False, True, True, False)),
|
|
||||||
- sqrt(2.0))
|
|
||||||
+ self.assertEqual(dist((True, True, False, False, True, True),
|
|
||||||
+ (True, False, True, False, False, False)),
|
|
||||||
+ 2.0)
|
|
||||||
|
|
||||||
# Test corner cases
|
|
||||||
self.assertEqual(dist((13.25, 12.5, -3.25),
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
From 0e461dd411e9ec3dbdf376435154ca2834bcab51 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Serhiy Storchaka <storchaka@gmail.com>
|
|
||||||
Date: Wed, 16 Apr 2025 00:24:56 +0300
|
|
||||||
Subject: [PATCH] gh-132535: Fix resource warnings in test_timeout
|
|
||||||
|
|
||||||
They were emitted if internet connection was not available.
|
|
||||||
---
|
|
||||||
Lib/test/test_timeout.py | 43 ++++++++++++++++---------------------------
|
|
||||||
1 file changed, 16 insertions(+), 27 deletions(-)
|
|
||||||
|
|
||||||
Index: Python-3.13.3/Lib/test/test_timeout.py
|
|
||||||
===================================================================
|
|
||||||
--- Python-3.13.3.orig/Lib/test/test_timeout.py 2025-04-08 15:54:08.000000000 +0200
|
|
||||||
+++ Python-3.13.3/Lib/test/test_timeout.py 2025-04-15 23:45:55.028517897 +0200
|
|
||||||
@@ -26,10 +26,8 @@
|
|
||||||
"""Test case for socket.gettimeout() and socket.settimeout()"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
-
|
|
||||||
- def tearDown(self):
|
|
||||||
- self.sock.close()
|
|
||||||
+ self.sock = self.enterContext(
|
|
||||||
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM))
|
|
||||||
|
|
||||||
def testObjectCreation(self):
|
|
||||||
# Test Socket creation
|
|
||||||
@@ -113,8 +111,6 @@
|
|
||||||
def setUp(self):
|
|
||||||
raise NotImplementedError()
|
|
||||||
|
|
||||||
- tearDown = setUp
|
|
||||||
-
|
|
||||||
def _sock_operation(self, count, timeout, method, *args):
|
|
||||||
"""
|
|
||||||
Test the specified socket method.
|
|
||||||
@@ -142,12 +138,10 @@
|
|
||||||
"""TCP test case for socket.socket() timeout functions"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
+ self.sock = self.enterContext(
|
|
||||||
+ socket.socket(socket.AF_INET, socket.SOCK_STREAM))
|
|
||||||
self.addr_remote = resolve_address('www.python.org.', 80)
|
|
||||||
|
|
||||||
- def tearDown(self):
|
|
||||||
- self.sock.close()
|
|
||||||
-
|
|
||||||
def testConnectTimeout(self):
|
|
||||||
# Testing connect timeout is tricky: we need to have IP connectivity
|
|
||||||
# to a host that silently drops our packets. We can't simulate this
|
|
||||||
@@ -190,19 +184,16 @@
|
|
||||||
# for the current configuration.
|
|
||||||
|
|
||||||
skip = True
|
|
||||||
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
- timeout = support.LOOPBACK_TIMEOUT
|
|
||||||
- sock.settimeout(timeout)
|
|
||||||
- try:
|
|
||||||
- sock.connect((whitehole))
|
|
||||||
- except TimeoutError:
|
|
||||||
- pass
|
|
||||||
- except OSError as err:
|
|
||||||
- if err.errno == errno.ECONNREFUSED:
|
|
||||||
- skip = False
|
|
||||||
- finally:
|
|
||||||
- sock.close()
|
|
||||||
- del sock
|
|
||||||
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
||||||
+ try:
|
|
||||||
+ timeout = support.LOOPBACK_TIMEOUT
|
|
||||||
+ sock.settimeout(timeout)
|
|
||||||
+ sock.connect((whitehole))
|
|
||||||
+ except TimeoutError:
|
|
||||||
+ pass
|
|
||||||
+ except OSError as err:
|
|
||||||
+ if err.errno == errno.ECONNREFUSED:
|
|
||||||
+ skip = False
|
|
||||||
|
|
||||||
if skip:
|
|
||||||
self.skipTest(
|
|
||||||
@@ -269,10 +260,8 @@
|
|
||||||
"""UDP test case for socket.socket() timeout functions"""
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
-
|
|
||||||
- def tearDown(self):
|
|
||||||
- self.sock.close()
|
|
||||||
+ self.sock = self.enterContext(
|
|
||||||
+ socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
|
||||||
|
|
||||||
def testRecvfromTimeout(self):
|
|
||||||
# Test recvfrom() timeout
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
---
|
|
||||||
Lib/test/test_posix.py | 2 +-
|
|
||||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
|
||||||
|
|
||||||
--- a/Lib/test/test_posix.py
|
|
||||||
+++ b/Lib/test/test_posix.py
|
|
||||||
@@ -437,7 +437,7 @@ class PosixTester(unittest.TestCase):
|
|
||||||
def test_posix_fadvise(self):
|
|
||||||
fd = os.open(os_helper.TESTFN, os.O_RDONLY)
|
|
||||||
try:
|
|
||||||
- posix.posix_fadvise(fd, 0, 0, posix.POSIX_FADV_WILLNEED)
|
|
||||||
+ posix.posix_fadvise(fd, 0, 0, posix.POSIX_FADV_RANDOM)
|
|
||||||
finally:
|
|
||||||
os.close(fd)
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user