Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9e6658a

Browse files
committed
Merge remote-tracking branch 'upstream/main' into tvobject
2 parents 8a783b3 + 563c7dc commit 9e6658a

15 files changed

Lines changed: 647 additions & 469 deletions

Lib/http/server.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,10 @@ def parse_request(self):
300300
# - Leading zeros MUST be ignored by recipients.
301301
if len(version_number) != 2:
302302
raise ValueError
303+
if any(not component.isdigit() for component in version_number):
304+
raise ValueError("non digit in http version")
305+
if any(len(component) > 10 for component in version_number):
306+
raise ValueError("unreasonable length http version")
303307
version_number = int(version_number[0]), int(version_number[1])
304308
except (ValueError, IndexError):
305309
self.send_error(

Lib/test/test_capi/test_misc.py

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1748,28 +1748,80 @@ class Subclass(BaseException, self.module.StateAccessType):
17481748

17491749
class Test_Pep523API(unittest.TestCase):
17501750

1751-
def do_test(self, func):
1752-
calls = []
1751+
def do_test(self, func, names):
1752+
actual_calls = []
17531753
start = SUFFICIENT_TO_DEOPT_AND_SPECIALIZE
17541754
count = start + SUFFICIENT_TO_DEOPT_AND_SPECIALIZE
1755-
for i in range(count):
1756-
if i == start:
1757-
_testinternalcapi.set_eval_frame_record(calls)
1758-
func()
1759-
_testinternalcapi.set_eval_frame_default()
1760-
self.assertEqual(len(calls), SUFFICIENT_TO_DEOPT_AND_SPECIALIZE)
1761-
for name in calls:
1762-
self.assertEqual(name, func.__name__)
1763-
1764-
def test_pep523_with_specialization_simple(self):
1765-
def func1():
1766-
pass
1767-
self.do_test(func1)
1755+
try:
1756+
for i in range(count):
1757+
if i == start:
1758+
_testinternalcapi.set_eval_frame_record(actual_calls)
1759+
func()
1760+
finally:
1761+
_testinternalcapi.set_eval_frame_default()
1762+
expected_calls = names * SUFFICIENT_TO_DEOPT_AND_SPECIALIZE
1763+
self.assertEqual(len(expected_calls), len(actual_calls))
1764+
for expected, actual in zip(expected_calls, actual_calls, strict=True):
1765+
self.assertEqual(expected, actual)
1766+
1767+
def test_inlined_binary_subscr(self):
1768+
class C:
1769+
def __getitem__(self, other):
1770+
return None
1771+
def func():
1772+
C()[42]
1773+
names = ["func", "__getitem__"]
1774+
self.do_test(func, names)
17681775

1769-
def test_pep523_with_specialization_with_default(self):
1770-
def func2(x=None):
1776+
def test_inlined_call(self):
1777+
def inner(x=42):
1778+
pass
1779+
def func():
1780+
inner()
1781+
inner(42)
1782+
names = ["func", "inner", "inner"]
1783+
self.do_test(func, names)
1784+
1785+
def test_inlined_call_function_ex(self):
1786+
def inner(x):
17711787
pass
1772-
self.do_test(func2)
1788+
def func():
1789+
inner(*[42])
1790+
names = ["func", "inner"]
1791+
self.do_test(func, names)
1792+
1793+
def test_inlined_for_iter(self):
1794+
def gen():
1795+
yield 42
1796+
def func():
1797+
for _ in gen():
1798+
pass
1799+
names = ["func", "gen", "gen", "gen"]
1800+
self.do_test(func, names)
1801+
1802+
def test_inlined_load_attr(self):
1803+
class C:
1804+
@property
1805+
def a(self):
1806+
return 42
1807+
class D:
1808+
def __getattribute__(self, name):
1809+
return 42
1810+
def func():
1811+
C().a
1812+
D().a
1813+
names = ["func", "a", "__getattribute__"]
1814+
self.do_test(func, names)
1815+
1816+
def test_inlined_send(self):
1817+
def inner():
1818+
yield 42
1819+
def outer():
1820+
yield from inner()
1821+
def func():
1822+
list(outer())
1823+
names = ["func", "outer", "outer", "inner", "inner", "outer", "inner"]
1824+
self.do_test(func, names)
17731825

17741826

17751827
if __name__ == "__main__":

Lib/test/test_exceptions.py

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -417,45 +417,45 @@ def testAttributes(self):
417417
# test that exception attributes are happy
418418

419419
exceptionList = [
420-
(BaseException, (), {'args' : ()}),
421-
(BaseException, (1, ), {'args' : (1,)}),
422-
(BaseException, ('foo',),
420+
(BaseException, (), {}, {'args' : ()}),
421+
(BaseException, (1, ), {}, {'args' : (1,)}),
422+
(BaseException, ('foo',), {},
423423
{'args' : ('foo',)}),
424-
(BaseException, ('foo', 1),
424+
(BaseException, ('foo', 1), {},
425425
{'args' : ('foo', 1)}),
426-
(SystemExit, ('foo',),
426+
(SystemExit, ('foo',), {},
427427
{'args' : ('foo',), 'code' : 'foo'}),
428-
(OSError, ('foo',),
428+
(OSError, ('foo',), {},
429429
{'args' : ('foo',), 'filename' : None, 'filename2' : None,
430430
'errno' : None, 'strerror' : None}),
431-
(OSError, ('foo', 'bar'),
431+
(OSError, ('foo', 'bar'), {},
432432
{'args' : ('foo', 'bar'),
433433
'filename' : None, 'filename2' : None,
434434
'errno' : 'foo', 'strerror' : 'bar'}),
435-
(OSError, ('foo', 'bar', 'baz'),
435+
(OSError, ('foo', 'bar', 'baz'), {},
436436
{'args' : ('foo', 'bar'),
437437
'filename' : 'baz', 'filename2' : None,
438438
'errno' : 'foo', 'strerror' : 'bar'}),
439-
(OSError, ('foo', 'bar', 'baz', None, 'quux'),
439+
(OSError, ('foo', 'bar', 'baz', None, 'quux'), {},
440440
{'args' : ('foo', 'bar'), 'filename' : 'baz', 'filename2': 'quux'}),
441-
(OSError, ('errnoStr', 'strErrorStr', 'filenameStr'),
441+
(OSError, ('errnoStr', 'strErrorStr', 'filenameStr'), {},
442442
{'args' : ('errnoStr', 'strErrorStr'),
443443
'strerror' : 'strErrorStr', 'errno' : 'errnoStr',
444444
'filename' : 'filenameStr'}),
445-
(OSError, (1, 'strErrorStr', 'filenameStr'),
445+
(OSError, (1, 'strErrorStr', 'filenameStr'), {},
446446
{'args' : (1, 'strErrorStr'), 'errno' : 1,
447447
'strerror' : 'strErrorStr',
448448
'filename' : 'filenameStr', 'filename2' : None}),
449-
(SyntaxError, (), {'msg' : None, 'text' : None,
449+
(SyntaxError, (), {}, {'msg' : None, 'text' : None,
450450
'filename' : None, 'lineno' : None, 'offset' : None,
451451
'end_offset': None, 'print_file_and_line' : None}),
452-
(SyntaxError, ('msgStr',),
452+
(SyntaxError, ('msgStr',), {},
453453
{'args' : ('msgStr',), 'text' : None,
454454
'print_file_and_line' : None, 'msg' : 'msgStr',
455455
'filename' : None, 'lineno' : None, 'offset' : None,
456456
'end_offset': None}),
457457
(SyntaxError, ('msgStr', ('filenameStr', 'linenoStr', 'offsetStr',
458-
'textStr', 'endLinenoStr', 'endOffsetStr')),
458+
'textStr', 'endLinenoStr', 'endOffsetStr')), {},
459459
{'offset' : 'offsetStr', 'text' : 'textStr',
460460
'args' : ('msgStr', ('filenameStr', 'linenoStr',
461461
'offsetStr', 'textStr',
@@ -465,46 +465,48 @@ def testAttributes(self):
465465
'end_lineno': 'endLinenoStr', 'end_offset': 'endOffsetStr'}),
466466
(SyntaxError, ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
467467
'textStr', 'endLinenoStr', 'endOffsetStr',
468-
'print_file_and_lineStr'),
468+
'print_file_and_lineStr'), {},
469469
{'text' : None,
470470
'args' : ('msgStr', 'filenameStr', 'linenoStr', 'offsetStr',
471471
'textStr', 'endLinenoStr', 'endOffsetStr',
472472
'print_file_and_lineStr'),
473473
'print_file_and_line' : None, 'msg' : 'msgStr',
474474
'filename' : None, 'lineno' : None, 'offset' : None,
475475
'end_lineno': None, 'end_offset': None}),
476-
(UnicodeError, (), {'args' : (),}),
476+
(UnicodeError, (), {}, {'args' : (),}),
477477
(UnicodeEncodeError, ('ascii', 'a', 0, 1,
478-
'ordinal not in range'),
478+
'ordinal not in range'), {},
479479
{'args' : ('ascii', 'a', 0, 1,
480480
'ordinal not in range'),
481481
'encoding' : 'ascii', 'object' : 'a',
482482
'start' : 0, 'reason' : 'ordinal not in range'}),
483483
(UnicodeDecodeError, ('ascii', bytearray(b'\xff'), 0, 1,
484-
'ordinal not in range'),
484+
'ordinal not in range'), {},
485485
{'args' : ('ascii', bytearray(b'\xff'), 0, 1,
486486
'ordinal not in range'),
487487
'encoding' : 'ascii', 'object' : b'\xff',
488488
'start' : 0, 'reason' : 'ordinal not in range'}),
489489
(UnicodeDecodeError, ('ascii', b'\xff', 0, 1,
490-
'ordinal not in range'),
490+
'ordinal not in range'), {},
491491
{'args' : ('ascii', b'\xff', 0, 1,
492492
'ordinal not in range'),
493493
'encoding' : 'ascii', 'object' : b'\xff',
494494
'start' : 0, 'reason' : 'ordinal not in range'}),
495-
(UnicodeTranslateError, ("\u3042", 0, 1, "ouch"),
495+
(UnicodeTranslateError, ("\u3042", 0, 1, "ouch"), {},
496496
{'args' : ('\u3042', 0, 1, 'ouch'),
497497
'object' : '\u3042', 'reason' : 'ouch',
498498
'start' : 0, 'end' : 1}),
499-
(NaiveException, ('foo',),
499+
(NaiveException, ('foo',), {},
500500
{'args': ('foo',), 'x': 'foo'}),
501-
(SlottedNaiveException, ('foo',),
501+
(SlottedNaiveException, ('foo',), {},
502502
{'args': ('foo',), 'x': 'foo'}),
503+
(AttributeError, ('foo',), dict(name='name', obj='obj'),
504+
dict(args=('foo',), name='name', obj='obj')),
503505
]
504506
try:
505507
# More tests are in test_WindowsError
506508
exceptionList.append(
507-
(WindowsError, (1, 'strErrorStr', 'filenameStr'),
509+
(WindowsError, (1, 'strErrorStr', 'filenameStr'), {},
508510
{'args' : (1, 'strErrorStr'),
509511
'strerror' : 'strErrorStr', 'winerror' : None,
510512
'errno' : 1,
@@ -513,11 +515,11 @@ def testAttributes(self):
513515
except NameError:
514516
pass
515517

516-
for exc, args, expected in exceptionList:
518+
for exc, args, kwargs, expected in exceptionList:
517519
try:
518-
e = exc(*args)
520+
e = exc(*args, **kwargs)
519521
except:
520-
print("\nexc=%r, args=%r" % (exc, args), file=sys.stderr)
522+
print(f"\nexc={exc!r}, args={args!r}", file=sys.stderr)
521523
# raise
522524
else:
523525
# Verify module name
@@ -540,7 +542,12 @@ def testAttributes(self):
540542
new = p.loads(s)
541543
for checkArgName in expected:
542544
got = repr(getattr(new, checkArgName))
543-
want = repr(expected[checkArgName])
545+
if exc == AttributeError and checkArgName == 'obj':
546+
# See GH-103352, we're not pickling
547+
# obj at this point. So verify it's None.
548+
want = repr(None)
549+
else:
550+
want = repr(expected[checkArgName])
544551
self.assertEqual(got, want,
545552
'pickled "%r", attribute "%s' %
546553
(e, checkArgName))

Lib/test/test_httpservers.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,27 @@ def test_version_digits(self):
164164
res = self.con.getresponse()
165165
self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
166166

167+
def test_version_signs_and_underscores(self):
168+
self.con._http_vsn_str = 'HTTP/-9_9_9.+9_9_9'
169+
self.con.putrequest('GET', '/')
170+
self.con.endheaders()
171+
res = self.con.getresponse()
172+
self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
173+
174+
def test_major_version_number_too_long(self):
175+
self.con._http_vsn_str = 'HTTP/909876543210.0'
176+
self.con.putrequest('GET', '/')
177+
self.con.endheaders()
178+
res = self.con.getresponse()
179+
self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
180+
181+
def test_minor_version_number_too_long(self):
182+
self.con._http_vsn_str = 'HTTP/1.909876543210'
183+
self.con.putrequest('GET', '/')
184+
self.con.endheaders()
185+
res = self.con.getresponse()
186+
self.assertEqual(res.status, HTTPStatus.BAD_REQUEST)
187+
167188
def test_version_none_get(self):
168189
self.con._http_vsn_str = ''
169190
self.con.putrequest('GET', '/')

Lib/test/test_listcomps.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,14 @@ def test_nested_3(self):
338338
outputs = {"y": [1, 3, 5]}
339339
self._check_in_scopes(code, outputs)
340340

341+
def test_nested_4(self):
342+
code = """
343+
items = [([lambda: x for x in range(2)], lambda: x) for x in range(3)]
344+
out = [([fn() for fn in fns], fn()) for fns, fn in items]
345+
"""
346+
outputs = {"out": [([1, 1], 2), ([1, 1], 2), ([1, 1], 2)]}
347+
self._check_in_scopes(code, outputs)
348+
341349
def test_nameerror(self):
342350
code = """
343351
[x for x in [1]]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:exc:`AttributeError` now retains the ``name`` attribute when pickled and unpickled.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix an issue where some :term:`bytecode` instructions could ignore
2+
:pep:`523` when "inlining" calls.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fixes :mod:`http.server` accepting HTTP requests with HTTP version numbers
2+
preceded by '+', or '-', or with digit-separating '_' characters. The length
3+
of the version numbers is also constrained.

Objects/exceptions.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2287,14 +2287,56 @@ AttributeError_traverse(PyAttributeErrorObject *self, visitproc visit, void *arg
22872287
return BaseException_traverse((PyBaseExceptionObject *)self, visit, arg);
22882288
}
22892289

2290+
/* Pickling support */
2291+
static PyObject *
2292+
AttributeError_getstate(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored))
2293+
{
2294+
PyObject *dict = ((PyAttributeErrorObject *)self)->dict;
2295+
if (self->name || self->args) {
2296+
dict = dict ? PyDict_Copy(dict) : PyDict_New();
2297+
if (dict == NULL) {
2298+
return NULL;
2299+
}
2300+
if (self->name && PyDict_SetItemString(dict, "name", self->name) < 0) {
2301+
Py_DECREF(dict);
2302+
return NULL;
2303+
}
2304+
/* We specifically are not pickling the obj attribute since there are many
2305+
cases where it is unlikely to be picklable. See GH-103352.
2306+
*/
2307+
if (self->args && PyDict_SetItemString(dict, "args", self->args) < 0) {
2308+
Py_DECREF(dict);
2309+
return NULL;
2310+
}
2311+
return dict;
2312+
}
2313+
else if (dict) {
2314+
return Py_NewRef(dict);
2315+
}
2316+
Py_RETURN_NONE;
2317+
}
2318+
2319+
static PyObject *
2320+
AttributeError_reduce(PyAttributeErrorObject *self, PyObject *Py_UNUSED(ignored))
2321+
{
2322+
PyObject *state = AttributeError_getstate(self, NULL);
2323+
if (state == NULL) {
2324+
return NULL;
2325+
}
2326+
2327+
return PyTuple_Pack(3, Py_TYPE(self), self->args, state);
2328+
}
2329+
22902330
static PyMemberDef AttributeError_members[] = {
22912331
{"name", T_OBJECT, offsetof(PyAttributeErrorObject, name), 0, PyDoc_STR("attribute name")},
22922332
{"obj", T_OBJECT, offsetof(PyAttributeErrorObject, obj), 0, PyDoc_STR("object")},
22932333
{NULL} /* Sentinel */
22942334
};
22952335

22962336
static PyMethodDef AttributeError_methods[] = {
2297-
{NULL} /* Sentinel */
2337+
{"__getstate__", (PyCFunction)AttributeError_getstate, METH_NOARGS},
2338+
{"__reduce__", (PyCFunction)AttributeError_reduce, METH_NOARGS },
2339+
{NULL}
22982340
};
22992341

23002342
ComplexExtendsException(PyExc_Exception, AttributeError,

Objects/obmalloc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -882,7 +882,7 @@ _Py_GetGlobalAllocatedBlocks(void)
882882

883883
/* Return a pointer to a bottom tree node, return NULL if it doesn't exist or
884884
* it cannot be created */
885-
static Py_ALWAYS_INLINE arena_map_bot_t *
885+
static inline Py_ALWAYS_INLINE arena_map_bot_t *
886886
arena_map_get(OMState *state, pymem_block *p, int create)
887887
{
888888
#ifdef USE_INTERIOR_NODES

0 commit comments

Comments
 (0)