Skip to content

Commit

Permalink
Merge branch '3.12' into backport-c39ae89-3.12
Browse files Browse the repository at this point in the history
  • Loading branch information
iritkatriel authored Jan 29, 2025
2 parents 421992e + f65aa0d commit fdb8a3e
Show file tree
Hide file tree
Showing 14 changed files with 247 additions and 8 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/reusable-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ env:
jobs:
build:
name: >-
build${{ inputs.arch != 'arm64' && ' and test' || '' }}
(${{ inputs.arch }})
name: ${{ inputs.arch == 'arm64' && 'build' || 'build and test' }} (${{ inputs.arch }})
runs-on: windows-latest
timeout-minutes: 60
env:
Expand Down
165 changes: 165 additions & 0 deletions Doc/library/errno.rst
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,171 @@ defined by the module. The specific list of defined symbols is available as

.. versionadded:: 3.11


.. data:: ENOMEDIUM

No medium found


.. data:: EMEDIUMTYPE

Wrong medium type


.. data:: ENOKEY

Required key not available


.. data:: EKEYEXPIRED

Key has expired


.. data:: EKEYREVOKED

Key has been revoked


.. data:: EKEYREJECTED

Key was rejected by service


.. data:: ERFKILL

Operation not possible due to RF-kill


.. data:: ELOCKUNMAPPED

Locked lock was unmapped


.. data:: ENOTACTIVE

Facility is not active


.. data:: EAUTH

Authentication error

.. versionadded:: 3.2


.. data:: EBADARCH

Bad CPU type in executable

.. versionadded:: 3.2


.. data:: EBADEXEC

Bad executable (or shared library)

.. versionadded:: 3.2


.. data:: EBADMACHO

Malformed Mach-o file

.. versionadded:: 3.2


.. data:: EDEVERR

Device error

.. versionadded:: 3.2


.. data:: EFTYPE

Inappropriate file type or format

.. versionadded:: 3.2


.. data:: ENEEDAUTH

Need authenticator

.. versionadded:: 3.2


.. data:: ENOATTR

Attribute not found

.. versionadded:: 3.2


.. data:: ENOPOLICY

Policy not found

.. versionadded:: 3.2


.. data:: EPROCLIM

Too many processes

.. versionadded:: 3.2


.. data:: EPROCUNAVAIL

Bad procedure for program

.. versionadded:: 3.2


.. data:: EPROGMISMATCH

Program version wrong

.. versionadded:: 3.2


.. data:: EPROGUNAVAIL

RPC prog. not avail

.. versionadded:: 3.2


.. data:: EPWROFF

Device power is off

.. versionadded:: 3.2


.. data:: EBADRPC

RPC struct is bad

.. versionadded:: 3.2


.. data:: ERPCMISMATCH

RPC version wrong

.. versionadded:: 3.2


.. data:: ESHLIBVERS

Shared library version mismatch

.. versionadded:: 3.2


.. data:: ENOTCAPABLE

Capabilities insufficient. This error is mapped to the exception
Expand Down
4 changes: 3 additions & 1 deletion Lib/http/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ def read(self, amt=None):
if self.chunked:
return self._read_chunked(amt)

if amt is not None:
if amt is not None and amt >= 0:
if self.length is not None and amt > self.length:
# clip the read to the "end of response"
amt = self.length
Expand Down Expand Up @@ -590,6 +590,8 @@ def _get_chunk_left(self):

def _read_chunked(self, amt=None):
assert self.chunked != _UNKNOWN
if amt is not None and amt < 0:
amt = None
value = []
try:
while (chunk_left := self._get_chunk_left()) is not None:
Expand Down
11 changes: 10 additions & 1 deletion Lib/imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@
# search command can be quite large, so we now use 1M.
_MAXLINE = 1000000

# Data larger than this will be read in chunks, to prevent extreme
# overallocation.
_SAFE_BUF_SIZE = 1 << 20

# Commands

Expand Down Expand Up @@ -315,7 +318,13 @@ def open(self, host='', port=IMAP4_PORT, timeout=None):

def read(self, size):
"""Read 'size' bytes from remote."""
return self.file.read(size)
cursize = min(size, _SAFE_BUF_SIZE)
data = self.file.read(cursize)
while cursize < size and len(data) == cursize:
delta = min(cursize, size - cursize)
data += self.file.read(delta)
cursize += delta
return data


def readline(self):
Expand Down
16 changes: 14 additions & 2 deletions Lib/subprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,8 @@
import builtins
import errno
import io
import locale
import os
import time
import signal
import sys
import threading
import warnings
Expand Down Expand Up @@ -138,6 +136,8 @@ def __init__(self, returncode, cmd, output=None, stderr=None):

def __str__(self):
if self.returncode and self.returncode < 0:
# Lazy import to improve module import time
import signal
try:
return "Command '%s' died with %r." % (
self.cmd, signal.Signals(-self.returncode))
Expand Down Expand Up @@ -375,6 +375,8 @@ def _text_encoding():
if sys.flags.utf8_mode:
return "utf-8"
else:
# Lazy import to improve module import time
import locale
return locale.getencoding()


Expand Down Expand Up @@ -1655,6 +1657,9 @@ def send_signal(self, sig):
# Don't signal a process that we know has already died.
if self.returncode is not None:
return

# Lazy import to improve module import time
import signal
if sig == signal.SIGTERM:
self.terminate()
elif sig == signal.CTRL_C_EVENT:
Expand Down Expand Up @@ -1759,6 +1764,9 @@ def _posix_spawn(self, args, executable, env, restore_signals,

kwargs = {}
if restore_signals:
# Lazy import to improve module import time
import signal

# See _Py_RestoreSignals() in Python/pylifecycle.c
sigset = []
for signame in ('SIGPIPE', 'SIGXFZ', 'SIGXFSZ'):
Expand Down Expand Up @@ -2208,9 +2216,13 @@ def send_signal(self, sig):
def terminate(self):
"""Terminate the process with SIGTERM
"""
# Lazy import to improve module import time
import signal
self.send_signal(signal.SIGTERM)

def kill(self):
"""Kill the process with SIGKILL
"""
# Lazy import to improve module import time
import signal
self.send_signal(signal.SIGKILL)
19 changes: 19 additions & 0 deletions Lib/test/test_httplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,25 @@ def test_chunked(self):
self.assertEqual(resp.read(), expected)
resp.close()

# Explicit full read
for n in (-123, -1, None):
with self.subTest('full read', n=n):
sock = FakeSocket(chunked_start + last_chunk + chunked_end)
resp = client.HTTPResponse(sock, method="GET")
resp.begin()
self.assertTrue(resp.chunked)
self.assertEqual(resp.read(n), expected)
resp.close()

# Read first chunk
with self.subTest('read1(-1)'):
sock = FakeSocket(chunked_start + last_chunk + chunked_end)
resp = client.HTTPResponse(sock, method="GET")
resp.begin()
self.assertTrue(resp.chunked)
self.assertEqual(resp.read1(-1), b"hello worl")
resp.close()

# Various read sizes
for n in range(1, 12):
sock = FakeSocket(chunked_start + last_chunk + chunked_end)
Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_imaplib.py
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,20 @@ def handle(self):
self.assertRaises(imaplib.IMAP4.error,
self.imap_class, *server.server_address)

def test_truncated_large_literal(self):
size = 0
class BadHandler(SimpleIMAPHandler):
def handle(self):
self._send_textline('* OK {%d}' % size)
self._send_textline('IMAP4rev1')

for exponent in range(15, 64):
size = 1 << exponent
with self.subTest(f"size=2e{size}"):
with self.reaped_server(BadHandler) as server:
with self.assertRaises(imaplib.IMAP4.abort):
self.imap_class(*server.server_address)

@threading_helper.reap_threads
def test_simple_with_statement(self):
# simplest call
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix incorrect handling of negative read sizes in :meth:`HTTPResponse.read
<http.client.HTTPResponse.read>`. Patch by Yury Manushkin.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
In :mod:`sqlite3`, handle out-of-memory when creating user-defined SQL
functions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Improve import time of :mod:`subprocess` by lazy importing ``locale`` and
``signal``. Patch by Taneli Hukkinen.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix an integer overflow in the :mod:`csv` module when writing a data field
larger than 2GB.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Fix a potential denial of service in the :mod:`imaplib` module. When connecting
to a malicious server, it could cause an arbitrary amount of memory to be
allocated. On many systems this is harmless as unused virtual memory is only a
mapping, but if this hit a virtual address size limit it could lead to a
:exc:`MemoryError` or other process crash. On unusual systems or builds where
all allocated memory is touched and backed by actual ram or storage it could've
consumed resources doing so until similarly crashing.
2 changes: 1 addition & 1 deletion Modules/_csv.c
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,7 @@ join_append_data(WriterObj *self, int field_kind, const void *field_data,
int copy_phase)
{
DialectObj *dialect = self->dialect;
int i;
Py_ssize_t i;
Py_ssize_t rec_len;

#define INCLEN \
Expand Down
5 changes: 5 additions & 0 deletions Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,11 @@ step_callback(sqlite3_context *context, int argc, sqlite3_value **params)
assert(ctx != NULL);

aggregate_instance = (PyObject**)sqlite3_aggregate_context(context, sizeof(PyObject*));
if (aggregate_instance == NULL) {
(void)PyErr_NoMemory();
set_sqlite_error(context, "unable to allocate SQLite aggregate context");
goto error;
}
if (*aggregate_instance == NULL) {
*aggregate_instance = PyObject_CallNoArgs(ctx->callable);
if (!*aggregate_instance) {
Expand Down

0 comments on commit fdb8a3e

Please sign in to comment.