Skip to content

Commit b7eab32

Browse files
authored
Merge branch 'main' into with_except_start_tb_ref
2 parents dec4ef9 + 9e474a9 commit b7eab32

File tree

11 files changed

+328
-212
lines changed

11 files changed

+328
-212
lines changed

Doc/library/email.errors.rst

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,12 @@ The following exception classes are defined in the :mod:`email.errors` module:
4545

4646
.. exception:: MultipartConversionError()
4747

48-
Raised when a payload is added to a :class:`~email.message.Message` object
49-
using :meth:`add_payload`, but the payload is already a scalar and the
50-
message's :mailheader:`Content-Type` main type is not either
51-
:mimetype:`multipart` or missing. :exc:`MultipartConversionError` multiply
52-
inherits from :exc:`MessageError` and the built-in :exc:`TypeError`.
53-
54-
Since :meth:`Message.add_payload` is deprecated, this exception is rarely
55-
raised in practice. However the exception may also be raised if the
56-
:meth:`~email.message.Message.attach`
57-
method is called on an instance of a class derived from
48+
Raised if the :meth:`~email.message.Message.attach` method is called
49+
on an instance of a class derived from
5850
:class:`~email.mime.nonmultipart.MIMENonMultipart` (e.g.
5951
:class:`~email.mime.image.MIMEImage`).
52+
:exc:`MultipartConversionError` multiply
53+
inherits from :exc:`MessageError` and the built-in :exc:`TypeError`.
6054

6155

6256
.. exception:: HeaderWriteError()

Include/cpython/object.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,13 +494,13 @@ PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int m
494494
#define Py_TRASHCAN_BEGIN(op, dealloc) \
495495
do { \
496496
PyThreadState *tstate = PyThreadState_Get(); \
497-
if (_Py_ReachedRecursionLimitWithMargin(tstate, 1) && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
497+
if (_Py_ReachedRecursionLimitWithMargin(tstate, 2) && Py_TYPE(op)->tp_dealloc == (destructor)dealloc) { \
498498
_PyTrash_thread_deposit_object(tstate, (PyObject *)op); \
499499
break; \
500500
}
501501
/* The body of the deallocator is here. */
502502
#define Py_TRASHCAN_END \
503-
if (tstate->delete_later && !_Py_ReachedRecursionLimitWithMargin(tstate, 2)) { \
503+
if (tstate->delete_later && !_Py_ReachedRecursionLimitWithMargin(tstate, 4)) { \
504504
_PyTrash_thread_destroy_chain(tstate); \
505505
} \
506506
} while (0);

Lib/test/support/__init__.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -835,15 +835,18 @@ def gc_threshold(*args):
835835
finally:
836836
gc.set_threshold(*old_threshold)
837837

838-
839838
def python_is_optimized():
840839
"""Find if Python was built with optimizations."""
841840
cflags = sysconfig.get_config_var('PY_CFLAGS') or ''
842841
final_opt = ""
843842
for opt in cflags.split():
844843
if opt.startswith('-O'):
845844
final_opt = opt
846-
return final_opt not in ('', '-O0', '-Og')
845+
if sysconfig.get_config_var("CC") == "gcc":
846+
non_opts = ('', '-O0', '-Og')
847+
else:
848+
non_opts = ('', '-O0')
849+
return final_opt not in non_opts
847850

848851

849852
def check_cflags_pgo():

Lib/test/test_http_cookiejar.py

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -227,10 +227,19 @@ def test_parse_ns_headers_special_names(self):
227227
self.assertEqual(parse_ns_headers([hdr]), expected)
228228

229229
def test_join_header_words(self):
230-
joined = join_header_words([[("foo", None), ("bar", "baz")]])
231-
self.assertEqual(joined, "foo; bar=baz")
232-
233-
self.assertEqual(join_header_words([[]]), "")
230+
for src, expected in [
231+
([[("foo", None), ("bar", "baz")]], "foo; bar=baz"),
232+
(([]), ""),
233+
(([[]]), ""),
234+
(([[("a", "_")]]), "a=_"),
235+
(([[("a", ";")]]), 'a=";"'),
236+
([[("n", None), ("foo", "foo;_")], [("bar", "foo_bar")]],
237+
'n; foo="foo;_", bar=foo_bar'),
238+
([[("n", "m"), ("foo", None)], [("bar", "foo_bar")]],
239+
'n=m; foo, bar=foo_bar'),
240+
]:
241+
with self.subTest(src=src):
242+
self.assertEqual(join_header_words(src), expected)
234243

235244
def test_split_header_words(self):
236245
tests = [
@@ -286,7 +295,10 @@ def test_roundtrip(self):
286295
'foo=bar; port="80,81"; discard, bar=baz'),
287296

288297
(r'Basic realm="\"foo\\\\bar\""',
289-
r'Basic; realm="\"foo\\\\bar\""')
298+
r'Basic; realm="\"foo\\\\bar\""'),
299+
300+
('n; foo="foo;_", bar=foo!_',
301+
'n; foo="foo;_", bar="foo!_"'),
290302
]
291303

292304
for arg, expect in tests:

Lib/test/test_zipapp.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,30 @@ def skip_pyc_files(path):
8989
self.assertIn('test.py', z.namelist())
9090
self.assertNotIn('test.pyc', z.namelist())
9191

92+
def test_create_archive_self_insertion(self):
93+
# When creating an archive, we shouldn't
94+
# include the archive in the list of files to add.
95+
source = self.tmpdir
96+
(source / '__main__.py').touch()
97+
(source / 'test.py').touch()
98+
target = self.tmpdir / 'target.pyz'
99+
100+
zipapp.create_archive(source, target)
101+
with zipfile.ZipFile(target, 'r') as z:
102+
self.assertEqual(len(z.namelist()), 2)
103+
self.assertIn('__main__.py', z.namelist())
104+
self.assertIn('test.py', z.namelist())
105+
106+
def test_target_overwrites_source_file(self):
107+
# The target cannot be one of the files to add.
108+
source = self.tmpdir
109+
(source / '__main__.py').touch()
110+
target = source / 'target.pyz'
111+
target.touch()
112+
113+
with self.assertRaises(zipapp.ZipAppError):
114+
zipapp.create_archive(source, target)
115+
92116
def test_create_archive_filter_exclude_dir(self):
93117
# Test packing a directory and using a filter to exclude a
94118
# subdirectory (ensures that the path supplied to include

Lib/zipapp.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,14 +131,37 @@ def create_archive(source, target=None, interpreter=None, main=None,
131131
elif not hasattr(target, 'write'):
132132
target = pathlib.Path(target)
133133

134+
# Create the list of files to add to the archive now, in case
135+
# the target is being created in the source directory - we
136+
# don't want the target being added to itself
137+
files_to_add = sorted(source.rglob('*'))
138+
139+
# The target cannot be in the list of files to add. If it were, we'd
140+
# end up overwriting the source file and writing the archive into
141+
# itself, which is an error. We therefore check for that case and
142+
# provide a helpful message for the user.
143+
144+
# Note that we only do a simple path equality check. This won't
145+
# catch every case, but it will catch the common case where the
146+
# source is the CWD and the target is a file in the CWD. More
147+
# thorough checks don't provide enough value to justify the extra
148+
# cost.
149+
150+
# If target is a file-like object, it will simply fail to compare
151+
# equal to any of the entries in files_to_add, so there's no need
152+
# to add a special check for that.
153+
if target in files_to_add:
154+
raise ZipAppError(
155+
f"The target archive {target} overwrites one of the source files.")
156+
134157
with _maybe_open(target, 'wb') as fd:
135158
_write_file_prefix(fd, interpreter)
136159
compression = (zipfile.ZIP_DEFLATED if compressed else
137160
zipfile.ZIP_STORED)
138161
with zipfile.ZipFile(fd, 'w', compression=compression) as z:
139-
for child in sorted(source.rglob('*')):
162+
for child in files_to_add:
140163
arcname = child.relative_to(source)
141-
if filter is None or filter(arcname) and child.resolve() != arcname.resolve():
164+
if filter is None or filter(arcname):
142165
z.write(child, arcname.as_posix())
143166
if main_py:
144167
z.writestr('__main__.py', main_py.encode('utf-8'))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
The zipapp module now calculates the list of files to be added to the archive before creating the archive. This avoids accidentally including the target when it is being created in the source directory.

Modules/_hashopenssl.c

Lines changed: 44 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,8 @@ typedef struct {
281281
PyMutex mutex; /* OpenSSL context lock */
282282
} EVPobject;
283283

284+
#define EVPobject_CAST(op) ((EVPobject *)(op))
285+
284286
typedef struct {
285287
PyObject_HEAD
286288
HMAC_CTX *ctx; /* OpenSSL hmac context */
@@ -289,6 +291,8 @@ typedef struct {
289291
PyMutex mutex; /* HMAC context lock */
290292
} HMACobject;
291293

294+
#define HMACobject_CAST(op) ((HMACobject *)(op))
295+
292296
#include "clinic/_hashopenssl.c.h"
293297
/*[clinic input]
294298
module _hashlib
@@ -478,7 +482,7 @@ py_digest_by_digestmod(PyObject *module, PyObject *digestmod, enum Py_hash_type
478482
static EVPobject *
479483
newEVPobject(PyTypeObject *type)
480484
{
481-
EVPobject *retval = (EVPobject *)PyObject_New(EVPobject, type);
485+
EVPobject *retval = PyObject_New(EVPobject, type);
482486
if (retval == NULL) {
483487
return NULL;
484488
}
@@ -517,8 +521,9 @@ EVP_hash(EVPobject *self, const void *vp, Py_ssize_t len)
517521
/* Internal methods for a hash object */
518522

519523
static void
520-
EVP_dealloc(EVPobject *self)
524+
EVP_dealloc(PyObject *op)
521525
{
526+
EVPobject *self = EVPobject_CAST(op);
522527
PyTypeObject *tp = Py_TYPE(self);
523528
EVP_MD_CTX_free(self->ctx);
524529
PyObject_Free(self);
@@ -676,55 +681,47 @@ static PyMethodDef EVP_methods[] = {
676681
};
677682

678683
static PyObject *
679-
EVP_get_block_size(EVPobject *self, void *closure)
684+
EVP_get_block_size(PyObject *op, void *Py_UNUSED(closure))
680685
{
681-
long block_size;
682-
block_size = EVP_MD_CTX_block_size(self->ctx);
686+
EVPobject *self = EVPobject_CAST(op);
687+
long block_size = EVP_MD_CTX_block_size(self->ctx);
683688
return PyLong_FromLong(block_size);
684689
}
685690

686691
static PyObject *
687-
EVP_get_digest_size(EVPobject *self, void *closure)
692+
EVP_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
688693
{
689-
long size;
690-
size = EVP_MD_CTX_size(self->ctx);
694+
EVPobject *self = EVPobject_CAST(op);
695+
long size = EVP_MD_CTX_size(self->ctx);
691696
return PyLong_FromLong(size);
692697
}
693698

694699
static PyObject *
695-
EVP_get_name(EVPobject *self, void *closure)
700+
EVP_get_name(PyObject *op, void *Py_UNUSED(closure))
696701
{
702+
EVPobject *self = EVPobject_CAST(op);
703+
// NOTE(picnixz): NULL EVP context will be handled by gh-127667.
697704
return py_digest_name(EVP_MD_CTX_md(self->ctx));
698705
}
699706

700707
static PyGetSetDef EVP_getseters[] = {
701-
{"digest_size",
702-
(getter)EVP_get_digest_size, NULL,
703-
NULL,
704-
NULL},
705-
{"block_size",
706-
(getter)EVP_get_block_size, NULL,
707-
NULL,
708-
NULL},
709-
{"name",
710-
(getter)EVP_get_name, NULL,
711-
NULL,
712-
PyDoc_STR("algorithm name.")},
708+
{"digest_size", EVP_get_digest_size, NULL, NULL, NULL},
709+
{"block_size", EVP_get_block_size, NULL, NULL, NULL},
710+
{"name", EVP_get_name, NULL, NULL, PyDoc_STR("algorithm name.")},
713711
{NULL} /* Sentinel */
714712
};
715713

716714

717715
static PyObject *
718-
EVP_repr(EVPobject *self)
716+
EVP_repr(PyObject *self)
719717
{
720-
PyObject *name_obj, *repr;
721-
name_obj = py_digest_name(EVP_MD_CTX_md(self->ctx));
722-
if (!name_obj) {
718+
PyObject *name = EVP_get_name(self, NULL);
719+
if (name == NULL) {
723720
return NULL;
724721
}
725-
repr = PyUnicode_FromFormat("<%U %s object @ %p>",
726-
name_obj, Py_TYPE(self)->tp_name, self);
727-
Py_DECREF(name_obj);
722+
PyObject *repr = PyUnicode_FromFormat("<%U %T object @ %p>",
723+
name, self, self);
724+
Py_DECREF(name);
728725
return repr;
729726
}
730727

@@ -866,16 +863,13 @@ static PyMethodDef EVPXOF_methods[] = {
866863

867864

868865
static PyObject *
869-
EVPXOF_get_digest_size(EVPobject *self, void *closure)
866+
EVPXOF_get_digest_size(PyObject *Py_UNUSED(self), void *Py_UNUSED(closure))
870867
{
871868
return PyLong_FromLong(0);
872869
}
873870

874871
static PyGetSetDef EVPXOF_getseters[] = {
875-
{"digest_size",
876-
(getter)EVPXOF_get_digest_size, NULL,
877-
NULL,
878-
NULL},
872+
{"digest_size", EVPXOF_get_digest_size, NULL, NULL, NULL},
879873
{NULL} /* Sentinel */
880874
};
881875

@@ -1628,6 +1622,7 @@ locked_HMAC_CTX_copy(HMAC_CTX *new_ctx_p, HMACobject *self)
16281622
static unsigned int
16291623
_hmac_digest_size(HMACobject *self)
16301624
{
1625+
// TODO(picnixz): NULL EVP context should also handled by gh-127667.
16311626
unsigned int digest_size = EVP_MD_size(HMAC_CTX_get_md(self->ctx));
16321627
assert(digest_size <= EVP_MAX_MD_SIZE);
16331628
return digest_size;
@@ -1696,8 +1691,9 @@ _hashlib_HMAC_copy_impl(HMACobject *self)
16961691
}
16971692

16981693
static void
1699-
_hmac_dealloc(HMACobject *self)
1694+
_hmac_dealloc(PyObject *op)
17001695
{
1696+
HMACobject *self = HMACobject_CAST(op);
17011697
PyTypeObject *tp = Py_TYPE(self);
17021698
if (self->ctx != NULL) {
17031699
HMAC_CTX_free(self->ctx);
@@ -1708,8 +1704,9 @@ _hmac_dealloc(HMACobject *self)
17081704
}
17091705

17101706
static PyObject *
1711-
_hmac_repr(HMACobject *self)
1707+
_hmac_repr(PyObject *op)
17121708
{
1709+
HMACobject *self = HMACobject_CAST(op);
17131710
PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
17141711
if (digest_name == NULL) {
17151712
return NULL;
@@ -1807,8 +1804,9 @@ _hashlib_HMAC_hexdigest_impl(HMACobject *self)
18071804
}
18081805

18091806
static PyObject *
1810-
_hashlib_hmac_get_digest_size(HMACobject *self, void *closure)
1807+
_hashlib_hmac_get_digest_size(PyObject *op, void *Py_UNUSED(closure))
18111808
{
1809+
HMACobject *self = HMACobject_CAST(op);
18121810
unsigned int digest_size = _hmac_digest_size(self);
18131811
if (digest_size == 0) {
18141812
return _setException(PyExc_ValueError, NULL);
@@ -1817,8 +1815,9 @@ _hashlib_hmac_get_digest_size(HMACobject *self, void *closure)
18171815
}
18181816

18191817
static PyObject *
1820-
_hashlib_hmac_get_block_size(HMACobject *self, void *closure)
1818+
_hashlib_hmac_get_block_size(PyObject *op, void *Py_UNUSED(closure))
18211819
{
1820+
HMACobject *self = HMACobject_CAST(op);
18221821
const EVP_MD *md = HMAC_CTX_get_md(self->ctx);
18231822
if (md == NULL) {
18241823
return _setException(PyExc_ValueError, NULL);
@@ -1827,8 +1826,9 @@ _hashlib_hmac_get_block_size(HMACobject *self, void *closure)
18271826
}
18281827

18291828
static PyObject *
1830-
_hashlib_hmac_get_name(HMACobject *self, void *closure)
1829+
_hashlib_hmac_get_name(PyObject *op, void *Py_UNUSED(closure))
18311830
{
1831+
HMACobject *self = HMACobject_CAST(op);
18321832
PyObject *digest_name = py_digest_name(HMAC_CTX_get_md(self->ctx));
18331833
if (digest_name == NULL) {
18341834
return NULL;
@@ -1847,9 +1847,9 @@ static PyMethodDef HMAC_methods[] = {
18471847
};
18481848

18491849
static PyGetSetDef HMAC_getset[] = {
1850-
{"digest_size", (getter)_hashlib_hmac_get_digest_size, NULL, NULL, NULL},
1851-
{"block_size", (getter)_hashlib_hmac_get_block_size, NULL, NULL, NULL},
1852-
{"name", (getter)_hashlib_hmac_get_name, NULL, NULL, NULL},
1850+
{"digest_size", _hashlib_hmac_get_digest_size, NULL, NULL, NULL},
1851+
{"block_size", _hashlib_hmac_get_block_size, NULL, NULL, NULL},
1852+
{"name", _hashlib_hmac_get_name, NULL, NULL, NULL},
18531853
{NULL} /* Sentinel */
18541854
};
18551855

@@ -1871,8 +1871,8 @@ digest_size -- number of bytes in digest() output\n");
18711871

18721872
static PyType_Slot HMACtype_slots[] = {
18731873
{Py_tp_doc, (char *)hmactype_doc},
1874-
{Py_tp_repr, (reprfunc)_hmac_repr},
1875-
{Py_tp_dealloc,(destructor)_hmac_dealloc},
1874+
{Py_tp_repr, _hmac_repr},
1875+
{Py_tp_dealloc, _hmac_dealloc},
18761876
{Py_tp_methods, HMAC_methods},
18771877
{Py_tp_getset, HMAC_getset},
18781878
{0, NULL}
@@ -2165,7 +2165,7 @@ hashlib_clear(PyObject *m)
21652165
static void
21662166
hashlib_free(void *m)
21672167
{
2168-
hashlib_clear((PyObject *)m);
2168+
(void)hashlib_clear((PyObject *)m);
21692169
}
21702170

21712171
/* Py_mod_exec functions */

0 commit comments

Comments
 (0)