Skip to content

Commit 1ad78fd

Browse files
authored
Merge branch 'main' into ascii-lower-upper-word
2 parents 492ef59 + 25181ce commit 1ad78fd

10 files changed

Lines changed: 81 additions & 8 deletions

‎.github/CODEOWNERS‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,12 @@ Lib/_osx_support.py @python/macos-team
172172
Lib/test/test__osx_support.py @python/macos-team
173173

174174
# WebAssembly (Emscripten)
175-
Platforms/emscripten @freakboy3742 @emmatyping
176-
Tools/wasm/emscripten @freakboy3742 @emmatyping
175+
Platforms/emscripten @freakboy3742 @emmatyping @hoodmane
176+
Tools/wasm/emscripten @freakboy3742 @emmatyping @hoodmane
177+
Python/wasm_trampoline.c @hoodmane
178+
Python/emscripten_signal.c @hoodmane
179+
Python/emscripten_syscalls.c @hoodmane
180+
.github/workflows/reusable-emscripten.yml @hoodmane
177181

178182
# WebAssembly (WASI)
179183
Platforms/WASI @brettcannon @emmatyping @savannahostrowski

‎Lib/pydoc.py‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2012,7 +2012,6 @@ class Helper:
20122012
':=': 'ASSIGNMENTEXPRESSIONS',
20132013
'_': 'PRIVATENAMES',
20142014
'__': 'PRIVATENAMES SPECIALMETHODS',
2015-
'`': 'BACKQUOTES',
20162015
'(': 'TUPLES FUNCTIONS CALLS',
20172016
')': 'TUPLES FUNCTIONS CALLS',
20182017
'[': 'LISTS SUBSCRIPTS SLICINGS',

‎Lib/tarfile.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1628,6 +1628,8 @@ def _proc_pax(self, tarfile):
16281628
except HeaderError as e:
16291629
raise SubsequentHeaderError(str(e)) from None
16301630

1631+
data_offset = next.offset_data
1632+
16311633
# Process GNU sparse information.
16321634
if "GNU.sparse.map" in pax_headers:
16331635
# GNU extended sparse format version 0.1.
@@ -1649,7 +1651,7 @@ def _proc_pax(self, tarfile):
16491651
# If the extended header replaces the size field,
16501652
# we need to recalculate the offset where the next
16511653
# header starts.
1652-
offset = next.offset + BLOCKSIZE
1654+
offset = data_offset
16531655
if next.isreg() or next.type not in SUPPORTED_TYPES:
16541656
try:
16551657
size = PAX_NUMBER_FIELDS["size"](pax_headers["size"])

‎Lib/test/test_bytes.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2098,6 +2098,22 @@ def g():
20982098
alloc = b.__alloc__()
20992099
self.assertGreater(alloc, len(b))
21002100

2101+
def test_init_from_iterator_with_offset(self):
2102+
# gh-158928: Inserting from an iterator in __init__ needs to take into
2103+
# account if there is a start offset.
2104+
b = bytearray()
2105+
def iterator_which_resets():
2106+
# __init__ reset ob_start. Make it an offset inside by allocating
2107+
# then doing fast prefix delete.
2108+
nonlocal b
2109+
b.resize(200)
2110+
del b[:100]
2111+
# Fill remaining already allocated space
2112+
yield from b'A' * 100
2113+
# Fill to end. Used to land out of bounds and crash.
2114+
b.__init__(iterator_which_resets())
2115+
self.assertEqual(b, bytes(100) + b'A' * 100)
2116+
21012117
def test_extend(self):
21022118
orig = b'hello'
21032119
a = bytearray(orig)

‎Lib/test/test_pydoc/test_pydoc.py‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,14 @@ def test_keywords(self):
22942294
self.assertEqual(sorted(pydoc.Helper.keywords),
22952295
sorted(keyword.kwlist + ['case', 'match', 'lazy']))
22962296

2297+
def test_symbols(self):
2298+
# gh-161414
2299+
for symbol in pydoc.Helper.symbols:
2300+
with self.subTest(symbol=symbol):
2301+
buf = StringIO()
2302+
pydoc.Helper(output=buf).showsymbol(symbol)
2303+
self.assertNotIn('no documentation found', buf.getvalue())
2304+
22972305
def test_interact_empty_line_continues(self):
22982306
# gh-138568: test pressing Enter without input should continue in help session
22992307
self.assertEqual(

‎Lib/test/test_tarfile.py‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1511,6 +1511,34 @@ def test_sparse_file_10_pax_size(self):
15111511
self.assertEqual(tar.getnames(), ["sparse", "last"])
15121512
self.assertEqual(tar.extractfile("last").read(), data)
15131513

1514+
def test_pax_size_with_gnu_longname(self):
1515+
# gh-159435: a GNU long-name header between a pax header and its
1516+
# member must not make the member header get read a second time.
1517+
long_name = "long-name-" * 12 + "file.txt"
1518+
1519+
def header(name, type, size):
1520+
info = tarfile.TarInfo(name)
1521+
info.type = type
1522+
info.size = size
1523+
return info.tobuf(tarfile.USTAR_FORMAT)
1524+
1525+
def padded(data):
1526+
return data + b"\0" * (-len(data) % tarfile.BLOCKSIZE)
1527+
1528+
pax_record = b"9 size=5\n"
1529+
buf = header("././@PaxHeader", tarfile.XHDTYPE, len(pax_record))
1530+
buf += padded(pax_record)
1531+
longname = long_name.encode() + b"\0"
1532+
buf += header("././@LongLink", tarfile.GNUTYPE_LONGNAME, len(longname))
1533+
buf += padded(longname)
1534+
buf += header("member-short", tarfile.REGTYPE, 5) + padded(b"hello")
1535+
buf += header("next.txt", tarfile.REGTYPE, 3) + padded(b"bye")
1536+
buf += b"\0" * (tarfile.BLOCKSIZE * 2)
1537+
1538+
with tarfile.open(fileobj=io.BytesIO(buf)) as tar:
1539+
self.assertEqual(tar.getnames(), [long_name, "next.txt"])
1540+
self.assertEqual(tar.extractfile("next.txt").read(), b"bye")
1541+
15141542
@staticmethod
15151543
def _fs_supports_holes():
15161544
# Return True if the platform knows the st_blocks stat attribute and
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix an offset calculation in :mod:`tarfile` when a PAX header with a ``size``
2+
record is followed by a GNU long-name header. Such archives could duplicate or
3+
skip members while being read.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove the backquote from the symbols listed by :func:`help`, asking for help on it reported that no
2+
documentation was found.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix a buffer overflow when initializing a :class:`bytearray` from an
2+
iterator.

‎Objects/bytearrayobject.c‎

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1156,17 +1156,26 @@ bytearray___init___impl(PyByteArrayObject *self, PyObject *arg,
11561156
/* Interpret it as an int (__index__) */
11571157
rc = _getbytevalue(item, &value);
11581158
Py_DECREF(item);
1159-
if (!rc)
1159+
if (!rc) {
11601160
goto error;
1161+
}
1162+
1163+
/* Append the byte.
11611164
1162-
/* Append the byte */
1163-
if (Py_SIZE(self) + 1 < self->ob_alloc) {
1165+
gh-158928: Iterators are arbitrary code which could modify the
1166+
bytearray so this must re-calculate if there is enough space(). */
1167+
Py_ssize_t needed =
1168+
self->ob_start - self->ob_bytes + Py_SIZE(self) + 1;
1169+
if (needed < self->ob_alloc) {
11641170
Py_SET_SIZE(self, Py_SIZE(self) + 1);
11651171
bytearray_write_trailing_null_byte(self);
11661172
}
1167-
else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0)
1173+
else if (PyByteArray_Resize((PyObject *)self, Py_SIZE(self)+1) < 0) {
11681174
goto error;
1175+
}
11691176
PyByteArray_AS_STRING(self)[Py_SIZE(self)-1] = value;
1177+
assert(self->ob_start - self->ob_bytes + Py_SIZE(self) <=
1178+
self->ob_alloc);
11701179
}
11711180

11721181
/* Clean up and return success */

0 commit comments

Comments
 (0)