Accepting request 1281134 from devel:languages:python:Factory

- Update to 3.14.0~b2:
  - Tools/Demos
    - gh-134215: REPL import autocomplete only suggests private
      modules when explicitly specified.
  - Tests
    - gh-133744: Fix multiprocessing interrupt test. Add an event
      to synchronize the parent process with the child process:
      wait until the child process starts sleeping. Patch by
      Victor Stinner.
    - gh-133682: Fixed test case
      test.test_annotationlib.TestStringFormat.test_displays
      which ensures proper handling of complex data structures
      (lists, sets, dictionaries, and tuples) in string
      annotations.
    - gh-133639: Fix
      TestPyReplAutoindent.test_auto_indent_default() doesn’t run
      input_code.
  - Security
    - gh-133767: Fix use-after-free in the “unicode-escape”
      decoder with a non-“strict” error handler (CVE-2025-4516
      bsc#1243273).
    - gh-128840: Short-circuit the processing of long IPv6
      addresses early in ipaddress to prevent excessive memory
      consumption and a minor denial-of-service.
  - Library
    - gh-132710: If possible, ensure that uuid.getnode()
      returns the same result even across different
      processes. Previously, the result was constant only within
      the same process. Patch by Bénédikt Tran.
    - gh-80334: multiprocessing.freeze_support() now checks for

OBS-URL: https://build.opensuse.org/request/show/1281134
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/python314?expand=0&rev=12
This commit is contained in:
2025-05-30 12:37:50 +00:00
committed by Git OBS Bridge
12 changed files with 270 additions and 553 deletions

View File

@@ -4,11 +4,9 @@
Lib/test/test_xml_etree.py | 10 ++++++++++
3 files changed, 17 insertions(+)
Index: Python-3.14.0a7/Lib/test/test_pyexpat.py
===================================================================
--- Python-3.14.0a7.orig/Lib/test/test_pyexpat.py 2025-04-12 23:55:25.077318106 +0200
+++ Python-3.14.0a7/Lib/test/test_pyexpat.py 2025-04-12 23:58:03.769944012 +0200
@@ -791,6 +791,10 @@
--- 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):
@@ -19,11 +17,9 @@ Index: Python-3.14.0a7/Lib/test/test_pyexpat.py
started = []
def start_element(name, _):
Index: Python-3.14.0a7/Lib/test/test_sax.py
===================================================================
--- Python-3.14.0a7.orig/Lib/test/test_sax.py 2025-04-12 23:55:25.131274628 +0200
+++ Python-3.14.0a7/Lib/test/test_sax.py 2025-04-12 23:58:03.770532570 +0200
@@ -1241,6 +1241,9 @@
--- a/Lib/test/test_sax.py
+++ b/Lib/test/test_sax.py
@@ -1241,6 +1241,9 @@ class ExpatReaderTest(XmlTestBase):
self.assertEqual(result.getvalue(), start + b"<doc></doc>")
@@ -33,11 +29,9 @@ Index: Python-3.14.0a7/Lib/test/test_sax.py
def test_flush_reparse_deferral_disabled(self):
result = BytesIO()
xmlgen = XMLGenerator(result)
Index: Python-3.14.0a7/Lib/test/test_xml_etree.py
===================================================================
--- Python-3.14.0a7.orig/Lib/test/test_xml_etree.py 2025-04-12 23:55:25.550207629 +0200
+++ Python-3.14.0a7/Lib/test/test_xml_etree.py 2025-04-12 23:58:03.771265630 +0200
@@ -138,6 +138,11 @@
--- a/Lib/test/test_xml_etree.py
+++ b/Lib/test/test_xml_etree.py
@@ -138,6 +138,11 @@ def equal_wrapper(cls):
return mock.patch.object(cls, "__eq__", autospec=True, wraps=eq)
@@ -49,7 +43,7 @@ Index: Python-3.14.0a7/Lib/test/test_xml_etree.py
def checkwarnings(*filters, quiet=False):
def decorator(test):
def newtest(*args, **kwargs):
@@ -1521,9 +1526,11 @@
@@ -1520,9 +1525,11 @@ class XMLPullParserTest(unittest.TestCas
self.assert_event_tags(parser, [('end', 'root')])
self.assertIsNone(parser.close())
@@ -61,7 +55,7 @@ Index: Python-3.14.0a7/Lib/test/test_xml_etree.py
def test_simple_xml_chunk_5(self):
self.test_simple_xml(chunk_size=5, flush=True)
@@ -1748,6 +1755,9 @@
@@ -1747,6 +1754,9 @@ class XMLPullParserTest(unittest.TestCas
self.assert_event_tags(parser, [('end', 'doc')])

View File

@@ -1,480 +0,0 @@
From 3a939ff2298d147459116f98a09549d0f1954039 Mon Sep 17 00:00:00 2001
From: Serhiy Storchaka <storchaka@gmail.com>
Date: Tue, 4 Feb 2025 11:44:39 +0200
Subject: Fix use-after-free in the unicode-escape decoder with error handler
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().
---
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(-)
Index: Python-3.14.0b1/Include/internal/pycore_bytesobject.h
===================================================================
--- Python-3.14.0b1.orig/Include/internal/pycore_bytesobject.h 2025-05-06 15:33:52.000000000 +0000
+++ Python-3.14.0b1/Include/internal/pycore_bytesobject.h 2025-05-17 06:44:53.614667081 +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.14.0b1/Include/internal/pycore_unicodeobject.h
===================================================================
--- Python-3.14.0b1.orig/Include/internal/pycore_unicodeobject.h 2025-05-06 15:33:52.000000000 +0000
+++ Python-3.14.0b1/Include/internal/pycore_unicodeobject.h 2025-05-17 06:44:53.614817134 +0000
@@ -139,14 +139,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.14.0b1/Lib/test/test_codeccallbacks.py
===================================================================
--- Python-3.14.0b1.orig/Lib/test/test_codeccallbacks.py 2025-05-17 06:44:47.673341939 +0000
+++ Python-3.14.0b1/Lib/test/test_codeccallbacks.py 2025-05-17 06:44:53.615018793 +0000
@@ -2,6 +2,7 @@
import codecs
import html.entities
import itertools
+import re
import sys
import unicodedata
import unittest
@@ -1125,7 +1126,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"++"),
@@ -1160,6 +1161,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'"\z" is an invalid escape sequence')
+ check(br'\x0n\501', '\u0404\n\u0141', r'"\501" is an invalid octal escape sequence')
+ check(br'\x0z', '\u0404\\z', r'"\z" is an invalid escape sequence')
+
+ check(br'\x3n\zr', '\u0404\n\\zr', r'"\z" is an invalid escape sequence')
+ check(br'\x3zr', '\u0404\\zr', r'"\z" is an invalid escape sequence')
+ check(br'\x3z5', '\u0404\\z5', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x3z5x')[:-1], '\u0404\\z5', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x3z5xy')[:-2], '\u0404\\z5', r'"\z" is an invalid escape sequence')
+
+ check(br'\x5n\z', '\u0404\n\\z', r'"\z" is an invalid escape sequence')
+ check(br'\x5n\501', '\u0404\n\u0141', r'"\501" is an invalid octal escape sequence')
+ check(br'\x5z', '\u0404\\z', r'"\z" is an invalid escape sequence')
+ check(memoryview(br'\x5zy')[:-1], '\u0404\\z', r'"\z" is an invalid escape sequence')
+
# issue32583
def test_crashing_decode_handler(self):
# better generating one more character to fill the extra space slot
Index: Python-3.14.0b1/Lib/test/test_codecs.py
===================================================================
--- Python-3.14.0b1.orig/Lib/test/test_codecs.py 2025-05-17 06:44:47.696604117 +0000
+++ Python-3.14.0b1/Lib/test/test_codecs.py 2025-05-17 06:44:53.615449954 +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'"\\%c" is an invalid escape sequence' % i):
check(b"\\" + b, b"\\" + b)
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % (i-32)):
check(b"\\" + b.upper(), b"\\" + b.upper())
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\8" is an invalid escape sequence'):
check(br"\8", b"\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", b"\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\\xfa" is an invalid escape sequence') as cm:
check(b"\\\xfa", b"\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%o" is an invalid octal escape sequence' % i):
check(rb'\%o' % i, bytes([i & 0o377]))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\z" is an invalid escape sequence'):
+ self.assertEqual(decode(br'\x\z', 'ignore'), (b'\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\501" is an invalid octal escape sequence'):
+ 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'"\\%c" is an invalid escape sequence' % i):
check(b"\\" + b, "\\" + chr(i))
if b.upper() not in b'UN':
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%c" is an invalid escape sequence' % (i-32)):
check(b"\\" + b.upper(), "\\" + chr(i-32))
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\8" is an invalid escape sequence'):
check(br"\8", "\\8")
with self.assertWarns(DeprecationWarning):
check(br"\9", "\\9")
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\\xfa" is an invalid escape sequence') as cm:
check(b"\\\xfa", "\\\xfa")
for i in range(0o400, 0o1000):
- with self.assertWarns(DeprecationWarning):
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\%o" is an invalid octal escape sequence' % i):
check(rb'\%o' % i, chr(i))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\z" is an invalid escape sequence'):
+ self.assertEqual(decode(br'\x\z', 'ignore'), ('\\z', 4))
+ with self.assertWarnsRegex(DeprecationWarning,
+ r'"\\501" is an invalid octal escape sequence'):
+ 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.14.0b1/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.14.0b1/Misc/NEWS.d/next/Security/2025-05-09-20-22-54.gh-issue-133767.kN2i3Q.rst 2025-05-17 06:44:53.615887918 +0000
@@ -0,0 +1,2 @@
+Fix use-after-free in the "unicode-escape" decoder with a non-"strict" error
+handler.
Index: Python-3.14.0b1/Objects/bytesobject.c
===================================================================
--- Python-3.14.0b1.orig/Objects/bytesobject.c 2025-05-06 15:33:52.000000000 +0000
+++ Python-3.14.0b1/Objects/bytesobject.c 2025-05-17 06:44:53.616354335 +0000
@@ -1075,10 +1075,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;
@@ -1092,7 +1093,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) {
@@ -1130,9 +1132,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;
@@ -1173,9 +1176,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--;
@@ -1195,18 +1199,19 @@
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,
- "b\"\\%.3s\" is an invalid octal escape sequence. "
+ "b\"\\%o\" is an invalid octal escape sequence. "
"Such sequences will not work in the future. ",
- first_invalid_escape) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -1216,7 +1221,7 @@
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"b\"\\%c\" is an invalid escape sequence. "
"Such sequences will not work in the future. ",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
Index: Python-3.14.0b1/Objects/unicodeobject.c
===================================================================
--- Python-3.14.0b1.orig/Objects/unicodeobject.c 2025-05-06 15:33:52.000000000 +0000
+++ Python-3.14.0b1/Objects/unicodeobject.c 2025-05-17 06:44:53.617547540 +0000
@@ -6621,13 +6621,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;
@@ -6635,7 +6637,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) {
@@ -6723,9 +6726,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);
@@ -6820,9 +6826,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);
@@ -6867,19 +6876,20 @@
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,
- "\"\\%.3s\" is an invalid octal escape sequence. "
+ "\"\\%o\" is an invalid octal escape sequence. "
"Such sequences will not work in the future. ",
- first_invalid_escape) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
@@ -6889,7 +6899,7 @@
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
"\"\\%c\" is an invalid escape sequence. "
"Such sequences will not work in the future. ",
- c) < 0)
+ first_invalid_escape_char) < 0)
{
Py_DECREF(result);
return NULL;
Index: Python-3.14.0b1/Parser/string_parser.c
===================================================================
--- Python-3.14.0b1.orig/Parser/string_parser.c 2025-05-06 15:33:52.000000000 +0000
+++ Python-3.14.0b1/Parser/string_parser.c 2025-05-17 06:44:53.618734552 +0000
@@ -196,15 +196,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;
@@ -217,14 +220,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;
}

BIN
Python-3.14.0b1.tar.xz (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

BIN
Python-3.14.0b2.tar.xz (Stored with Git LFS) Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

@@ -13,11 +13,9 @@ Co-Authored-By: Xavier de Gaye <xdegaye@gmail.com>
5 files changed, 37 insertions(+), 9 deletions(-)
create mode 100644 Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
Index: Python-3.14.0b1/Doc/library/ensurepip.rst
===================================================================
--- Python-3.14.0b1.orig/Doc/library/ensurepip.rst 2025-05-12 10:59:00.152603111 +0000
+++ Python-3.14.0b1/Doc/library/ensurepip.rst 2025-05-12 10:59:06.662087113 +0000
@@ -61,7 +61,11 @@
--- a/Doc/library/ensurepip.rst
+++ b/Doc/library/ensurepip.rst
@@ -61,7 +61,11 @@ is at least as recent as the one availab
By default, ``pip`` is installed into the current virtual environment
(if one is active) or into the system site packages (if there is no
active virtual environment). The installation location can be controlled
@@ -30,7 +28,7 @@ Index: Python-3.14.0b1/Doc/library/ensurepip.rst
.. option:: --root <dir>
@@ -102,7 +106,7 @@
@@ -102,7 +106,7 @@ Module API
Returns a string specifying the available version of pip that will be
installed when bootstrapping an environment.
@@ -39,7 +37,7 @@ Index: Python-3.14.0b1/Doc/library/ensurepip.rst
altinstall=False, default_pip=False, \
verbosity=0)
@@ -112,6 +116,8 @@
@@ -112,6 +116,8 @@ Module API
If *root* is ``None``, then installation uses the default install location
for the current environment.
@@ -48,7 +46,7 @@ Index: Python-3.14.0b1/Doc/library/ensurepip.rst
*upgrade* indicates whether or not to upgrade an existing installation
of an earlier version of ``pip`` to the available version.
@@ -132,6 +138,8 @@
@@ -132,6 +138,8 @@ Module API
*verbosity* controls the level of output to :data:`sys.stdout` from the
bootstrapping operation.
@@ -57,11 +55,9 @@ Index: Python-3.14.0b1/Doc/library/ensurepip.rst
.. audit-event:: ensurepip.bootstrap root ensurepip.bootstrap
.. note::
Index: Python-3.14.0b1/Lib/ensurepip/__init__.py
===================================================================
--- Python-3.14.0b1.orig/Lib/ensurepip/__init__.py 2025-05-12 10:59:00.152603111 +0000
+++ Python-3.14.0b1/Lib/ensurepip/__init__.py 2025-05-12 10:59:06.662530889 +0000
@@ -106,27 +106,27 @@
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -106,27 +106,27 @@ def _disable_pip_configuration_settings(
os.environ['PIP_CONFIG_FILE'] = os.devnull
@@ -94,7 +90,7 @@ Index: Python-3.14.0b1/Lib/ensurepip/__init__.py
Note that calling this function will alter both sys.path and os.environ.
"""
@@ -162,6 +162,8 @@
@@ -162,6 +162,8 @@ def _bootstrap(*, root=None, upgrade=Fal
args = ["install", "--no-cache-dir", "--no-index", "--find-links", tmpdir]
if root:
args += ["--root", root]
@@ -103,7 +99,7 @@ Index: Python-3.14.0b1/Lib/ensurepip/__init__.py
if upgrade:
args += ["--upgrade"]
if user:
@@ -238,6 +240,11 @@
@@ -238,6 +240,11 @@ def _main(argv=None):
help="Install everything relative to this alternate root directory.",
)
parser.add_argument(
@@ -115,7 +111,7 @@ Index: Python-3.14.0b1/Lib/ensurepip/__init__.py
"--altinstall",
action="store_true",
default=False,
@@ -256,6 +263,7 @@
@@ -256,6 +263,7 @@ def _main(argv=None):
return _bootstrap(
root=args.root,
@@ -123,11 +119,9 @@ Index: Python-3.14.0b1/Lib/ensurepip/__init__.py
upgrade=args.upgrade,
user=args.user,
verbosity=args.verbosity,
Index: Python-3.14.0b1/Lib/test/test_ensurepip.py
===================================================================
--- Python-3.14.0b1.orig/Lib/test/test_ensurepip.py 2025-05-12 10:59:00.152603111 +0000
+++ Python-3.14.0b1/Lib/test/test_ensurepip.py 2025-05-12 10:59:06.662803061 +0000
@@ -100,6 +100,17 @@
--- a/Lib/test/test_ensurepip.py
+++ b/Lib/test/test_ensurepip.py
@@ -100,6 +100,17 @@ class TestBootstrap(EnsurepipMixin, unit
unittest.mock.ANY,
)
@@ -145,11 +139,9 @@ Index: Python-3.14.0b1/Lib/test/test_ensurepip.py
def test_bootstrapping_with_user(self):
ensurepip.bootstrap(user=True)
Index: Python-3.14.0b1/Makefile.pre.in
===================================================================
--- Python-3.14.0b1.orig/Makefile.pre.in 2025-05-12 10:59:05.200858322 +0000
+++ Python-3.14.0b1/Makefile.pre.in 2025-05-12 10:59:06.663191503 +0000
@@ -2335,7 +2335,7 @@
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -2341,7 +2341,7 @@ install: @FRAMEWORKINSTALLFIRST@ @INSTAL
install|*) ensurepip="" ;; \
esac; \
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
@@ -158,7 +150,7 @@ Index: Python-3.14.0b1/Makefile.pre.in
fi
.PHONY: altinstall
@@ -2346,7 +2346,7 @@
@@ -2352,7 +2352,7 @@ altinstall: commoninstall
install|*) ensurepip="--altinstall" ;; \
esac; \
$(RUNSHARED) $(PYTHON_FOR_BUILD) -m ensurepip \
@@ -167,9 +159,7 @@ Index: Python-3.14.0b1/Makefile.pre.in
fi
.PHONY: commoninstall
Index: Python-3.14.0b1/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ Python-3.14.0b1/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst 2025-05-12 10:59:06.663664734 +0000
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2019-12-16-17-50-42.bpo-31046.XA-Qfr.rst
@@ -0,0 +1 @@
+A directory prefix can now be specified when using :mod:`ensurepip`.

View File

@@ -2,11 +2,9 @@
Makefile.pre.in | 5 +++++
1 file changed, 5 insertions(+)
Index: Python-3.14.0b1/Makefile.pre.in
===================================================================
--- Python-3.14.0b1.orig/Makefile.pre.in 2025-05-12 10:57:03.566724942 +0000
+++ Python-3.14.0b1/Makefile.pre.in 2025-05-12 10:57:41.504010702 +0000
@@ -1874,6 +1874,11 @@
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1880,6 +1880,11 @@ Modules/getbuildinfo.o: $(PARSER_OBJS) \
-DGITBRANCH="\"`LC_ALL=C $(GITBRANCH)`\"" \
-o $@ $(srcdir)/Modules/getbuildinfo.c

View File

@@ -1,9 +1,11 @@
Index: Python-3.13.0a3/Lib/site.py
===================================================================
--- Python-3.13.0a3.orig/Lib/site.py
+++ Python-3.13.0a3/Lib/site.py
@@ -77,7 +77,7 @@ import io
import stat
---
Lib/site.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/Lib/site.py
+++ b/Lib/site.py
@@ -78,7 +78,7 @@ import stat
import errno
# Prefixes for site-packages; add additional prefixes like /usr/local here
-PREFIXES = [sys.prefix, sys.exec_prefix]

View File

@@ -1,3 +1,221 @@
-------------------------------------------------------------------
Thu May 29 11:42:15 UTC 2025 - Matej Cepl <mcepl@cepl.eu>
- Update to 3.14.0~b2:
- Tools/Demos
- gh-134215: REPL import autocomplete only suggests private
modules when explicitly specified.
- Tests
- gh-133744: Fix multiprocessing interrupt test. Add an event
to synchronize the parent process with the child process:
wait until the child process starts sleeping. Patch by
Victor Stinner.
- gh-133682: Fixed test case
test.test_annotationlib.TestStringFormat.test_displays
which ensures proper handling of complex data structures
(lists, sets, dictionaries, and tuples) in string
annotations.
- gh-133639: Fix
TestPyReplAutoindent.test_auto_indent_default() doesnt run
input_code.
- Security
- gh-133767: Fix use-after-free in the “unicode-escape”
decoder with a non-“strict” error handler (CVE-2025-4516
bsc#1243273).
- gh-128840: Short-circuit the processing of long IPv6
addresses early in ipaddress to prevent excessive memory
consumption and a minor denial-of-service.
- Library
- gh-132710: If possible, ensure that uuid.getnode()
returns the same result even across different
processes. Previously, the result was constant only within
the same process. Patch by Bénédikt Tran.
- gh-80334: multiprocessing.freeze_support() now checks for
work on any “spawn” start method platform rather than only
on Windows.
- gh-134582: Fix tokenize.untokenize() round-trip errors
related to t-strings braces escaping
- gh-134546: Ensure pdb remote debugging script is readable
by remote Python process.
- gh-134451: Converted asyncio.tools.CycleFoundException from
dataclass to a regular exception type.
- gh-114177: Fix asyncio to not close subprocess pipes which
would otherwise error out when the event loop is already
closed.
- gh-90871: Fixed an off by one error concerning the backlog
parameter in create_unix_server(). Contributed by Christian
Harries.
- gh-134323: Fix the threading.RLock.locked() method.
- gh-86802: Fixed asyncio memory leak in cancelled
shield tasks. For shielded tasks where the shield was
cancelled, log potential exceptions through the exception
handler. Contributed by Christian Harries.
- gh-134209: curses: The curses.window.instr() and
curses.window.getstr() methods now allocate their internal
buffer on the heap instead of the stack; in addition, the
max buffer size is increased from 1023 to 2047.
- gh-134235: Updated tab completion on REPL to include
builtin modules. Contributed by Tom Wang, Hunter Young
- gh-134152: Fixed UnboundLocalError that could occur during
email header parsing if an expected trailing delimiter is
missing in some contexts.
- gh-134168: http.server: Fix IPv6 address binding and
--directory handling when using HTTPS.
- gh-62184: Remove import of C implementation of io.FileIO
from Python implementation which has its own implementation
- gh-133982: Emit RuntimeWarning in the Python implementation
of io when the file-like object is not closed explicitly in
the presence of multiple I/O layers.
- gh-133890: The tarfile module now handles
UnicodeEncodeError in the same way as OSError when cannot
extract a member.
- gh-134097: Fix interaction of the new REPL and -X
showrefcount command line option.
- gh-133889: The generated directory listing page in
http.server.SimpleHTTPRequestHandler now only shows the
decoded path component of the requested URL, and not the
query and fragment.
- gh-134098: Fix handling paths that end with
a percent-encoded slash (%2f or %2F) in
http.server.SimpleHTTPRequestHandler.
- gh-132124: On POSIX-compliant systems,
multiprocessing.util.get_temp_dir() now ignores TMPDIR
(and similar environment variables) if the path length of
AF_UNIX socket files exceeds the platform-specific maximum
length when using the forkserver start method. Patch by
Bénédikt Tran.
- gh-134062: ipaddress: fix collisions in __hash__() for
IPv4Network and IPv6Network objects.
- gh-133970: Make string.templatelib.Template and
string.templatelib.Interpolation generic.
- gh-71253: Raise ValueError in open() if opener returns a
negative file-descriptor in the Python implementation of io
to match the C implementation.
- gh-133960: Simplify and improve
typing.evaluate_forward_ref(). It now no longer raises
errors on certain invalid types. In several situations,
it is now able to evaluate forward references that were
previously unsupported.
- gh-133925: Make the private class typing._UnionGenericAlias
hashable.
- gh-133653: Fix argparse.ArgumentParser with the
formatter_class argument. Fix TypeError when
formatter_class is a custom subclass of HelpFormatter. Fix
TypeError when formatter_class is not a subclass of
HelpFormatter and non-standard prefix_char is used. Fix
support of colorizing when formatter_class is not a
subclass of HelpFormatter.
- gh-132641: Fixed a race in functools.lru_cache() under
free-threading.
- gh-133783: Fix bug with applying copy.replace() to ast
objects. Attributes that default to None were incorrectly
treated as required for manually created AST nodes.
- gh-133684: Fix bug where annotationlib.get_annotations()
would return the wrong result for certain classes that are
part of a class hierarchy where from __future__ import
annotations is used.
- gh-77057: Fix handling of invalid markup declarations in
html.parser.HTMLParser.
- gh-130328: Speedup pasting in PyREPL on Windows in a legacy
console. Patch by Chris Eibl.
- gh-133701: Fix bug where typing.TypedDict classes defined
under from __future__ import annotations and inheriting
from another TypedDict had an incorrect __annotations__
attribute.
- gh-133581: Improve unparsing of t-strings in ast.unparse()
and from __future__ import annotations. Empty t-strings now
round-trip correctly and formatting in interpolations is
preserved. Patch by Jelle Zijlstra.
- gh-133551: Support t-strings (PEP 750) in
annotationlib. Patch by Jelle Zijlstra.
- gh-133439: Fix dot commands with trailing spaces are
mistaken for multi-line SQL statements in the sqlite3
command-line interface.
- gh-132493: Avoid accessing __annotations__ unnecessarily in
inspect.signature().
- gh-132876: ldexp() on Windows doesnt round subnormal
results before Windows 11, but should. Pythons
math.ldexp() wrapper now does round them, so results may
change slightly, in rare cases of very small results, on
Windows versions before 11.
- gh-133009: xml.etree.ElementTree: Fix a crash in
Element.__deepcopy__ when the element is concurrently
mutated. Patch by Bénédikt Tran.
- gh-91555: Ignore log messages generated during handling of
log messages, to avoid deadlock or infinite recursion.
- gh-125028: functools.Placeholder cannot be passed to
functools.partial() as a keyword argument.
- gh-62824: Fix aliases for iso8859_8 encoding. Patch by Dave
Goncalves.
- gh-86155: html.parser.HTMLParser.close() no longer loses
data when the <script> tag is not closed. Patch by Waylan
Limberg.
- gh-69426: Fix html.parser.HTMLParser to not unescape
character entities in attribute values if they are followed
by an ASCII alphanumeric or an equals sign.
bpo-28494: Improve Zip file validation false positive rate in zipfile.is_zipfile().
- Core and Builtins
- gh-134381: Fix RuntimeError when using a not-started
threading.Thread after calling os.fork()
- gh-127960: PyREPL interactive shell no longer starts with
__package__ and __file__ global names set to _pyrepl
package internals. Contributed by Yuichiro Tachibana.
- gh-130397: Remove special-casing for C stack depth limits
for WASI. Due to WebAssemblys built-in stack protection
this does not pose a security concern.
- gh-128066: Fixes an edge case where PyREPL improperly threw
an error when Python is invoked on a read only filesystem
while trying to write history file entries.
- gh-69605: When auto-completing an import in the REPL,
finding no candidates now issues no suggestion, rather than
suggestions from the current namespace.
- gh-134158: Fix coloring of double braces in f-strings and
t-strings in the REPL.
- gh-134119: Fix crash when calling next() on an exhausted
template string iterator. Patch by Jelle Zijlstra.
- gh-134100: Fix a use-after-free bug that occurs when an
imported module isnt in sys.modules after its initial
import. Patch by Nico-Posada.
- gh-133999: Fix SyntaxError regression in except parsing
after gh-123440.
- gh-133886: Fix sys.remote_exec() for non-ASCII paths in
non-UTF-8 locales and non-UTF-8 paths in UTF-8 locales.
- gh-133703: Fix hashtable in dict can be bigger than
intended in some situations.
- gh-133778: Fix bug where assigning to the __annotations__
attributes of classes defined under from __future__ import
annotations had no effect.
- gh-132762: fromkeys() no longer loops forever when adding
a small set of keys to a large base dict. Patch by Angela
Liss.
- gh-133541: Inconsistent indentation in user input crashed
the new REPL when syntax highlighting was active. This is
now fixed.
- gh-133516: Raise ValueError when constants True, False or
None are used as an identifier after NFKC normalization.
- gh-132542: Update Thread.native_id after fork(2) to ensure
accuracy. Patch by Noam Cohen.
- C API
- gh-134144: Fix crash when calling Py_EndInterpreter()
with a thread state that isnt the initial thread for the
interpreter.
- Build
- gh-134455: Fixed build-details.json generation to use the
correct c_api.headers as defined in PEP 739, instead of
c_api.include.
- gh-131769: Fix detecting when the build Python in a
cross-build is a pydebug build.
- gh-117088: AIX linker dont support -h option, so avoid it
through platform check
- Remove upstreamed patches:
- CVE-2025-4516-DecodeError-handler.patch
- Patches reapplied:
- CVE-2023-52425-libexpat-2.6.0-backport-15.6.patch
- bpo-31046_ensurepip_honours_prefix.patch
- python-3.3.0b1-fix_date_time_compiler.patch
- python-3.3.0b1-localpath.patch
- skip-test_pyobject_freed_is_freed.patch
-------------------------------------------------------------------
Fri May 16 13:44:12 UTC 2025 - Matej Cepl <mcepl@cepl.eu>

View File

@@ -162,8 +162,8 @@
# _md5.cpython-38m-x86_64-linux-gnu.so
%define dynlib() %{sitedir}/lib-dynload/%{1}.cpython-%{abi_tag}-%{archname}-%{_os}%{?_gnu}%{?armsuffix}.so
Name: %{python_pkg_name}%{psuffix}
Version: 3.14.0~b1
%define tarversion 3.14.0b1
Version: 3.14.0~b2
%define tarversion 3.14.0b2
%define tarname Python-%{tarversion}
Release: 0
Summary: Python 3 Interpreter
@@ -219,9 +219,6 @@ Patch39: CVE-2023-52425-libexpat-2.6.0-backport-15.6.patch
# PATCH-FIX-OPENSUSE fix-test-recursion-limit-15.6.patch gh#python/cpython#115083
# Skip some failing tests in test_compile for i586 arch in 15.6.
Patch40: fix-test-recursion-limit-15.6.patch
# PATCH-FIX-UPSTREAM CVE-2025-4516-DecodeError-handler.patch bsc#1243273 mcepl@suse.com
# this patch makes things totally awesome
Patch41: CVE-2025-4516-DecodeError-handler.patch
#### Python 3.14 DEVELOPMENT PATCHES
BuildRequires: autoconf-archive
BuildRequires: automake

View File

@@ -2,11 +2,9 @@
Lib/test/test_capi/test_mem.py | 1 +
1 file changed, 1 insertion(+)
Index: Python-3.14.0a7/Lib/test/test_capi/test_mem.py
===================================================================
--- Python-3.14.0a7.orig/Lib/test/test_capi/test_mem.py 2025-04-12 23:55:23.949981777 +0200
+++ Python-3.14.0a7/Lib/test/test_capi/test_mem.py 2025-04-12 23:58:00.502480186 +0200
@@ -114,6 +114,7 @@
--- a/Lib/test/test_capi/test_mem.py
+++ b/Lib/test/test_capi/test_mem.py
@@ -114,6 +114,7 @@ class PyMemDebugTests(unittest.TestCase)
def test_pyobject_forbidden_bytes_is_freed(self):
self.check_pyobject_is_freed('check_pyobject_forbidden_bytes_is_freed')