diff --git a/Doc/library/base64.rst b/Doc/library/base64.rst
index 529a7242443820..2d901824335145 100644
--- a/Doc/library/base64.rst
+++ b/Doc/library/base64.rst
@@ -267,14 +267,20 @@ Refer to the documentation of the individual functions for more information.
.. versionadded:: 3.4
-.. function:: z85encode(s)
+.. function:: z85encode(s, pad=False)
Encode the :term:`bytes-like object` *s* using Z85 (as used in ZeroMQ)
and return the encoded :class:`bytes`. See `Z85 specification
`_ for more information.
+ If *pad* is true, the input is padded with ``b'\0'`` so its length is a
+ multiple of 4 bytes before encoding.
+
.. versionadded:: 3.13
+ .. versionchanged:: next
+ The *pad* parameter was added.
+
.. function:: z85decode(s)
diff --git a/Lib/base64.py b/Lib/base64.py
index 341bf8eaf1891e..c2fdee8eab9690 100644
--- a/Lib/base64.py
+++ b/Lib/base64.py
@@ -508,9 +508,9 @@ def b85decode(b):
)
_z85_encode_translation = bytes.maketrans(_b85alphabet, _z85alphabet)
-def z85encode(s):
+def z85encode(s, pad=False):
"""Encode bytes-like object b in z85 format and return a bytes object."""
- return b85encode(s).translate(_z85_encode_translation)
+ return b85encode(s, pad).translate(_z85_encode_translation)
def z85decode(s):
"""Decode the z85-encoded bytes-like object or ASCII string b
diff --git a/Lib/test/test_base64.py b/Lib/test/test_base64.py
index ac3f09405457df..288caf663e8321 100644
--- a/Lib/test/test_base64.py
+++ b/Lib/test/test_base64.py
@@ -665,6 +665,7 @@ def test_z85encode(self):
tests = {
b'': b'',
+ b'\x86\x4F\xD2\x6F\xB5\x59\xF7\x5B': b'HelloWorld',
b'www.python.org': b'CxXl-AcVLsz/dgCA+t',
bytes(range(255)): b"""009c61o!#m2NH?C3>iWS5d]J*6CRx17-skh9337x"""
b"""ar.{NbQB=+c[cR@eg&FcfFLssg=mfIi5%2YjuU>)kTv.7l}6Nnnj=AD"""
@@ -840,6 +841,21 @@ def test_b85_padding(self):
eq(base64.b85decode(b'czAet'), b"xxxx")
eq(base64.b85decode(b'czAetcmMzZ'), b"xxxxx\x00\x00\x00")
+ def test_z85_padding(self):
+ eq = self.assertEqual
+
+ eq(base64.z85encode(b"x", pad=True), b'CMmZz')
+ eq(base64.z85encode(b"xx", pad=True), b'CZ6h*')
+ eq(base64.z85encode(b"xxx", pad=True), b'CZaDk')
+ eq(base64.z85encode(b"xxxx", pad=True), b'CZaET')
+ eq(base64.z85encode(b"xxxxx", pad=True), b'CZaETCMmZz')
+
+ eq(base64.z85decode(b'CMmZz'), b"x\x00\x00\x00")
+ eq(base64.z85decode(b'CZ6h*'), b"xx\x00\x00")
+ eq(base64.z85decode(b'CZaDk'), b"xxx\x00")
+ eq(base64.z85decode(b'CZaET'), b"xxxx")
+ eq(base64.z85decode(b'CZaETCMmZz'), b"xxxxx\x00\x00\x00")
+
def test_a85decode_errors(self):
illegal = (set(range(32)) | set(range(118, 256))) - set(b' \t\n\r\v')
for c in illegal:
diff --git a/Lib/test/test_ctypes/test_struct_fields.py b/Lib/test/test_ctypes/test_struct_fields.py
index b50bbcbb65c423..dc26e26d8a9fb1 100644
--- a/Lib/test/test_ctypes/test_struct_fields.py
+++ b/Lib/test/test_ctypes/test_struct_fields.py
@@ -130,6 +130,21 @@ class S(Structure):
self.check_struct(S)
self.assertEqual(S.largeField.bit_size, size * 8)
+ def test_bitfield_overflow_error_message(self):
+ with self.assertRaisesRegex(
+ ValueError,
+ r"bit field 'x' overflows its type \(2 \+ 7 > 8\)",
+ ):
+ CField(
+ name="x",
+ type=c_byte,
+ byte_size=1,
+ byte_offset=0,
+ index=0,
+ _internal_use=True,
+ bit_size=7,
+ bit_offset=2,
+ )
# __set__ and __get__ should raise a TypeError in case their self
# argument is not a ctype instance.
diff --git a/Lib/test/test_free_threading/test_gc.py b/Lib/test/test_free_threading/test_gc.py
index 3b83e0431efa6b..8b45b6e2150c28 100644
--- a/Lib/test/test_free_threading/test_gc.py
+++ b/Lib/test/test_free_threading/test_gc.py
@@ -62,6 +62,38 @@ def mutator_thread():
with threading_helper.start_threads(gcs + mutators):
pass
+ def test_freeze_object_in_brc_queue(self):
+ # GH-142975: Freezing objects in the BRC queue could result in some
+ # objects having a zero refcount without being deallocated.
+
+ class Weird:
+ # We need a destructor to trigger the check for object resurrection
+ def __del__(self):
+ pass
+
+ # This is owned by the main thread, so the subthread will have to increment
+ # this object's reference count.
+ weird = Weird()
+
+ def evil():
+ gc.freeze()
+
+ # Decrement the reference count from this thread, which will trigger the
+ # slow path during resurrection and add our weird object to the BRC queue.
+ nonlocal weird
+ del weird
+
+ # Collection will merge the object's reference count and make it zero.
+ gc.collect()
+
+ # Unfreeze the object, making it visible to the GC.
+ gc.unfreeze()
+ gc.collect()
+
+ thread = Thread(target=evil)
+ thread.start()
+ thread.join()
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/ACKS b/Misc/ACKS
index a14089a39cce82..bb6b6bde822a4e 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -418,6 +418,7 @@ Lisandro Dalcin
Darren Dale
Andrew Dalke
Lars Damerow
+Hauke Dämpfling
Evan Dandrea
Eric Daniel
Scott David Daniels
diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-24-13-44-24.gh-issue-142975.8C4vIP.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-24-13-44-24.gh-issue-142975.8C4vIP.rst
new file mode 100644
index 00000000000000..9d7f57ee60aa47
--- /dev/null
+++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-24-13-44-24.gh-issue-142975.8C4vIP.rst
@@ -0,0 +1,2 @@
+Fix crash after unfreezing all objects tracked by the garbage collector on
+the :term:`free threaded ` build.
diff --git a/Misc/NEWS.d/next/Library/2025-12-23-17-07-22.gh-issue-143103.LRjXEW.rst b/Misc/NEWS.d/next/Library/2025-12-23-17-07-22.gh-issue-143103.LRjXEW.rst
new file mode 100644
index 00000000000000..b00c03707ca352
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-23-17-07-22.gh-issue-143103.LRjXEW.rst
@@ -0,0 +1 @@
+Add padding support to :func:`base64.z85encode` via the ``pad`` parameter.
diff --git a/Misc/NEWS.d/next/Library/2025-12-24-14-18-52.gh-issue-143145.eXLw8D.rst b/Misc/NEWS.d/next/Library/2025-12-24-14-18-52.gh-issue-143145.eXLw8D.rst
new file mode 100644
index 00000000000000..2aff1090b1812f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-24-14-18-52.gh-issue-143145.eXLw8D.rst
@@ -0,0 +1 @@
+Fixed a possible reference leak in ctypes when constructing results with multiple output parameters on error.
diff --git a/Misc/NEWS.d/next/Library/2025-12-25-08-58-55.gh-issue-142164.XrFztf.rst b/Misc/NEWS.d/next/Library/2025-12-25-08-58-55.gh-issue-142164.XrFztf.rst
new file mode 100644
index 00000000000000..e75270b9e94c03
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2025-12-25-08-58-55.gh-issue-142164.XrFztf.rst
@@ -0,0 +1 @@
+Fix the ctypes bitfield overflow error message to report the correct offset and size calculation.
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 774ac71ce9ec56..563e95a762599b 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -4557,6 +4557,7 @@ _build_result(PyObject *result, PyObject *callargs,
v = PyTuple_GET_ITEM(callargs, i);
v = PyObject_CallMethodNoArgs(v, &_Py_ID(__ctypes_from_outparam__));
if (v == NULL || numretvals == 1) {
+ Py_XDECREF(tup);
Py_DECREF(callargs);
return v;
}
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 547e2471a1cbc0..4ebca0e0b3db0a 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -160,8 +160,8 @@ PyCField_new_impl(PyTypeObject *type, PyObject *name, PyObject *proto,
if ((bitfield_size + bit_offset) > byte_size * 8) {
PyErr_Format(
PyExc_ValueError,
- "bit field %R overflows its type (%zd + %zd >= %zd)",
- name, bit_offset, byte_size*8);
+ "bit field %R overflows its type (%zd + %zd > %zd)",
+ name, bit_offset, bitfield_size, byte_size * 8);
goto error;
}
}
diff --git a/Python/gc_free_threading.c b/Python/gc_free_threading.c
index 04b9b8f3f85603..51261cea0cfe2c 100644
--- a/Python/gc_free_threading.c
+++ b/Python/gc_free_threading.c
@@ -906,7 +906,11 @@ gc_visit_thread_stacks_mark_alive(PyInterpreterState *interp, gc_mark_args_t *ar
static void
queue_untracked_obj_decref(PyObject *op, struct collection_state *state)
{
- if (!_PyObject_GC_IS_TRACKED(op)) {
+ assert(Py_REFCNT(op) == 0);
+ // gh-142975: We have to treat frozen objects as untracked in this function
+ // or else they might be picked up in a future collection, which breaks the
+ // assumption that all incoming objects have a non-zero reference count.
+ if (!_PyObject_GC_IS_TRACKED(op) || gc_is_frozen(op)) {
// GC objects with zero refcount are handled subsequently by the
// GC as if they were cyclic trash, but we have to handle dead
// non-GC objects here. Add one to the refcount so that we can