Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ jobs:
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
# supported by important vendors such as AWS-LC.
openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4]
openssl_ver: [1.1.1w, 3.0.18, 3.3.5, 3.4.3, 3.5.4, 3.6.0]
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
Expand Down
11 changes: 8 additions & 3 deletions Lib/stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,14 @@ def filemode(mode):
perm = []
for index, table in enumerate(_filemode_table):
for bit, char in table:
if mode & bit == bit:
perm.append(char)
break
if index == 0:
if S_IFMT(mode) == bit:
perm.append(char)
break
else:
if mode & bit == bit:
perm.append(char)
break
else:
if index == 0:
# Unknown filetype
Expand Down
5 changes: 5 additions & 0 deletions Lib/test/test_stat.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ def test_mode(self):
self.statmod.S_IFREG)
self.assertEqual(self.statmod.S_IMODE(st_mode), 0o666)

def test_filemode_does_not_misclassify_random_bits(self):
# gh-144050 regression test
self.assertEqual(self.statmod.filemode(0o77777)[0], "?")
self.assertEqual(self.statmod.filemode(0o177777)[0], "?")

@os_helper.skip_unless_working_chmod
def test_directory(self):
os.mkdir(TESTFN)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for OpenSSL 3.6, drop EOL 3.2. Patch by Hugo van Kemenade.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :func:`stat.filemode` in the pure-Python implementation to avoid misclassifying
invalid mode values as block devices.
2 changes: 1 addition & 1 deletion Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ static void _PySSLFixErrno(void) {
/* Include generated data (error codes) */
/* See Tools/ssl/make_ssl_data.py for notes on adding a new version. */
#if (OPENSSL_VERSION_NUMBER >= 0x30401000L)
#include "_ssl_data_35.h"
#include "_ssl_data_36.h"
#elif (OPENSSL_VERSION_NUMBER >= 0x30100000L)
#include "_ssl_data_340.h"
#elif (OPENSSL_VERSION_NUMBER >= 0x30000000L)
Expand Down
24 changes: 22 additions & 2 deletions Modules/_ssl_data_35.h → Modules/_ssl_data_36.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* File generated by Tools/ssl/make_ssl_data.py */
/* Generated on 2025-10-04T17:49:19.148321+00:00 */
/* Generated from Git commit openssl-3.5.4-0-gc1eeb9406 */
/* Generated on 2026-01-17T13:03:49.335767+00:00 */
/* Generated from Git commit openssl-3.6.0-0-g7b371d80d9 */

/* generated from args.lib2errnum */
static struct py_ssl_library_code library_codes[] = {
Expand Down Expand Up @@ -1863,6 +1863,11 @@ static struct py_ssl_error_code error_codes[] = {
#else
{"NOT_KEK", 46, 123},
#endif
#ifdef CMS_R_NOT_KEM
{"NOT_KEM", ERR_LIB_CMS, CMS_R_NOT_KEM},
#else
{"NOT_KEM", 46, 197},
#endif
#ifdef CMS_R_NOT_KEY_AGREEMENT
{"NOT_KEY_AGREEMENT", ERR_LIB_CMS, CMS_R_NOT_KEY_AGREEMENT},
#else
Expand Down Expand Up @@ -2058,6 +2063,11 @@ static struct py_ssl_error_code error_codes[] = {
#else
{"UNKNOWN_ID", 46, 150},
#endif
#ifdef CMS_R_UNKNOWN_KDF_ALGORITHM
{"UNKNOWN_KDF_ALGORITHM", ERR_LIB_CMS, CMS_R_UNKNOWN_KDF_ALGORITHM},
#else
{"UNKNOWN_KDF_ALGORITHM", 46, 198},
#endif
#ifdef CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM
{"UNSUPPORTED_COMPRESSION_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_COMPRESSION_ALGORITHM},
#else
Expand All @@ -2078,6 +2088,11 @@ static struct py_ssl_error_code error_codes[] = {
#else
{"UNSUPPORTED_ENCRYPTION_TYPE", 46, 192},
#endif
#ifdef CMS_R_UNSUPPORTED_KDF_ALGORITHM
{"UNSUPPORTED_KDF_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KDF_ALGORITHM},
#else
{"UNSUPPORTED_KDF_ALGORITHM", 46, 199},
#endif
#ifdef CMS_R_UNSUPPORTED_KEK_ALGORITHM
{"UNSUPPORTED_KEK_ALGORITHM", ERR_LIB_CMS, CMS_R_UNSUPPORTED_KEK_ALGORITHM},
#else
Expand Down Expand Up @@ -5763,6 +5778,11 @@ static struct py_ssl_error_code error_codes[] = {
#else
{"PSS_SALTLEN_TOO_SMALL", 57, 172},
#endif
#ifdef PROV_R_REPEATED_PARAMETER
{"REPEATED_PARAMETER", ERR_LIB_PROV, PROV_R_REPEATED_PARAMETER},
#else
{"REPEATED_PARAMETER", 57, 252},
#endif
#ifdef PROV_R_REQUEST_TOO_LARGE_FOR_DRBG
{"REQUEST_TOO_LARGE_FOR_DRBG", ERR_LIB_PROV, PROV_R_REQUEST_TOO_LARGE_FOR_DRBG},
#else
Expand Down
3 changes: 1 addition & 2 deletions Modules/_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -2662,8 +2662,7 @@ The optional first format char indicates byte order, size and alignment:\n\
The remaining chars indicate types of args and must match exactly;\n\
these can be preceded by a decimal repeat count:\n\
x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\
?: _Bool (requires C99; if not available, char is used instead)\n\
h:short; H:unsigned short; i:int; I:unsigned int;\n\
?:_Bool; h:short; H:unsigned short; i:int; I:unsigned int;\n\
l:long; L:unsigned long; f:float; d:double; e:half-float.\n\
F:float complex; D:double complex.\n\
Special cases (preceding decimal count indicates length):\n\
Expand Down
52 changes: 34 additions & 18 deletions Python/gc_free_threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,17 +308,18 @@ disable_deferred_refcounting(PyObject *op)
// should also be disabled when we turn off deferred refcounting.
_PyObject_DisablePerThreadRefcounting(op);
}

// Generators and frame objects may contain deferred references to other
// objects. If the pointed-to objects are part of cyclic trash, we may
// have disabled deferred refcounting on them and need to ensure that we
// use strong references, in case the generator or frame object is
// resurrected by a finalizer.
if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) {
frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe);
}
else if (PyFrame_Check(op)) {
frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame);
if (_PyObject_GC_IS_TRACKED(op)) {
// Generators and frame objects may contain deferred references to other
// objects. If the pointed-to objects are part of cyclic trash, we may
// have disabled deferred refcounting on them and need to ensure that we
// use strong references, in case the generator or frame object is
// resurrected by a finalizer.
if (PyGen_CheckExact(op) || PyCoro_CheckExact(op) || PyAsyncGen_CheckExact(op)) {
frame_disable_deferred_refcounting(&((PyGenObject *)op)->gi_iframe);
}
else if (PyFrame_Check(op)) {
frame_disable_deferred_refcounting(((PyFrameObject *)op)->f_frame);
}
}
}

Expand Down Expand Up @@ -1240,19 +1241,30 @@ scan_heap_visitor(const mi_heap_t *heap, const mi_heap_area_t *area,
return true;
}

if (state->reason == _Py_GC_REASON_SHUTDOWN) {
// Disable deferred refcounting for reachable objects as well during
// interpreter shutdown. This ensures that these objects are collected
// immediately when their last reference is removed.
disable_deferred_refcounting(op);
}

// object is reachable, restore `ob_tid`; we're done with these objects
gc_restore_tid(op);
gc_clear_alive(op);
return true;
}

// Disable deferred refcounting for reachable objects during interpreter
// shutdown. This ensures that these objects are collected immediately when
// their last reference is removed. This needs to consider both tracked and
// untracked GC objects, since either might have deferred refcounts enabled.
static bool
scan_heap_disable_deferred(const mi_heap_t *heap, const mi_heap_area_t *area,
void *block, size_t block_size, void *args)
{
PyObject *op = op_from_block_all_gc(block, args);
if (op == NULL) {
return true;
}
if (!_Py_IsImmortal(op)) {
disable_deferred_refcounting(op);
}
return true;
}

static int
move_legacy_finalizer_reachable(struct collection_state *state);

Expand Down Expand Up @@ -1487,6 +1499,10 @@ deduce_unreachable_heap(PyInterpreterState *interp,
// Restores ob_tid for reachable objects.
gc_visit_heaps(interp, &scan_heap_visitor, &state->base);

if (state->reason == _Py_GC_REASON_SHUTDOWN) {
gc_visit_heaps(interp, &scan_heap_disable_deferred, &state->base);
}

if (state->legacy_finalizers.head) {
// There may be objects reachable from legacy finalizers that are in
// the unreachable set. We need to mark them as reachable.
Expand Down
4 changes: 2 additions & 2 deletions Tools/ssl/make_ssl_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
git tag --list 'openssl-*'
git switch --detach openssl-3.4.1
After generating the definitions, compare the result with newest pre-existing file.
You can use a command like:
After generating the definitions, compare the result with the newest
pre-existing file. You can use a command like:
git diff --no-index Modules/_ssl_data_340.h Modules/_ssl_data_341.h
Expand Down
3 changes: 2 additions & 1 deletion Tools/ssl/multissltests.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@
OPENSSL_OLD_VERSIONS = [
"1.1.1w",
"3.1.8",
"3.2.6",
]

OPENSSL_RECENT_VERSIONS = [
"3.0.18",
"3.2.6",
"3.3.5",
"3.4.3",
"3.5.4",
"3.6.0",
# See make_ssl_data.py for notes on adding a new version.
]

Expand Down
Loading