Skip to content

Commit b94db0b

Browse files
authored
Merge branch 'main' into gh-148211/decompose-insert-1
2 parents edb4004 + 8c52450 commit b94db0b

File tree

11 files changed

+115
-4
lines changed

11 files changed

+115
-4
lines changed

.github/workflows/reusable-san.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ jobs:
6161
|| ''
6262
}}.txt handle_segv=0" >> "$GITHUB_ENV"
6363
else
64-
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION}" >> "$GITHUB_ENV"
64+
echo "UBSAN_OPTIONS=${SAN_LOG_OPTION} halt_on_error=1 suppressions=${GITHUB_WORKSPACE}/Tools/ubsan/suppressions.txt" >> "$GITHUB_ENV"
6565
fi
6666
echo "CC=clang" >> "$GITHUB_ENV"
6767
echo "CXX=clang++" >> "$GITHUB_ENV"
@@ -75,18 +75,21 @@ jobs:
7575
${{
7676
inputs.sanitizer == 'TSan'
7777
&& '--with-thread-sanitizer'
78-
|| '--with-undefined-behavior-sanitizer'
78+
|| '--with-undefined-behavior-sanitizer --with-strict-overflow'
7979
}}
8080
--with-pydebug
8181
${{ fromJSON(inputs.free-threading) && '--disable-gil' || '' }}
8282
- name: Build CPython
8383
run: make -j4
8484
- name: Display build info
8585
run: make pythoninfo
86+
# test_{capi,faulthandler} are skipped under UBSan because
87+
# they raise signals that UBSan with halt_on_error=1 intercepts.
8688
- name: Tests
8789
run: >-
8890
./python -m test
8991
${{ inputs.sanitizer == 'TSan' && '--tsan' || '' }}
92+
${{ inputs.sanitizer == 'UBSan' && '-x test_capi -x test_faulthandler' || '' }}
9093
-j4
9194
- name: Parallel tests
9295
if: >-

Doc/c-api/unicode.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1881,6 +1881,10 @@ object.
18811881
On success, return ``0``.
18821882
On error, set an exception, leave the writer unchanged, and return ``-1``.
18831883
1884+
To write a :class:`str` subclass which overrides the :meth:`~object.__str__`
1885+
method, :c:func:`PyUnicode_FromObject` can be used to get the original
1886+
string.
1887+
18841888
.. c:function:: int PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj)
18851889
18861890
Call :c:func:`PyObject_Repr` on *obj* and write the output into *writer*.

Doc/library/glob.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ The :mod:`!glob` module defines the following functions:
8383
This function may return duplicate path names if *pathname*
8484
contains multiple "``**``" patterns and *recursive* is true.
8585

86+
.. note::
87+
Any :exc:`OSError` exceptions raised from scanning the filesystem are
88+
suppressed. This includes :exc:`PermissionError` when accessing
89+
directories without read permission.
90+
8691
.. versionchanged:: 3.5
8792
Support for recursive globs using "``**``".
8893

@@ -106,6 +111,11 @@ The :mod:`!glob` module defines the following functions:
106111
This function may return duplicate path names if *pathname*
107112
contains multiple "``**``" patterns and *recursive* is true.
108113

114+
.. note::
115+
Any :exc:`OSError` exceptions raised from scanning the filesystem are
116+
suppressed. This includes :exc:`PermissionError` when accessing
117+
directories without read permission.
118+
109119
.. versionchanged:: 3.5
110120
Support for recursive globs using "``**``".
111121

Doc/library/pathlib.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,6 +1351,11 @@ Reading directories
13511351
``False``, this method follows symlinks except when expanding "``**``"
13521352
wildcards. Set *recurse_symlinks* to ``True`` to always follow symlinks.
13531353

1354+
.. note::
1355+
Any :exc:`OSError` exceptions raised from scanning the filesystem are
1356+
suppressed. This includes :exc:`PermissionError` when accessing
1357+
directories without read permission.
1358+
13541359
.. audit-event:: pathlib.Path.glob self,pattern pathlib.Path.glob
13551360

13561361
.. versionchanged:: 3.12
@@ -1377,6 +1382,11 @@ Reading directories
13771382
The paths are returned in no particular order.
13781383
If you need a specific order, sort the results.
13791384

1385+
.. note::
1386+
Any :exc:`OSError` exceptions raised from scanning the filesystem are
1387+
suppressed. This includes :exc:`PermissionError` when accessing
1388+
directories without read permission.
1389+
13801390
.. seealso::
13811391
:ref:`pathlib-pattern-language` and :meth:`Path.glob` documentation.
13821392

Lib/test/test_json/test_dump.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,36 @@ def __lt__(self, o):
7777
d[1337] = "true.dat"
7878
self.assertEqual(self.dumps(d, sort_keys=True), '{"1337": "true.dat"}')
7979

80+
def test_dumps_str_subclass(self):
81+
# Don't call obj.__str__() on str subclasses
82+
83+
# str subclass which returns a different string on str(obj)
84+
class StrSubclass(str):
85+
def __str__(self):
86+
return "StrSubclass"
87+
88+
obj = StrSubclass('ascii')
89+
self.assertEqual(self.dumps(obj), '"ascii"')
90+
self.assertEqual(self.dumps([obj]), '["ascii"]')
91+
self.assertEqual(self.dumps({'key': obj}), '{"key": "ascii"}')
92+
93+
obj = StrSubclass('escape\n')
94+
self.assertEqual(self.dumps(obj), '"escape\\n"')
95+
self.assertEqual(self.dumps([obj]), '["escape\\n"]')
96+
self.assertEqual(self.dumps({'key': obj}), '{"key": "escape\\n"}')
97+
98+
obj = StrSubclass('nonascii:é')
99+
self.assertEqual(self.dumps(obj, ensure_ascii=False),
100+
'"nonascii:é"')
101+
self.assertEqual(self.dumps([obj], ensure_ascii=False),
102+
'["nonascii:é"]')
103+
self.assertEqual(self.dumps({'key': obj}, ensure_ascii=False),
104+
'{"key": "nonascii:é"}')
105+
self.assertEqual(self.dumps(obj), '"nonascii:\\u00e9"')
106+
self.assertEqual(self.dumps([obj]), '["nonascii:\\u00e9"]')
107+
self.assertEqual(self.dumps({'key': obj}),
108+
'{"key": "nonascii:\\u00e9"}')
109+
80110

81111
class TestPyDump(TestDump, PyTest): pass
82112

Lib/test/test_json/test_encode_basestring_ascii.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
from test.support import bigaddrspacetest
44

55

6+
# str subclass which returns a different string on str(obj)
7+
class StrSubclass(str):
8+
def __str__(self):
9+
return "StrSubclass"
10+
611
CASES = [
712
('/\\"\ucafe\ubabe\uab98\ufcde\ubcda\uef4a\x08\x0c\n\r\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?', '"/\\\\\\"\\ucafe\\ubabe\\uab98\\ufcde\\ubcda\\uef4a\\b\\f\\n\\r\\t`1~!@#$%^&*()_+-=[]{}|;:\',./<>?"'),
813
('\u0123\u4567\u89ab\ucdef\uabcd\uef4a', '"\\u0123\\u4567\\u89ab\\ucdef\\uabcd\\uef4a"'),
@@ -14,6 +19,8 @@
1419
('\U0001d120', '"\\ud834\\udd20"'),
1520
('\u03b1\u03a9', '"\\u03b1\\u03a9"'),
1621
("`1~!@#$%^&*()_+-={':[,]}|;.</>?", '"`1~!@#$%^&*()_+-={\':[,]}|;.</>?"'),
22+
# Don't call obj.__str__() on str subclasses
23+
(StrSubclass('ascii'), '"ascii"'),
1724
]
1825

1926
class TestEncodeBasestringAscii:

Lib/test/test_json/test_enum.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ class WeirdNum(float, Enum):
3131
neg_inf = NEG_INF
3232
nan = NAN
3333

34+
class StringEnum(str, Enum):
35+
COLOR = "color"
36+
3437
class TestEnum:
3538

3639
def test_floats(self):
@@ -116,5 +119,11 @@ def test_dict_values(self):
116119
self.assertEqual(nd['j'], NEG_INF)
117120
self.assertTrue(isnan(nd['n']))
118121

122+
def test_str_enum(self):
123+
obj = StringEnum.COLOR
124+
self.assertEqual(self.dumps(obj), '"color"')
125+
self.assertEqual(self.dumps([obj]), '["color"]')
126+
self.assertEqual(self.dumps({'key': obj}), '{"key": "color"}')
127+
119128
class TestPyEnum(TestEnum, PyTest): pass
120129
class TestCEnum(TestEnum, CTest): pass
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Document that :func:`glob.glob`, :func:`glob.iglob`,
2+
:meth:`pathlib.Path.glob`, and :meth:`pathlib.Path.rglob` silently suppress
3+
:exc:`OSError` exceptions raised from scanning the filesystem.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`json`: Fix serialization: no longer call ``str(obj)`` on :class:`str`
2+
subclasses. Patch by Victor Stinner.

Modules/_json.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,10 @@ write_escaped_ascii(PyUnicodeWriter *writer, PyObject *pystr)
258258
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
259259
return -1;
260260
}
261-
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
261+
// gh-148241: Avoid PyUnicodeWriter_WriteStr() which calls str(obj)
262+
// on str subclasses
263+
assert(PyUnicode_IS_ASCII(pystr));
264+
if (PyUnicodeWriter_WriteASCII(writer, input, input_chars) < 0) {
262265
return -1;
263266
}
264267
return PyUnicodeWriter_WriteChar(writer, '"');
@@ -399,7 +402,9 @@ write_escaped_unicode(PyUnicodeWriter *writer, PyObject *pystr)
399402
if (PyUnicodeWriter_WriteChar(writer, '"') < 0) {
400403
return -1;
401404
}
402-
if (PyUnicodeWriter_WriteStr(writer, pystr) < 0) {
405+
// gh-148241: Avoid PyUnicodeWriter_WriteStr() which calls str(obj)
406+
// on str subclasses
407+
if (_PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, pystr) < 0) {
403408
return -1;
404409
}
405410
return PyUnicodeWriter_WriteChar(writer, '"');

0 commit comments

Comments
 (0)