Skip to content

Commit a0f596d

Browse files
authored
Merge branch 'main' into fix-doc-example
2 parents 09c7965 + 06b0920 commit a0f596d

File tree

15 files changed

+62
-9
lines changed

15 files changed

+62
-9
lines changed

Lib/test/test_decimal.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3963,15 +3963,21 @@ def test_flag_comparisons(self):
39633963
d.update(c.flags)
39643964
self.assertEqual(d, c.flags)
39653965
self.assertEqual(c.flags, d)
3966+
self.assertEqual(frozendict(d), c.flags)
3967+
self.assertEqual(c.flags, frozendict(d))
39663968

39673969
d[Inexact] = True
39683970
self.assertNotEqual(d, c.flags)
39693971
self.assertNotEqual(c.flags, d)
3972+
self.assertNotEqual(frozendict(d), c.flags)
3973+
self.assertNotEqual(c.flags, frozendict(d))
39703974

39713975
# Invalid SignalDict
39723976
d = {Inexact:False}
39733977
self.assertNotEqual(d, c.flags)
39743978
self.assertNotEqual(c.flags, d)
3979+
self.assertNotEqual(frozendict(d), c.flags)
3980+
self.assertNotEqual(c.flags, frozendict(d))
39753981

39763982
d = ["xyz"]
39773983
self.assertNotEqual(d, c.flags)

Lib/test/test_source_encoding.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,23 @@ def test_issue7820(self):
6565
# two bytes in common with the UTF-8 BOM
6666
self.assertRaises(SyntaxError, eval, b'\xef\xbb\x20')
6767

68+
def test_truncated_utf8_at_eof(self):
69+
# Regression test for https://issues.oss-fuzz.com/issues/451112368
70+
# Truncated multi-byte UTF-8 sequences at end of input caused an
71+
# out-of-bounds read in Parser/tokenizer/helpers.c:valid_utf8().
72+
truncated = [
73+
b'\xc2', # 2-byte lead, missing 1 continuation
74+
b'\xdf', # 2-byte lead, missing 1 continuation
75+
b'\xe0', # 3-byte lead, missing 2 continuations
76+
b'\xe0\xa0', # 3-byte lead, missing 1 continuation
77+
b'\xf0\x90', # 4-byte lead, missing 2 continuations
78+
b'\xf0\x90\x80', # 4-byte lead, missing 1 continuation
79+
b'\xf3', # 4-byte lead, missing 3 (the oss-fuzz reproducer)
80+
]
81+
for seq in truncated:
82+
with self.subTest(seq=seq):
83+
self.assertRaises(SyntaxError, compile, seq, '<test>', 'exec')
84+
6885
@support.requires_subprocess()
6986
def test_20731(self):
7087
sub = subprocess.Popen([sys.executable,

Lib/test/test_sqlite3/test_dbapi.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1379,6 +1379,11 @@ def test_blob_get_slice(self):
13791379
def test_blob_get_empty_slice(self):
13801380
self.assertEqual(self.blob[5:5], b"")
13811381

1382+
def test_blob_get_empty_slice_oob_indices(self):
1383+
self.cx.execute("insert into test(b) values (?)", (b"abc",))
1384+
with self.cx.blobopen("test", "b", 2) as blob:
1385+
self.assertEqual(blob[5:-5], b"")
1386+
13821387
def test_blob_get_slice_negative_index(self):
13831388
self.assertEqual(self.blob[5:-5], self.data[5:-5])
13841389

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix heap buffer overflow in the parser found by OSS-Fuzz.
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix assertion failure in :mod:`sqlite3` blob subscript when slicing with
2+
indices that result in an empty slice.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix crash in ``_remote_debugging`` that caused ``test_external_inspection`` to intermittently fail. Patch by Taegyun Kim.

Modules/_decimal/_decimal.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ dict_as_flags(decimal_state *state, PyObject *val)
552552
uint32_t flags = 0;
553553
int x;
554554

555-
if (!PyDict_Check(val)) {
555+
if (!PyAnyDict_Check(val)) {
556556
PyErr_SetString(PyExc_TypeError,
557557
"argument must be a signal dict");
558558
return DEC_INVALID_SIGNALS;
@@ -802,7 +802,7 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op)
802802
if (PyDecSignalDict_Check(state, w)) {
803803
res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False;
804804
}
805-
else if (PyDict_Check(w)) {
805+
else if (PyAnyDict_Check(w)) {
806806
uint32_t flags = dict_as_flags(state, w);
807807
if (flags & DEC_ERRORS) {
808808
if (flags & DEC_INVALID_SIGNALS) {

Modules/_remote_debugging/_remote_debugging.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern "C" {
2929
#include "internal/pycore_interpframe.h" // FRAME_OWNED_BY_INTERPRETER
3030
#include "internal/pycore_llist.h" // struct llist_node
3131
#include "internal/pycore_long.h" // _PyLong_GetZero
32+
#include "internal/pycore_pyerrors.h" // _PyErr_FormatFromCause
3233
#include "internal/pycore_stackref.h" // Py_TAG_BITS
3334
#include "../../Python/remote_debug.h"
3435

@@ -173,10 +174,13 @@ typedef enum _WIN32_THREADSTATE {
173174
#define THREAD_STATUS_HAS_EXCEPTION (1 << 4)
174175

175176
/* Exception cause macro */
176-
#define set_exception_cause(unwinder, exc_type, message) \
177-
if (unwinder->debug) { \
178-
_set_debug_exception_cause(exc_type, message); \
179-
}
177+
#define set_exception_cause(unwinder, exc_type, message) \
178+
do { \
179+
assert(PyErr_Occurred() && "function returned -1 without setting exception"); \
180+
if (unwinder->debug) { \
181+
_set_debug_exception_cause(exc_type, message); \
182+
} \
183+
} while (0)
180184

181185
/* ============================================================================
182186
* TYPE DEFINITIONS

Modules/_remote_debugging/asyncio.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ iterate_set_entries(
121121

122122
// Validate mask and num_els to prevent huge loop iterations from garbage data
123123
if (mask < 0 || mask >= MAX_SET_TABLE_SIZE || num_els < 0 || num_els > mask + 1) {
124+
PyErr_SetString(PyExc_RuntimeError, "Invalid set object (corrupted remote memory)");
124125
set_exception_cause(unwinder, PyExc_RuntimeError,
125126
"Invalid set object (corrupted remote memory)");
126127
return -1;

Modules/_remote_debugging/code_objects.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,9 @@ parse_code_object(RemoteUnwinderObject *unwinder,
446446
if (tlbc_entry) {
447447
// Validate index bounds (also catches negative values since tlbc_index is signed)
448448
if (ctx->tlbc_index < 0 || ctx->tlbc_index >= tlbc_entry->tlbc_array_size) {
449+
PyErr_Format(PyExc_RuntimeError,
450+
"Invalid tlbc_index %d (array size %zd, corrupted remote memory)",
451+
ctx->tlbc_index, tlbc_entry->tlbc_array_size);
449452
set_exception_cause(unwinder, PyExc_RuntimeError,
450453
"Invalid tlbc_index (corrupted remote memory)");
451454
goto error;

0 commit comments

Comments
 (0)