Skip to content

Commit 44a03a1

Browse files
Merge branch 'main' into sigsegv_fix_in_iterators
2 parents f056908 + 7ffe94f commit 44a03a1

File tree

13 files changed

+160
-132
lines changed

13 files changed

+160
-132
lines changed

Doc/c-api/tuple.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,8 @@ type.
167167
168168
.. c:member:: const char *name
169169
170-
Name of the struct sequence type.
170+
Fully qualified name of the type; null-terminated UTF-8 encoded.
171+
The name must contain the module name.
171172
172173
.. c:member:: const char *doc
173174

Doc/library/importlib.metadata.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ Entry points
122122

123123
Returns a :class:`EntryPoints` instance describing entry points for the
124124
current environment. Any given keyword parameters are passed to the
125-
:meth:`!~EntryPoints.select` method for comparison to the attributes of
125+
:meth:`!select` method for comparison to the attributes of
126126
the individual entry point definitions.
127127

128128
Note: it is not currently possible to query for entry points based on
@@ -158,7 +158,7 @@ attributes for convenience::
158158
>>> sorted(eps.groups) # doctest: +SKIP
159159
['console_scripts', 'distutils.commands', 'distutils.setup_keywords', 'egg_info.writers', 'setuptools.installation']
160160

161-
:class:`!EntryPoints` has a :meth:`!~EntryPoints.select` method to select entry points
161+
:class:`!EntryPoints` has a :meth:`!select` method to select entry points
162162
matching specific properties. Select entry points in the
163163
``console_scripts`` group::
164164

@@ -232,7 +232,7 @@ Distribution metadata
232232
`PackageMetadata protocol <https://importlib-metadata.readthedocs.io/en/latest/api.html#importlib_metadata.PackageMetadata>`_.
233233

234234
In addition to providing the defined protocol methods and attributes, subscripting
235-
the instance is equivalent to calling the :meth:`!~PackageMetadata.get` method.
235+
the instance is equivalent to calling the :meth:`!get` method.
236236

237237
Every `Distribution Package <https://packaging.python.org/en/latest/glossary/#term-Distribution-Package>`_
238238
includes some metadata, which you can extract using the :func:`!metadata` function::
@@ -245,7 +245,7 @@ the values are returned unparsed from the distribution metadata::
245245
>>> wheel_metadata['Requires-Python'] # doctest: +SKIP
246246
'>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*'
247247

248-
:class:`PackageMetadata` also presents a :attr:`!~PackageMetadata.json` attribute that returns
248+
:class:`PackageMetadata` also presents a :attr:`!json` attribute that returns
249249
all the metadata in a JSON-compatible form per :PEP:`566`::
250250

251251
>>> wheel_metadata.json['requires_python']
@@ -331,7 +331,7 @@ Once you have the file, you can also read its contents::
331331
return s.encode('utf-8')
332332
return s
333333

334-
You can also use the :meth:`!~PackagePath.locate` method to get the absolute
334+
You can also use the :meth:`!locate` method to get the absolute
335335
path to the file::
336336

337337
>>> util.locate() # doctest: +SKIP

Doc/library/logging.config.rst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -753,16 +753,17 @@ The ``queue`` and ``listener`` keys are optional.
753753

754754
If the ``queue`` key is present, the corresponding value can be one of the following:
755755

756-
* An object implementing the :class:`queue.Queue` public API. For instance,
757-
this may be an actual instance of :class:`queue.Queue` or a subclass thereof,
758-
or a proxy obtained by :meth:`multiprocessing.managers.SyncManager.Queue`.
756+
* An object implementing the :meth:`Queue.put_nowait <queue.Queue.put_nowait>`
757+
and :meth:`Queue.get <queue.Queue.get>` public API. For instance, this may be
758+
an actual instance of :class:`queue.Queue` or a subclass thereof, or a proxy
759+
obtained by :meth:`multiprocessing.managers.SyncManager.Queue`.
759760

760761
This is of course only possible if you are constructing or modifying
761762
the configuration dictionary in code.
762763

763764
* A string that resolves to a callable which, when called with no arguments, returns
764-
the :class:`queue.Queue` instance to use. That callable could be a
765-
:class:`queue.Queue` subclass or a function which returns a suitable queue instance,
765+
the queue instance to use. That callable could be a :class:`queue.Queue` subclass
766+
or a function which returns a suitable queue instance,
766767
such as ``my.module.queue_factory()``.
767768

768769
* A dict with a ``'()'`` key which is constructed in the usual way as discussed in

Include/internal/pycore_stackref.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,8 @@ PyStackRef_AsPyObjectBorrow(_PyStackRef stackref)
111111
static inline PyObject *
112112
PyStackRef_AsPyObjectSteal(_PyStackRef stackref)
113113
{
114-
if (!PyStackRef_IsNull(stackref) && PyStackRef_IsDeferred(stackref)) {
114+
assert(!PyStackRef_IsNull(stackref));
115+
if (PyStackRef_IsDeferred(stackref)) {
115116
return Py_NewRef(PyStackRef_AsPyObjectBorrow(stackref));
116117
}
117118
return PyStackRef_AsPyObjectBorrow(stackref);
@@ -131,9 +132,10 @@ PyStackRef_AsPyObjectSteal(_PyStackRef stackref)
131132
static inline _PyStackRef
132133
_PyStackRef_FromPyObjectSteal(PyObject *obj)
133134
{
135+
assert(obj != NULL);
134136
// Make sure we don't take an already tagged value.
135137
assert(((uintptr_t)obj & Py_TAG_BITS) == 0);
136-
unsigned int tag = (obj == NULL || _Py_IsImmortal(obj)) ? (Py_TAG_DEFERRED) : Py_TAG_PTR;
138+
unsigned int tag = _Py_IsImmortal(obj) ? (Py_TAG_DEFERRED) : Py_TAG_PTR;
137139
return ((_PyStackRef){.bits = ((uintptr_t)(obj)) | tag});
138140
}
139141
# define PyStackRef_FromPyObjectSteal(obj) _PyStackRef_FromPyObjectSteal(_PyObject_CAST(obj))
@@ -193,6 +195,7 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj)
193195
# define PyStackRef_CLOSE(REF) \
194196
do { \
195197
_PyStackRef _close_tmp = (REF); \
198+
assert(!PyStackRef_IsNull(_close_tmp)); \
196199
if (!PyStackRef_IsDeferred(_close_tmp)) { \
197200
Py_DECREF(PyStackRef_AsPyObjectBorrow(_close_tmp)); \
198201
} \
@@ -214,10 +217,11 @@ PyStackRef_FromPyObjectImmortal(PyObject *obj)
214217
static inline _PyStackRef
215218
PyStackRef_DUP(_PyStackRef stackref)
216219
{
220+
assert(!PyStackRef_IsNull(stackref));
217221
if (PyStackRef_IsDeferred(stackref)) {
218-
assert(PyStackRef_IsNull(stackref) ||
219-
_Py_IsImmortal(PyStackRef_AsPyObjectBorrow(stackref)) ||
220-
_PyObject_HasDeferredRefcount(PyStackRef_AsPyObjectBorrow(stackref)));
222+
assert(_Py_IsImmortal(PyStackRef_AsPyObjectBorrow(stackref)) ||
223+
_PyObject_HasDeferredRefcount(PyStackRef_AsPyObjectBorrow(stackref))
224+
);
221225
return stackref;
222226
}
223227
Py_INCREF(PyStackRef_AsPyObjectBorrow(stackref));

Lib/logging/config.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,7 @@ def as_tuple(self, value):
499499

500500
def _is_queue_like_object(obj):
501501
"""Check that *obj* implements the Queue API."""
502-
if isinstance(obj, queue.Queue):
502+
if isinstance(obj, (queue.Queue, queue.SimpleQueue)):
503503
return True
504504
# defer importing multiprocessing as much as possible
505505
from multiprocessing.queues import Queue as MPQueue
@@ -516,13 +516,13 @@ def _is_queue_like_object(obj):
516516
# Ideally, we would have wanted to simply use strict type checking
517517
# instead of a protocol-based type checking since the latter does
518518
# not check the method signatures.
519-
queue_interface = [
520-
'empty', 'full', 'get', 'get_nowait',
521-
'put', 'put_nowait', 'join', 'qsize',
522-
'task_done',
523-
]
519+
#
520+
# Note that only 'put_nowait' and 'get' are required by the logging
521+
# queue handler and queue listener (see gh-124653) and that other
522+
# methods are either optional or unused.
523+
minimal_queue_interface = ['put_nowait', 'get']
524524
return all(callable(getattr(obj, method, None))
525-
for method in queue_interface)
525+
for method in minimal_queue_interface)
526526

527527
class DictConfigurator(BaseConfigurator):
528528
"""

Lib/test/certdata/make_ssl_certs.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,6 @@ def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='',
139139
f.write(req)
140140
args = ['req', '-new', '-nodes', '-days', cmdlineargs.days,
141141
'-newkey', key, '-keyout', key_file,
142-
'-extensions', ext,
143142
'-config', req_file]
144143
if sign:
145144
with tempfile.NamedTemporaryFile(delete=False) as f:
@@ -148,7 +147,7 @@ def make_cert_key(cmdlineargs, hostname, sign=False, extra_san='',
148147
args += ['-out', reqfile ]
149148

150149
else:
151-
args += ['-x509', '-out', cert_file ]
150+
args += ['-extensions', ext, '-x509', '-out', cert_file ]
152151
check_call(['openssl'] + args)
153152

154153
if sign:

Lib/test/test_logging.py

Lines changed: 64 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2377,16 +2377,22 @@ def __getattr__(self, attribute):
23772377
return getattr(queue, attribute)
23782378

23792379
class CustomQueueFakeProtocol(CustomQueueProtocol):
2380-
# An object implementing the Queue API (incorrect signatures).
2380+
# An object implementing the minimial Queue API for
2381+
# the logging module but with incorrect signatures.
2382+
#
23812383
# The object will be considered a valid queue class since we
23822384
# do not check the signatures (only callability of methods)
23832385
# but will NOT be usable in production since a TypeError will
2384-
# be raised due to a missing argument.
2385-
def empty(self, x):
2386+
# be raised due to the extra argument in 'put_nowait'.
2387+
def put_nowait(self):
23862388
pass
23872389

23882390
class CustomQueueWrongProtocol(CustomQueueProtocol):
2389-
empty = None
2391+
put_nowait = None
2392+
2393+
class MinimalQueueProtocol:
2394+
def put_nowait(self, x): pass
2395+
def get(self): pass
23902396

23912397
def queueMaker():
23922398
return queue.Queue()
@@ -3946,56 +3952,70 @@ def test_config_queue_handler(self):
39463952
msg = str(ctx.exception)
39473953
self.assertEqual(msg, "Unable to configure handler 'ah'")
39483954

3955+
def _apply_simple_queue_listener_configuration(self, qspec):
3956+
self.apply_config({
3957+
"version": 1,
3958+
"handlers": {
3959+
"queue_listener": {
3960+
"class": "logging.handlers.QueueHandler",
3961+
"queue": qspec,
3962+
},
3963+
},
3964+
})
3965+
39493966
@threading_helper.requires_working_threading()
39503967
@support.requires_subprocess()
39513968
@patch("multiprocessing.Manager")
39523969
def test_config_queue_handler_does_not_create_multiprocessing_manager(self, manager):
3953-
# gh-120868, gh-121723
3954-
3955-
from multiprocessing import Queue as MQ
3956-
3957-
q1 = {"()": "queue.Queue", "maxsize": -1}
3958-
q2 = MQ()
3959-
q3 = queue.Queue()
3960-
# CustomQueueFakeProtocol passes the checks but will not be usable
3961-
# since the signatures are incompatible. Checking the Queue API
3962-
# without testing the type of the actual queue is a trade-off
3963-
# between usability and the work we need to do in order to safely
3964-
# check that the queue object correctly implements the API.
3965-
q4 = CustomQueueFakeProtocol()
3966-
3967-
for qspec in (q1, q2, q3, q4):
3968-
self.apply_config(
3969-
{
3970-
"version": 1,
3971-
"handlers": {
3972-
"queue_listener": {
3973-
"class": "logging.handlers.QueueHandler",
3974-
"queue": qspec,
3975-
},
3976-
},
3977-
}
3978-
)
3979-
manager.assert_not_called()
3970+
# gh-120868, gh-121723, gh-124653
3971+
3972+
for qspec in [
3973+
{"()": "queue.Queue", "maxsize": -1},
3974+
queue.Queue(),
3975+
# queue.SimpleQueue does not inherit from queue.Queue
3976+
queue.SimpleQueue(),
3977+
# CustomQueueFakeProtocol passes the checks but will not be usable
3978+
# since the signatures are incompatible. Checking the Queue API
3979+
# without testing the type of the actual queue is a trade-off
3980+
# between usability and the work we need to do in order to safely
3981+
# check that the queue object correctly implements the API.
3982+
CustomQueueFakeProtocol(),
3983+
MinimalQueueProtocol(),
3984+
]:
3985+
with self.subTest(qspec=qspec):
3986+
self._apply_simple_queue_listener_configuration(qspec)
3987+
manager.assert_not_called()
39803988

39813989
@patch("multiprocessing.Manager")
39823990
def test_config_queue_handler_invalid_config_does_not_create_multiprocessing_manager(self, manager):
39833991
# gh-120868, gh-121723
39843992

39853993
for qspec in [object(), CustomQueueWrongProtocol()]:
3986-
with self.assertRaises(ValueError):
3987-
self.apply_config(
3988-
{
3989-
"version": 1,
3990-
"handlers": {
3991-
"queue_listener": {
3992-
"class": "logging.handlers.QueueHandler",
3993-
"queue": qspec,
3994-
},
3995-
},
3996-
}
3997-
)
3998-
manager.assert_not_called()
3994+
with self.subTest(qspec=qspec), self.assertRaises(ValueError):
3995+
self._apply_simple_queue_listener_configuration(qspec)
3996+
manager.assert_not_called()
3997+
3998+
@skip_if_tsan_fork
3999+
@support.requires_subprocess()
4000+
@unittest.skipUnless(support.Py_DEBUG, "requires a debug build for testing"
4001+
" assertions in multiprocessing")
4002+
def test_config_reject_simple_queue_handler_multiprocessing_context(self):
4003+
# multiprocessing.SimpleQueue does not implement 'put_nowait'
4004+
# and thus cannot be used as a queue-like object (gh-124653)
4005+
4006+
import multiprocessing
4007+
4008+
if support.MS_WINDOWS:
4009+
start_methods = ['spawn']
4010+
else:
4011+
start_methods = ['spawn', 'fork', 'forkserver']
4012+
4013+
for start_method in start_methods:
4014+
with self.subTest(start_method=start_method):
4015+
ctx = multiprocessing.get_context(start_method)
4016+
qspec = ctx.SimpleQueue()
4017+
with self.assertRaises(ValueError):
4018+
self._apply_simple_queue_listener_configuration(qspec)
39994019

40004020
@skip_if_tsan_fork
40014021
@support.requires_subprocess()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix detection of the minimal Queue API needed by the :mod:`logging` module.
2+
Patch by Bénédikt Tran.

Modules/_csv.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ static struct PyMemberDef Dialect_memberlist[] = {
367367
{ NULL }
368368
};
369369

370+
#undef D_OFF
371+
370372
static PyGetSetDef Dialect_getsetlist[] = {
371373
{ "delimiter", (getter)Dialect_get_delimiter},
372374
{ "escapechar", (getter)Dialect_get_escapechar},
@@ -502,6 +504,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
502504
DIALECT_GETATTR(skipinitialspace, "skipinitialspace");
503505
DIALECT_GETATTR(strict, "strict");
504506
}
507+
#undef DIALECT_GETATTR
505508

506509
/* check types and convert to C values */
507510
#define DIASET(meth, name, target, src, dflt) \
@@ -515,6 +518,7 @@ dialect_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
515518
DIASET(_set_int, "quoting", &self->quoting, quoting, QUOTE_MINIMAL);
516519
DIASET(_set_bool, "skipinitialspace", &self->skipinitialspace, skipinitialspace, false);
517520
DIASET(_set_bool, "strict", &self->strict, strict, false);
521+
#undef DIASET
518522

519523
/* validate options */
520524
if (dialect_check_quoting(self->quoting))
@@ -1026,6 +1030,8 @@ static struct PyMemberDef Reader_memberlist[] = {
10261030
{ NULL }
10271031
};
10281032

1033+
#undef R_OFF
1034+
10291035

10301036
static PyType_Slot Reader_Type_slots[] = {
10311037
{Py_tp_doc, (char*)Reader_Type_doc},
@@ -1441,6 +1447,8 @@ static struct PyMemberDef Writer_memberlist[] = {
14411447
{ NULL }
14421448
};
14431449

1450+
#undef W_OFF
1451+
14441452
static int
14451453
Writer_traverse(WriterObj *self, visitproc visit, void *arg)
14461454
{

Objects/longobject.c

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4828,21 +4828,12 @@ long_divmod(PyObject *a, PyObject *b)
48284828
static PyLongObject *
48294829
long_invmod(PyLongObject *a, PyLongObject *n)
48304830
{
4831-
PyLongObject *b, *c;
4832-
48334831
/* Should only ever be called for positive n */
48344832
assert(_PyLong_IsPositive(n));
48354833

4836-
b = (PyLongObject *)PyLong_FromLong(1L);
4837-
if (b == NULL) {
4838-
return NULL;
4839-
}
4840-
c = (PyLongObject *)PyLong_FromLong(0L);
4841-
if (c == NULL) {
4842-
Py_DECREF(b);
4843-
return NULL;
4844-
}
48454834
Py_INCREF(a);
4835+
PyLongObject *b = (PyLongObject *)Py_NewRef(_PyLong_GetOne());
4836+
PyLongObject *c = (PyLongObject *)Py_NewRef(_PyLong_GetZero());
48464837
Py_INCREF(n);
48474838

48484839
/* references now owned: a, b, c, n */

0 commit comments

Comments
 (0)