From 83c97d750eff498da3cd2dbc9fde163896ffaecc Mon Sep 17 00:00:00 2001 From: alperyoney Date: Wed, 10 Sep 2025 10:30:55 -0700 Subject: [PATCH 1/5] gh-116738: Make mmap module thread-safe --- Lib/test/test_free_threading/test_mmap.py | 315 ++++++++++++++++++ ...-09-21-14-33-17.gh-issue-116738.vNaI4h.rst | 2 + Modules/mmapmodule.c | 176 ++++++++-- 3 files changed, 465 insertions(+), 28 deletions(-) create mode 100644 Lib/test/test_free_threading/test_mmap.py create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-09-21-14-33-17.gh-issue-116738.vNaI4h.rst diff --git a/Lib/test/test_free_threading/test_mmap.py b/Lib/test/test_free_threading/test_mmap.py new file mode 100644 index 00000000000000..ece13d33f3b79b --- /dev/null +++ b/Lib/test/test_free_threading/test_mmap.py @@ -0,0 +1,315 @@ +import unittest + +from test.support import import_helper, threading_helper +from test.support.threading_helper import run_concurrently + +import os +import string +import tempfile +import threading + +from collections import Counter + +mmap = import_helper.import_module("mmap") + +NTHREADS = 10 +ANONYMOUS_MEM = -1 + + +@threading_helper.requires_working_threading() +class MmapTests(unittest.TestCase): + def test_read_and_read_byte(self): + ascii_uppercase = string.ascii_uppercase.encode() + # Choose a total mmap size that evenly divides across threads and the + # read pattern (3 bytes per loop). + mmap_size = 3 * NTHREADS * len(ascii_uppercase) + num_bytes_to_read_per_thread = mmap_size // NTHREADS + bytes_read_from_mmap = [] + + def read(mm_obj): + nread = 0 + while nread < num_bytes_to_read_per_thread: + b = mm_obj.read_byte() + bytes_read_from_mmap.append(b) + b = mm_obj.read(2) + bytes_read_from_mmap.extend(b) + nread += 3 + + with mmap.mmap(ANONYMOUS_MEM, mmap_size) as mm_obj: + for i in range(mmap_size // len(ascii_uppercase)): + mm_obj.write(ascii_uppercase) + + mm_obj.seek(0) + run_concurrently( + worker_func=read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(len(bytes_read_from_mmap), mmap_size) + # Count each letter/byte to verify read correctness + counter = Counter(bytes_read_from_mmap) + self.assertEqual(len(counter), len(ascii_uppercase)) + # Each letter/byte should be read (3 * NTHREADS) times + for letter in ascii_uppercase: + self.assertEqual(counter[letter], 3 * NTHREADS) + + def test_readline(self): + num_lines = 1000 + lines_read_from_mmap = [] + expected_lines = [] + + def readline(mm_obj): + for i in range(num_lines // NTHREADS): + line = mm_obj.readline() + lines_read_from_mmap.append(line) + + # Allocate mmap enough for num_lines (max line 5 bytes including NL) + with mmap.mmap(ANONYMOUS_MEM, num_lines * 5) as mm_obj: + for i in range(num_lines): + line = b"%d\n" % i + mm_obj.write(line) + expected_lines.append(line) + + mm_obj.seek(0) + run_concurrently( + worker_func=readline, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(len(lines_read_from_mmap), num_lines) + # Every line should be read once by threads; order is non-deterministic + # Sort numerically by integer value + lines_read_from_mmap.sort(key=lambda x: int(x)) + self.assertEqual(lines_read_from_mmap, expected_lines) + + def test_write_and_write_byte(self): + thread_letters = list(string.ascii_uppercase) + self.assertLessEqual(NTHREADS, len(thread_letters)) + per_thread_write_loop = 100 + + def write(mm_obj): + # Each thread picks a unique letter to write + thread_letter = thread_letters.pop(0) + thread_bytes = (thread_letter * 2).encode() + for _ in range(per_thread_write_loop): + mm_obj.write_byte(thread_bytes[0]) + mm_obj.write(thread_bytes) + + with mmap.mmap( + ANONYMOUS_MEM, per_thread_write_loop * 3 * NTHREADS + ) as mm_obj: + run_concurrently( + worker_func=write, + args=(mm_obj,), + nthreads=NTHREADS, + ) + mm_obj.seek(0) + data = mm_obj.read() + self.assertEqual(len(data), NTHREADS * per_thread_write_loop * 3) + counter = Counter(data) + self.assertEqual(len(counter), NTHREADS) + # Each thread letter should be written `per_thread_write_loop` * 3 + for letter in counter: + self.assertEqual(counter[letter], per_thread_write_loop * 3) + + def test_move(self): + ascii_uppercase = string.ascii_uppercase.encode() + num_letters = len(ascii_uppercase) + + def move(mm_obj): + for i in range(num_letters): + # Move 1 byte from the first half to the second half + mm_obj.move(0 + i, num_letters + i, 1) + + with mmap.mmap(ANONYMOUS_MEM, 2 * num_letters) as mm_obj: + mm_obj.write(ascii_uppercase) + run_concurrently( + worker_func=move, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_seek_and_tell(self): + seek_per_thread = 10 + + def seek(mm_obj): + self.assertTrue(mm_obj.seekable()) + for _ in range(seek_per_thread): + before_seek = mm_obj.tell() + mm_obj.seek(1, os.SEEK_CUR) + self.assertLess(before_seek, mm_obj.tell()) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=seek, + args=(mm_obj,), + nthreads=NTHREADS, + ) + # Each thread seeks from current position, the end position should + # be the sum of all seeks from all threads. + self.assertEqual(mm_obj.tell(), NTHREADS * seek_per_thread) + + def test_slice_update_and_slice_read(self): + thread_letters = list(string.ascii_uppercase) + self.assertLessEqual(NTHREADS, len(thread_letters)) + + def slice_update_and_slice_read(mm_obj): + # Each thread picks a unique letter to write + thread_letter = thread_letters.pop(0) + thread_bytes = (thread_letter * 1024).encode() + for _ in range(100): + mm_obj[:] = thread_bytes + read_bytes = mm_obj[:] + # Read bytes should be all the same letter, showing no + # interleaving + self.assertTrue(all_same(read_bytes)) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=slice_update_and_slice_read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_item_update_and_item_read(self): + thread_indexes = [i for i in range(NTHREADS)] + + def item_update_and_item_read(mm_obj): + # Each thread picks a unique index to write + thread_index = thread_indexes.pop() + for i in range(100): + mm_obj[thread_index] = i + self.assertEqual(mm_obj[thread_index], i) + + # Read values set by other threads, all values + # should be less than '100' + for val in mm_obj: + self.assertLess(int.from_bytes(val), 100) + + with mmap.mmap(ANONYMOUS_MEM, NTHREADS + 1) as mm_obj: + run_concurrently( + worker_func=item_update_and_item_read, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + @unittest.skipUnless(os.name == "posix", "requires Posix") + @unittest.skipUnless(hasattr(mmap.mmap, "resize"), "requires mmap.resize") + def test_resize_and_size(self): + thread_indexes = [i for i in range(NTHREADS)] + + def resize_and_item_update(mm_obj): + # Each thread picks a unique index to write + thread_index = thread_indexes.pop() + mm_obj.resize(2048) + self.assertEqual(mm_obj.size(), 2048) + for i in range(100): + mm_obj[thread_index] = i + self.assertEqual(mm_obj[thread_index], i) + + with mmap.mmap(ANONYMOUS_MEM, 1024, flags=mmap.MAP_PRIVATE) as mm_obj: + run_concurrently( + worker_func=resize_and_item_update, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_close_and_closed(self): + def close_mmap(mm_obj): + mm_obj.close() + self.assertTrue(mm_obj.closed) + + with mmap.mmap(ANONYMOUS_MEM, 1) as mm_obj: + run_concurrently( + worker_func=close_mmap, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + def test_find_and_rfind(self): + per_thread_loop = 10 + + def find_and_rfind(mm_obj): + pattern = b'Thread-Ident:"%d"' % threading.get_ident() + mm_obj.write(pattern) + for _ in range(per_thread_loop): + found_at = mm_obj.find(pattern, 0) + self.assertNotEqual(found_at, -1) + # Should not find it after the `found_at` + self.assertEqual(mm_obj.find(pattern, found_at + 1), -1) + found_at_rev = mm_obj.rfind(pattern, 0) + self.assertEqual(found_at, found_at_rev) + # Should not find it after the `found_at` + self.assertEqual(mm_obj.rfind(pattern, found_at + 1), -1) + + with mmap.mmap(ANONYMOUS_MEM, 1024) as mm_obj: + run_concurrently( + worker_func=find_and_rfind, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + @unittest.skipUnless(os.name == "posix", "requires Posix") + @unittest.skipUnless(hasattr(mmap.mmap, "resize"), "requires mmap.resize") + def test_flush(self): + mmap_filename = "test_mmap_file" + resize_to = 1024 + + def resize_and_flush(mm_obj): + mm_obj.resize(resize_to) + mm_obj.flush() + + with tempfile.TemporaryDirectory() as tmpdirname: + file_path = f"{tmpdirname}/{mmap_filename}" + with open(file_path, "wb+") as file: + file.write(b"CPython") + file.flush() + with mmap.mmap(file.fileno(), 1) as mm_obj: + run_concurrently( + worker_func=resize_and_flush, + args=(mm_obj,), + nthreads=NTHREADS, + ) + + self.assertEqual(os.path.getsize(file_path), resize_to) + + def test_mmap_export_as_memoryview(self): + """ + Each thread creates a memoryview and updates the internal state of the + mmap object. + """ + buffer_size = 42 + + def create_memoryview_from_mmap(mm_obj): + memoryviews = [] + for _ in range(100): + mv = memoryview(mm_obj) + memoryviews.append(mv) + self.assertEqual(len(mv), buffer_size) + self.assertEqual(mv[:7], b"CPython") + + # Cannot close the mmap while it is exported as buffers + with self.assertRaisesRegex( + BufferError, "cannot close exported pointers exist" + ): + mm_obj.close() + + with mmap.mmap(ANONYMOUS_MEM, 42) as mm_obj: + mm_obj.write(b"CPython") + run_concurrently( + worker_func=create_memoryview_from_mmap, + args=(mm_obj,), + nthreads=NTHREADS, + ) + # Implicit mm_obj.close() verifies all exports (memoryviews) are + # properly freed. + + +def all_same(lst): + return all(item == lst[0] for item in lst) + + +if __name__ == "__main__": + unittest.main() diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-09-21-14-33-17.gh-issue-116738.vNaI4h.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-21-14-33-17.gh-issue-116738.vNaI4h.rst new file mode 100644 index 00000000000000..0668d57604bc43 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-09-21-14-33-17.gh-issue-116738.vNaI4h.rst @@ -0,0 +1,2 @@ +Make :mod:`mmap` thread-safe on the :term:`free threaded ` +build. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8caadde8ae211b..edc5d6ddbe6ad3 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -91,6 +91,16 @@ my_getpagesize(void) # define MAP_ANONYMOUS MAP_ANON #endif +#define DEFINE_AND_FORWARD_TO_LOCK_HELD(fn_name) \ + static PyObject* fn_name(PyObject *op, PyObject *args) \ + { \ + PyObject *result = NULL; \ + Py_BEGIN_CRITICAL_SECTION(op); \ + result = fn_name##_lock_held(op, args); \ + Py_END_CRITICAL_SECTION(); \ + return result; \ + } + typedef enum { ACCESS_DEFAULT, @@ -166,7 +176,7 @@ mmap_object_dealloc(PyObject *op) } static PyObject * -mmap_close_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_close_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) { mmap_object *self = mmap_object_CAST(op); if (self->exports > 0) { @@ -218,6 +228,8 @@ mmap_close_method(PyObject *op, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_close_method); + #ifdef MS_WINDOWS #define CHECK_VALID(err) \ do { \ @@ -473,7 +485,7 @@ _safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) } static PyObject * -mmap_read_byte_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_read_byte_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -489,8 +501,10 @@ mmap_read_byte_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return PyLong_FromLong((unsigned char) dest); } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_byte_method); + static PyObject * -mmap_read_line_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_read_line_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) { Py_ssize_t remaining; char *start, *eol; @@ -519,8 +533,10 @@ mmap_read_line_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return result; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_line_method); + static PyObject * -mmap_read_method(PyObject *op, PyObject *args) +mmap_read_method_lock_held(PyObject *op, PyObject *args) { Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; mmap_object *self = mmap_object_CAST(op); @@ -543,11 +559,14 @@ mmap_read_method(PyObject *op, PyObject *args) return result; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_method); + static PyObject * -mmap_gfind(mmap_object *self, +mmap_gfind_lock_held(PyObject *op, PyObject *args, int reverse) { + mmap_object *self = mmap_object_CAST(op); Py_ssize_t start = self->pos; Py_ssize_t end = self->size; Py_buffer view; @@ -610,15 +629,21 @@ mmap_gfind(mmap_object *self, static PyObject * mmap_find_method(PyObject *op, PyObject *args) { - mmap_object *self = mmap_object_CAST(op); - return mmap_gfind(self, args, 0); + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_gfind_lock_held(op, args, 0); + Py_END_CRITICAL_SECTION(); + return result; } static PyObject * mmap_rfind_method(PyObject *op, PyObject *args) { - mmap_object *self = mmap_object_CAST(op); - return mmap_gfind(self, args, 1); + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_gfind_lock_held(op, args, 1); + Py_END_CRITICAL_SECTION(); + return result; } static int @@ -655,7 +680,7 @@ is_resizeable(mmap_object *self) static PyObject * -mmap_write_method(PyObject *op, PyObject *args) +mmap_write_method_lock_held(PyObject *op, PyObject *args) { Py_buffer data; mmap_object *self = mmap_object_CAST(op); @@ -688,8 +713,10 @@ mmap_write_method(PyObject *op, PyObject *args) return result; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_write_method); + static PyObject * -mmap_write_byte_method(PyObject *op, PyObject *args) +mmap_write_byte_method_lock_held(PyObject *op, PyObject *args) { char value; mmap_object *self = mmap_object_CAST(op); @@ -714,8 +741,10 @@ mmap_write_byte_method(PyObject *op, PyObject *args) Py_RETURN_NONE; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_write_byte_method); + static PyObject * -mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_size_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -761,6 +790,8 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) } } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_size_method); + /* This assumes that you want the entire file mapped, / and when recreating the map will make the new file / have the new size @@ -772,7 +803,7 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored)) #if defined(MS_WINDOWS) || defined(HAVE_MREMAP) static PyObject * -mmap_resize_method(PyObject *op, PyObject *args) +mmap_resize_method_lock_held(PyObject *op, PyObject *args) { Py_ssize_t new_size; mmap_object *self = mmap_object_CAST(op); @@ -919,18 +950,22 @@ mmap_resize_method(PyObject *op, PyObject *args) #endif /* UNIX */ } } + +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_resize_method); #endif /* MS_WINDOWS || HAVE_MREMAP */ static PyObject * -mmap_tell_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_tell_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); return PyLong_FromSize_t(self->pos); } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_tell_method); + static PyObject * -mmap_flush_method(PyObject *op, PyObject *args) +mmap_flush_method_lock_held(PyObject *op, PyObject *args) { Py_ssize_t offset = 0; mmap_object *self = mmap_object_CAST(op); @@ -965,8 +1000,10 @@ mmap_flush_method(PyObject *op, PyObject *args) #endif } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_flush_method); + static PyObject * -mmap_seek_method(PyObject *op, PyObject *args) +mmap_seek_method_lock_held(PyObject *op, PyObject *args) { Py_ssize_t dist; mmap_object *self = mmap_object_CAST(op); @@ -1005,6 +1042,8 @@ mmap_seek_method(PyObject *op, PyObject *args) return NULL; } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_seek_method); + static PyObject * mmap_seekable_method(PyObject *op, PyObject *Py_UNUSED(ignored)) { @@ -1012,7 +1051,7 @@ mmap_seekable_method(PyObject *op, PyObject *Py_UNUSED(ignored)) } static PyObject * -mmap_move_method(PyObject *op, PyObject *args) +mmap_move_method_lock_held(PyObject *op, PyObject *args) { Py_ssize_t dest, src, cnt; mmap_object *self = mmap_object_CAST(op); @@ -1040,15 +1079,21 @@ mmap_move_method(PyObject *op, PyObject *args) } } +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_move_method); + static PyObject * mmap_closed_get(PyObject *op, void *Py_UNUSED(closure)) { mmap_object *self = mmap_object_CAST(op); + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); #ifdef MS_WINDOWS - return PyBool_FromLong(self->map_handle == NULL ? 1 : 0); + result = PyBool_FromLong(self->map_handle == NULL ? 1 : 0); #elif defined(UNIX) - return PyBool_FromLong(self->data == NULL ? 1 : 0); + result = PyBool_FromLong(self->data == NULL ? 1 : 0); #endif + Py_END_CRITICAL_SECTION(); + return result; } static PyObject * @@ -1067,7 +1112,7 @@ mmap__exit__method(PyObject *op, PyObject *Py_UNUSED(args)) } static PyObject * -mmap__repr__method(PyObject *op) +mmap__repr__method_lock_held(PyObject *op) { mmap_object *mobj = mmap_object_CAST(op); @@ -1111,6 +1156,16 @@ mmap__repr__method(PyObject *op) } } +static PyObject * +mmap__repr__method(PyObject *op) +{ + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap__repr__method_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + #ifdef MS_WINDOWS static PyObject * mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) @@ -1126,7 +1181,7 @@ mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) #if defined(MS_WINDOWS) && defined(Py_DEBUG) static PyObject * -mmap_protect_method(PyObject *op, PyObject *args) { +mmap_protect_method_lock_held(PyObject *op, PyObject *args) { DWORD flNewProtect, flOldProtect; Py_ssize_t start, length; mmap_object *self = mmap_object_CAST(op); @@ -1146,11 +1201,13 @@ mmap_protect_method(PyObject *op, PyObject *args) { Py_RETURN_NONE; } + +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_protect_method); #endif #ifdef HAVE_MADVISE static PyObject * -mmap_madvise_method(PyObject *op, PyObject *args) +mmap_madvise_method_lock_held(PyObject *op, PyObject *args) { int option; Py_ssize_t start = 0, length; @@ -1188,6 +1245,8 @@ mmap_madvise_method(PyObject *op, PyObject *args) Py_RETURN_NONE; } + +DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_madvise_method); #endif // HAVE_MADVISE static struct PyMemberDef mmap_object_members[] = { @@ -1236,7 +1295,7 @@ static PyGetSetDef mmap_object_getset[] = { /* Functions for treating an mmap'ed file as a buffer */ static int -mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +mmap_buffer_getbuf_lock_held(PyObject *op, Py_buffer *view, int flags) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); @@ -1247,23 +1306,45 @@ mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) return 0; } +static int +mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) +{ + int result = -1; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_buffer_getbuf_lock_held(op, view, flags); + Py_END_CRITICAL_SECTION(); + return result; +} + static void mmap_buffer_releasebuf(PyObject *op, Py_buffer *Py_UNUSED(view)) { mmap_object *self = mmap_object_CAST(op); + Py_BEGIN_CRITICAL_SECTION(self); self->exports--; + Py_END_CRITICAL_SECTION(); } static Py_ssize_t -mmap_length(PyObject *op) +mmap_length_lock_held(PyObject *op) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); return self->size; } +static Py_ssize_t +mmap_length(PyObject *op) +{ + Py_ssize_t result = -1; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_length_lock_held(op); + Py_END_CRITICAL_SECTION(); + return result; +} + static PyObject * -mmap_item(PyObject *op, Py_ssize_t i) +mmap_item_lock_held(PyObject *op, Py_ssize_t i) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -1280,7 +1361,16 @@ mmap_item(PyObject *op, Py_ssize_t i) } static PyObject * -mmap_subscript(PyObject *op, PyObject *item) +mmap_item(PyObject *op, Py_ssize_t i) { + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_item_lock_held(op, i); + Py_END_CRITICAL_SECTION(); + return result; +} + +static PyObject * +mmap_subscript_lock_held(PyObject *op, PyObject *item) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -1342,8 +1432,18 @@ mmap_subscript(PyObject *op, PyObject *item) } } +static PyObject * +mmap_subscript(PyObject *op, PyObject *item) +{ + PyObject *result = NULL; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_subscript_lock_held(op, item); + Py_END_CRITICAL_SECTION(); + return result; +} + static int -mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) +mmap_ass_item_lock_held(PyObject *op, Py_ssize_t i, PyObject *v) { const char *buf; mmap_object *self = mmap_object_CAST(op); @@ -1374,7 +1474,17 @@ mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) } static int -mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) +mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) +{ + int result = -1; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_ass_item_lock_held(op, i, v); + Py_END_CRITICAL_SECTION(); + return result; +} + +static int +mmap_ass_subscript_lock_held(PyObject *op, PyObject *item, PyObject *value) { mmap_object *self = mmap_object_CAST(op); CHECK_VALID(-1); @@ -1470,6 +1580,16 @@ mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) } } +static int +mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) +{ + int result = -1; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_ass_subscript_lock_held(op, item, value); + Py_END_CRITICAL_SECTION(); + return result; +} + static PyObject * new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict); From e33497a0efc0a62e99fb5558529c8da6921771bf Mon Sep 17 00:00:00 2001 From: alperyoney Date: Wed, 1 Oct 2025 02:34:24 -0700 Subject: [PATCH 2/5] gh-116738: Convert the mmap module to use Argument Clinic --- Modules/clinic/mmapmodule.c.h | 650 ++++++++++++++++++++++++++++++++++ Modules/mmapmodule.c | 425 +++++++++++++--------- 2 files changed, 899 insertions(+), 176 deletions(-) create mode 100644 Modules/clinic/mmapmodule.c.h diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h new file mode 100644 index 00000000000000..add0d708c5fefb --- /dev/null +++ b/Modules/clinic/mmapmodule.c.h @@ -0,0 +1,650 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() +#include "pycore_tuple.h" // _PyTuple_FromArray() + +PyDoc_STRVAR(mmap_mmap_close__doc__, +"close($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_CLOSE_METHODDEF \ + {"close", (PyCFunction)mmap_mmap_close, METH_NOARGS, mmap_mmap_close__doc__}, + +static PyObject * +mmap_mmap_close_impl(mmap_object *self); + +static PyObject * +mmap_mmap_close(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_close_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_read_byte__doc__, +"read_byte($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READ_BYTE_METHODDEF \ + {"read_byte", (PyCFunction)mmap_mmap_read_byte, METH_NOARGS, mmap_mmap_read_byte__doc__}, + +static PyObject * +mmap_mmap_read_byte_impl(mmap_object *self); + +static PyObject * +mmap_mmap_read_byte(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_read_byte_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_readline__doc__, +"readline($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READLINE_METHODDEF \ + {"readline", (PyCFunction)mmap_mmap_readline, METH_NOARGS, mmap_mmap_readline__doc__}, + +static PyObject * +mmap_mmap_readline_impl(mmap_object *self); + +static PyObject * +mmap_mmap_readline(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_readline_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_read__doc__, +"read($self, n=None, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_READ_METHODDEF \ + {"read", _PyCFunction_CAST(mmap_mmap_read), METH_FASTCALL, mmap_mmap_read__doc__}, + +static PyObject * +mmap_mmap_read_impl(mmap_object *self, Py_ssize_t num_bytes); + +static PyObject * +mmap_mmap_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t num_bytes = PY_SSIZE_T_MAX; + + if (!_PyArg_CheckPositional("read", nargs, 0, 1)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + if (!_Py_convert_optional_to_ssize_t(args[0], &num_bytes)) { + goto exit; + } +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_read_impl((mmap_object *)self, num_bytes); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_find__doc__, +"find($self, /, *args)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_FIND_METHODDEF \ + {"find", _PyCFunction_CAST(mmap_mmap_find), METH_FASTCALL, mmap_mmap_find__doc__}, + +static PyObject * +mmap_mmap_find_impl(mmap_object *self, PyObject *args); + +static PyObject * +mmap_mmap_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_find_impl((mmap_object *)self, __clinic_args); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_rfind__doc__, +"rfind($self, /, *args)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_RFIND_METHODDEF \ + {"rfind", _PyCFunction_CAST(mmap_mmap_rfind), METH_FASTCALL, mmap_mmap_rfind__doc__}, + +static PyObject * +mmap_mmap_rfind_impl(mmap_object *self, PyObject *args); + +static PyObject * +mmap_mmap_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_rfind_impl((mmap_object *)self, __clinic_args); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_write__doc__, +"write($self, bytes, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_WRITE_METHODDEF \ + {"write", (PyCFunction)mmap_mmap_write, METH_O, mmap_mmap_write__doc__}, + +static PyObject * +mmap_mmap_write_impl(mmap_object *self, Py_buffer *data); + +static PyObject * +mmap_mmap_write(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_buffer data = {NULL, NULL}; + + if (PyObject_GetBuffer(arg, &data, PyBUF_SIMPLE) != 0) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_write_impl((mmap_object *)self, &data); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for data */ + if (data.obj) { + PyBuffer_Release(&data); + } + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_write_byte__doc__, +"write_byte($self, byte, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_WRITE_BYTE_METHODDEF \ + {"write_byte", (PyCFunction)mmap_mmap_write_byte, METH_O, mmap_mmap_write_byte__doc__}, + +static PyObject * +mmap_mmap_write_byte_impl(mmap_object *self, unsigned char value); + +static PyObject * +mmap_mmap_write_byte(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + unsigned char value; + + { + long ival = PyLong_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + else if (ival < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is less than minimum"); + goto exit; + } + else if (ival > UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is greater than maximum"); + goto exit; + } + else { + value = (unsigned char) ival; + } + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_write_byte_impl((mmap_object *)self, value); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_size__doc__, +"size($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SIZE_METHODDEF \ + {"size", (PyCFunction)mmap_mmap_size, METH_NOARGS, mmap_mmap_size__doc__}, + +static PyObject * +mmap_mmap_size_impl(mmap_object *self); + +static PyObject * +mmap_mmap_size(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_size_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#if (defined(MS_WINDOWS) || defined(HAVE_MREMAP)) + +PyDoc_STRVAR(mmap_mmap_resize__doc__, +"resize($self, newsize, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_RESIZE_METHODDEF \ + {"resize", (PyCFunction)mmap_mmap_resize, METH_O, mmap_mmap_resize__doc__}, + +static PyObject * +mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size); + +static PyObject * +mmap_mmap_resize(PyObject *self, PyObject *arg) +{ + PyObject *return_value = NULL; + Py_ssize_t new_size; + + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + new_size = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_resize_impl((mmap_object *)self, new_size); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#endif /* (defined(MS_WINDOWS) || defined(HAVE_MREMAP)) */ + +PyDoc_STRVAR(mmap_mmap_tell__doc__, +"tell($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_TELL_METHODDEF \ + {"tell", (PyCFunction)mmap_mmap_tell, METH_NOARGS, mmap_mmap_tell__doc__}, + +static PyObject * +mmap_mmap_tell_impl(mmap_object *self); + +static PyObject * +mmap_mmap_tell(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_tell_impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_flush__doc__, +"flush([offset, size])"); + +#define MMAP_MMAP_FLUSH_METHODDEF \ + {"flush", (PyCFunction)mmap_mmap_flush, METH_VARARGS, mmap_mmap_flush__doc__}, + +static PyObject * +mmap_mmap_flush_impl(mmap_object *self, int group_right_1, Py_ssize_t offset, + Py_ssize_t size); + +static PyObject * +mmap_mmap_flush(PyObject *self, PyObject *args) +{ + PyObject *return_value = NULL; + int group_right_1 = 0; + Py_ssize_t offset = 0; + Py_ssize_t size = 0; + + switch (PyTuple_GET_SIZE(args)) { + case 0: + break; + case 2: + if (!PyArg_ParseTuple(args, "nn:flush", &offset, &size)) { + goto exit; + } + group_right_1 = 1; + break; + default: + PyErr_SetString(PyExc_TypeError, "mmap.mmap.flush requires 0 to 2 arguments"); + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_flush_impl((mmap_object *)self, group_right_1, offset, size); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_seek__doc__, +"seek($self, pos, whence=0, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SEEK_METHODDEF \ + {"seek", _PyCFunction_CAST(mmap_mmap_seek), METH_FASTCALL, mmap_mmap_seek__doc__}, + +static PyObject * +mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how); + +static PyObject * +mmap_mmap_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t dist; + int how = 0; + + if (!_PyArg_CheckPositional("seek", nargs, 1, 2)) { + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + dist = ival; + } + if (nargs < 2) { + goto skip_optional; + } + how = PyLong_AsInt(args[1]); + if (how == -1 && PyErr_Occurred()) { + goto exit; + } +skip_optional: + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_seek_impl((mmap_object *)self, dist, how); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +PyDoc_STRVAR(mmap_mmap_move__doc__, +"move($self, dest, src, count, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_MOVE_METHODDEF \ + {"move", _PyCFunction_CAST(mmap_mmap_move), METH_FASTCALL, mmap_mmap_move__doc__}, + +static PyObject * +mmap_mmap_move_impl(mmap_object *self, Py_ssize_t dest, Py_ssize_t src, + Py_ssize_t cnt); + +static PyObject * +mmap_mmap_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t dest; + Py_ssize_t src; + Py_ssize_t cnt; + + if (!_PyArg_CheckPositional("move", nargs, 3, 3)) { + goto exit; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[0]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + dest = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + src = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + cnt = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_move_impl((mmap_object *)self, dest, src, cnt); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#if defined(MS_WINDOWS) + +PyDoc_STRVAR(mmap_mmap___sizeof____doc__, +"__sizeof__($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___SIZEOF___METHODDEF \ + {"__sizeof__", (PyCFunction)mmap_mmap___sizeof__, METH_NOARGS, mmap_mmap___sizeof____doc__}, + +static PyObject * +mmap_mmap___sizeof___impl(mmap_object *self); + +static PyObject * +mmap_mmap___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___sizeof___impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +#endif /* defined(MS_WINDOWS) */ + +#if (defined(MS_WINDOWS) && defined(Py_DEBUG)) + +PyDoc_STRVAR(mmap_mmap__protect__doc__, +"_protect($self, flNewProtect, start, end, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP__PROTECT_METHODDEF \ + {"_protect", _PyCFunction_CAST(mmap_mmap__protect), METH_FASTCALL, mmap_mmap__protect__doc__}, + +static PyObject * +mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, + Py_ssize_t start, Py_ssize_t end); + +static PyObject * +mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + unsigned int flNewProtect; + Py_ssize_t start; + Py_ssize_t end; + + if (!_PyArg_CheckPositional("_protect", nargs, 3, 3)) { + goto exit; + } + { + Py_ssize_t _bytes = PyLong_AsNativeBytes(args[0], &flNewProtect, sizeof(unsigned int), + Py_ASNATIVEBYTES_NATIVE_ENDIAN | + Py_ASNATIVEBYTES_ALLOW_INDEX | + Py_ASNATIVEBYTES_UNSIGNED_BUFFER); + if (_bytes < 0) { + goto exit; + } + if ((size_t)_bytes > sizeof(unsigned int)) { + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "integer value out of range", 1) < 0) + { + goto exit; + } + } + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + start = ival; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[2]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + end = ival; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap__protect_impl((mmap_object *)self, flNewProtect, start, end); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + +#endif /* (defined(MS_WINDOWS) && defined(Py_DEBUG)) */ + +#if defined(HAVE_MADVISE) + +PyDoc_STRVAR(mmap_mmap_madvise__doc__, +"madvise($self, /, *args)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_MADVISE_METHODDEF \ + {"madvise", _PyCFunction_CAST(mmap_mmap_madvise), METH_FASTCALL, mmap_mmap_madvise__doc__}, + +static PyObject * +mmap_mmap_madvise_impl(mmap_object *self, PyObject *args); + +static PyObject * +mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *__clinic_args = NULL; + + __clinic_args = _PyTuple_FromArray(args, nargs); + if (__clinic_args == NULL) { + goto exit; + } + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap_madvise_impl((mmap_object *)self, __clinic_args); + Py_END_CRITICAL_SECTION(); + +exit: + /* Cleanup for args */ + Py_XDECREF(__clinic_args); + + return return_value; +} + +#endif /* defined(HAVE_MADVISE) */ + +#ifndef MMAP_MMAP_RESIZE_METHODDEF + #define MMAP_MMAP_RESIZE_METHODDEF +#endif /* !defined(MMAP_MMAP_RESIZE_METHODDEF) */ + +#ifndef MMAP_MMAP___SIZEOF___METHODDEF + #define MMAP_MMAP___SIZEOF___METHODDEF +#endif /* !defined(MMAP_MMAP___SIZEOF___METHODDEF) */ + +#ifndef MMAP_MMAP__PROTECT_METHODDEF + #define MMAP_MMAP__PROTECT_METHODDEF +#endif /* !defined(MMAP_MMAP__PROTECT_METHODDEF) */ + +#ifndef MMAP_MMAP_MADVISE_METHODDEF + #define MMAP_MMAP_MADVISE_METHODDEF +#endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ +/*[clinic end generated code: output=712475834981dd16 input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index edc5d6ddbe6ad3..9926e0c2428854 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -91,15 +91,11 @@ my_getpagesize(void) # define MAP_ANONYMOUS MAP_ANON #endif -#define DEFINE_AND_FORWARD_TO_LOCK_HELD(fn_name) \ - static PyObject* fn_name(PyObject *op, PyObject *args) \ - { \ - PyObject *result = NULL; \ - Py_BEGIN_CRITICAL_SECTION(op); \ - result = fn_name##_lock_held(op, args); \ - Py_END_CRITICAL_SECTION(); \ - return result; \ - } +/*[clinic input] +module mmap +class mmap.mmap "mmap_object *" "" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=82a9f8a529905b9b]*/ typedef enum { @@ -139,6 +135,8 @@ typedef struct { #define mmap_object_CAST(op) ((mmap_object *)(op)) +#include "clinic/mmapmodule.c.h" + static void mmap_object_dealloc(PyObject *op) { @@ -175,10 +173,16 @@ mmap_object_dealloc(PyObject *op) Py_DECREF(tp); } +/*[clinic input] +@critical_section +mmap.mmap.close + +[clinic start generated code]*/ + static PyObject * -mmap_close_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_close_impl(mmap_object *self) +/*[clinic end generated code: output=a1ae0c727546f78d input=25020035f047eae1]*/ { - mmap_object *self = mmap_object_CAST(op); if (self->exports > 0) { PyErr_SetString(PyExc_BufferError, "cannot close "\ "exported pointers exist"); @@ -228,8 +232,6 @@ mmap_close_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) Py_RETURN_NONE; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_close_method); - #ifdef MS_WINDOWS #define CHECK_VALID(err) \ do { \ @@ -484,10 +486,16 @@ _safe_PyBytes_FromStringAndSize(char *start, size_t num_bytes) } } +/*[clinic input] +@critical_section +mmap.mmap.read_byte + +[clinic start generated code]*/ + static PyObject * -mmap_read_byte_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_read_byte_impl(mmap_object *self) +/*[clinic end generated code: output=d931da1319f3869b input=5b8c6a904bdddda9]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); if (self->pos >= self->size) { PyErr_SetString(PyExc_ValueError, "read byte out of range"); @@ -501,14 +509,18 @@ mmap_read_byte_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) return PyLong_FromLong((unsigned char) dest); } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_byte_method); +/*[clinic input] +@critical_section +mmap.mmap.readline + +[clinic start generated code]*/ static PyObject * -mmap_read_line_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_readline_impl(mmap_object *self) +/*[clinic end generated code: output=b9d2bf9999283311 input=2c4efd1d06e1cdd1]*/ { Py_ssize_t remaining; char *start, *eol; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); @@ -533,18 +545,22 @@ mmap_read_line_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) return result; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_line_method); +/*[clinic input] +@critical_section +mmap.mmap.read + + n as num_bytes: object(converter='_Py_convert_optional_to_ssize_t', type='Py_ssize_t', c_default='PY_SSIZE_T_MAX') = None + / + +[clinic start generated code]*/ static PyObject * -mmap_read_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_read_impl(mmap_object *self, Py_ssize_t num_bytes) +/*[clinic end generated code: output=3b4d4f3704ed0969 input=8f97f361d435e357]*/ { - Py_ssize_t num_bytes = PY_SSIZE_T_MAX, remaining; - mmap_object *self = mmap_object_CAST(op); + Py_ssize_t remaining; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|O&:read", _Py_convert_optional_to_ssize_t, &num_bytes)) - return NULL; - CHECK_VALID(NULL); /* silently 'adjust' out-of-range requests */ remaining = (self->pos < self->size) ? self->size - self->pos : 0; @@ -559,14 +575,9 @@ mmap_read_method_lock_held(PyObject *op, PyObject *args) return result; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_read_method); - static PyObject * -mmap_gfind_lock_held(PyObject *op, - PyObject *args, - int reverse) +mmap_gfind_lock_held(mmap_object *self, PyObject *args, int reverse) { - mmap_object *self = mmap_object_CAST(op); Py_ssize_t start = self->pos; Py_ssize_t end = self->size; Py_buffer view; @@ -626,24 +637,34 @@ mmap_gfind_lock_held(PyObject *op, } } +/*[clinic input] +@critical_section +mmap.mmap.find + + *args: tuple + +[clinic start generated code]*/ + static PyObject * -mmap_find_method(PyObject *op, PyObject *args) +mmap_mmap_find_impl(mmap_object *self, PyObject *args) +/*[clinic end generated code: output=6e0dfd51873d7263 input=dc56119de60c458f]*/ { - PyObject *result = NULL; - Py_BEGIN_CRITICAL_SECTION(op); - result = mmap_gfind_lock_held(op, args, 0); - Py_END_CRITICAL_SECTION(); - return result; + return mmap_gfind_lock_held(self, args, 0); } +/*[clinic input] +@critical_section +mmap.mmap.rfind + + *args: tuple + +[clinic start generated code]*/ + static PyObject * -mmap_rfind_method(PyObject *op, PyObject *args) +mmap_mmap_rfind_impl(mmap_object *self, PyObject *args) +/*[clinic end generated code: output=a8dbff2d7090cf2c input=ab496c4db0a37948]*/ { - PyObject *result = NULL; - Py_BEGIN_CRITICAL_SECTION(op); - result = mmap_gfind_lock_held(op, args, 1); - Py_END_CRITICAL_SECTION(); - return result; + return mmap_gfind_lock_held(self, args, 1); } static int @@ -679,52 +700,55 @@ is_resizeable(mmap_object *self) #endif /* MS_WINDOWS || HAVE_MREMAP */ +/*[clinic input] +@critical_section +mmap.mmap.write + + bytes as data: Py_buffer + / + +[clinic start generated code]*/ + static PyObject * -mmap_write_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_write_impl(mmap_object *self, Py_buffer *data) +/*[clinic end generated code: output=9e97063efb6fb27b input=3f16fa79aa89d6f7]*/ { - Py_buffer data; - mmap_object *self = mmap_object_CAST(op); - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "y*:write", &data)) - return NULL; - if (!is_writable(self)) { - PyBuffer_Release(&data); return NULL; } - if (self->pos > self->size || self->size - self->pos < data.len) { - PyBuffer_Release(&data); + if (self->pos > self->size || self->size - self->pos < data->len) { PyErr_SetString(PyExc_ValueError, "data out of range"); return NULL; } - CHECK_VALID_OR_RELEASE(NULL, data); + CHECK_VALID(NULL); PyObject *result; - if (safe_memcpy(self->data + self->pos, data.buf, data.len) < 0) { + if (safe_memcpy(self->data + self->pos, data->buf, data->len) < 0) { result = NULL; } else { - self->pos += data.len; - result = PyLong_FromSsize_t(data.len); + self->pos += data->len; + result = PyLong_FromSsize_t(data->len); } - PyBuffer_Release(&data); return result; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_write_method); +/*[clinic input] +@critical_section +mmap.mmap.write_byte + + byte as value: unsigned_char + / + +[clinic start generated code]*/ static PyObject * -mmap_write_byte_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_write_byte_impl(mmap_object *self, unsigned char value) +/*[clinic end generated code: output=aa11adada9b17510 input=32740bfa174f0991]*/ { - char value; - mmap_object *self = mmap_object_CAST(op); - CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "b:write_byte", &value)) - return(NULL); - if (!is_writable(self)) return NULL; @@ -734,19 +758,23 @@ mmap_write_byte_method_lock_held(PyObject *op, PyObject *args) return NULL; } - if (safe_byte_copy(self->data + self->pos, &value) < 0) { + if (safe_byte_copy(self->data + self->pos, (const char*)&value) < 0) { return NULL; } self->pos++; Py_RETURN_NONE; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_write_byte_method); +/*[clinic input] +@critical_section +mmap.mmap.size + +[clinic start generated code]*/ static PyObject * -mmap_size_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_size_impl(mmap_object *self) +/*[clinic end generated code: output=c177e65e83a648ff input=f69c072efd2e1595]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); #ifdef MS_WINDOWS @@ -790,8 +818,6 @@ mmap_size_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) } } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_size_method); - /* This assumes that you want the entire file mapped, / and when recreating the map will make the new file / have the new size @@ -802,14 +828,21 @@ DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_size_method); */ #if defined(MS_WINDOWS) || defined(HAVE_MREMAP) +/*[clinic input] +@critical_section +mmap.mmap.resize + + newsize as new_size: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -mmap_resize_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_resize_impl(mmap_object *self, Py_ssize_t new_size) +/*[clinic end generated code: output=6f262537ce9c2dcc input=b6b5dee52a41b79f]*/ { - Py_ssize_t new_size; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n:resize", &new_size) || - !is_resizeable(self)) { + if (!is_resizeable(self)) { return NULL; } if (new_size < 0 || PY_SSIZE_T_MAX - new_size < self->offset) { @@ -950,29 +983,45 @@ mmap_resize_method_lock_held(PyObject *op, PyObject *args) #endif /* UNIX */ } } - -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_resize_method); #endif /* MS_WINDOWS || HAVE_MREMAP */ +/*[clinic input] +@critical_section +mmap.mmap.tell + +[clinic start generated code]*/ + static PyObject * -mmap_tell_method_lock_held(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_tell_impl(mmap_object *self) +/*[clinic end generated code: output=6034958630e1b1d1 input=fd163acacf45c3a5]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); return PyLong_FromSize_t(self->pos); } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_tell_method); +/*[clinic input] +@critical_section +mmap.mmap.flush + + [ + offset: Py_ssize_t + size: Py_ssize_t + ] + / + +[clinic start generated code]*/ static PyObject * -mmap_flush_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_flush_impl(mmap_object *self, int group_right_1, Py_ssize_t offset, + Py_ssize_t size) +/*[clinic end generated code: output=ddf491da85fe48dc input=5d80ec527a2b1137]*/ { - Py_ssize_t offset = 0; - mmap_object *self = mmap_object_CAST(op); - Py_ssize_t size = self->size; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "|nn:flush", &offset, &size)) - return NULL; + if (group_right_1 == 0) { + offset = 0; + size = self->size; + } + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; @@ -1000,64 +1049,74 @@ mmap_flush_method_lock_held(PyObject *op, PyObject *args) #endif } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_flush_method); +/*[clinic input] +@critical_section +mmap.mmap.seek + + pos as dist: Py_ssize_t + whence as how: int = 0 + / + +[clinic start generated code]*/ static PyObject * -mmap_seek_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how) +/*[clinic end generated code: output=00310494e8b8c592 input=e2fda5d081c3db22]*/ { - Py_ssize_t dist; - mmap_object *self = mmap_object_CAST(op); - int how=0; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "n|i:seek", &dist, &how)) - return NULL; - else { - Py_ssize_t where; - switch (how) { - case 0: /* relative to start */ - where = dist; - break; - case 1: /* relative to current position */ - if (PY_SSIZE_T_MAX - self->pos < dist) - goto onoutofrange; - where = self->pos + dist; - break; - case 2: /* relative to end */ - if (PY_SSIZE_T_MAX - self->size < dist) - goto onoutofrange; - where = self->size + dist; - break; - default: - PyErr_SetString(PyExc_ValueError, "unknown seek type"); - return NULL; - } - if (where > self->size || where < 0) + Py_ssize_t where; + switch (how) { + case 0: /* relative to start */ + where = dist; + break; + case 1: /* relative to current position */ + if (PY_SSIZE_T_MAX - self->pos < dist) + goto onoutofrange; + where = self->pos + dist; + break; + case 2: /* relative to end */ + if (PY_SSIZE_T_MAX - self->size < dist) goto onoutofrange; - self->pos = where; - return PyLong_FromSsize_t(self->pos); + where = self->size + dist; + break; + default: + PyErr_SetString(PyExc_ValueError, "unknown seek type"); + return NULL; } + if (where > self->size || where < 0) + goto onoutofrange; + self->pos = where; + return PyLong_FromSsize_t(self->pos); onoutofrange: PyErr_SetString(PyExc_ValueError, "seek out of range"); return NULL; } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_seek_method); - static PyObject * mmap_seekable_method(PyObject *op, PyObject *Py_UNUSED(ignored)) { Py_RETURN_TRUE; } +/*[clinic input] +@critical_section +mmap.mmap.move + + dest: Py_ssize_t + src: Py_ssize_t + count as cnt: Py_ssize_t + / + +[clinic start generated code]*/ + static PyObject * -mmap_move_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_move_impl(mmap_object *self, Py_ssize_t dest, Py_ssize_t src, + Py_ssize_t cnt) +/*[clinic end generated code: output=391f549a44181793 input=cf8cfe10d9f6b448]*/ { - Py_ssize_t dest, src, cnt; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "nnn:move", &dest, &src, &cnt) || - !is_writable(self)) { + if (!is_writable(self)) { return NULL; } else { /* bounds check the values */ @@ -1079,13 +1138,11 @@ mmap_move_method_lock_held(PyObject *op, PyObject *args) } } -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_move_method); - static PyObject * mmap_closed_get(PyObject *op, void *Py_UNUSED(closure)) { mmap_object *self = mmap_object_CAST(op); - PyObject *result = NULL; + PyObject *result; Py_BEGIN_CRITICAL_SECTION(op); #ifdef MS_WINDOWS result = PyBool_FromLong(self->map_handle == NULL ? 1 : 0); @@ -1108,7 +1165,12 @@ mmap__enter__method(PyObject *op, PyObject *Py_UNUSED(ignored)) static PyObject * mmap__exit__method(PyObject *op, PyObject *Py_UNUSED(args)) { - return mmap_close_method(op, NULL); + mmap_object *self = mmap_object_CAST(op); + PyObject *result; + Py_BEGIN_CRITICAL_SECTION(op); + result = mmap_mmap_close_impl(self); + Py_END_CRITICAL_SECTION(); + return result; } static PyObject * @@ -1159,7 +1221,7 @@ mmap__repr__method_lock_held(PyObject *op) static PyObject * mmap__repr__method(PyObject *op) { - PyObject *result = NULL; + PyObject *result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap__repr__method_lock_held(op); Py_END_CRITICAL_SECTION(); @@ -1167,10 +1229,16 @@ mmap__repr__method(PyObject *op) } #ifdef MS_WINDOWS +/*[clinic input] +@critical_section +mmap.mmap.__sizeof__ + +[clinic start generated code]*/ + static PyObject * -mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) +mmap_mmap___sizeof___impl(mmap_object *self) +/*[clinic end generated code: output=1aed30daff807d09 input=8a648868a089553c]*/ { - mmap_object *self = mmap_object_CAST(op); size_t res = _PyObject_SIZE(Py_TYPE(self)); if (self->tagname) { res += (wcslen(self->tagname) + 1) * sizeof(self->tagname[0]); @@ -1180,18 +1248,27 @@ mmap__sizeof__method(PyObject *op, PyObject *Py_UNUSED(dummy)) #endif #if defined(MS_WINDOWS) && defined(Py_DEBUG) +/*[clinic input] +@critical_section +mmap.mmap._protect + + flNewProtect: unsigned_int(bitwise=True) + start: Py_ssize_t + end: Py_ssize_t + / + +[clinic start generated code]*/ + +static PyObject * +mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, + Py_ssize_t start, Py_ssize_t end) +/*[clinic end generated code: output=126138a77e74e532 input=85b4fe22b2bf086f]*/ static PyObject * mmap_protect_method_lock_held(PyObject *op, PyObject *args) { - DWORD flNewProtect, flOldProtect; - Py_ssize_t start, length; - mmap_object *self = mmap_object_CAST(op); + DWORD flOldProtect; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, "Inn:protect", &flNewProtect, &start, &length)) { - return NULL; - } - if (!VirtualProtect((void *) (self->data + start), length, flNewProtect, &flOldProtect)) { @@ -1201,17 +1278,23 @@ mmap_protect_method_lock_held(PyObject *op, PyObject *args) { Py_RETURN_NONE; } - -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_protect_method); #endif #ifdef HAVE_MADVISE +/*[clinic input] +@critical_section +mmap.mmap.madvise + + *args: tuple + +[clinic start generated code]*/ + static PyObject * -mmap_madvise_method_lock_held(PyObject *op, PyObject *args) +mmap_mmap_madvise_impl(mmap_object *self, PyObject *args) +/*[clinic end generated code: output=237b3c0176f65b4f input=14e3ccbd25a38f22]*/ { int option; Py_ssize_t start = 0, length; - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); length = self->size; @@ -1245,8 +1328,6 @@ mmap_madvise_method_lock_held(PyObject *op, PyObject *args) Py_RETURN_NONE; } - -DEFINE_AND_FORWARD_TO_LOCK_HELD(mmap_madvise_method); #endif // HAVE_MADVISE static struct PyMemberDef mmap_object_members[] = { @@ -1255,34 +1336,26 @@ static struct PyMemberDef mmap_object_members[] = { }; static struct PyMethodDef mmap_object_methods[] = { - {"close", mmap_close_method, METH_NOARGS}, - {"find", mmap_find_method, METH_VARARGS}, - {"rfind", mmap_rfind_method, METH_VARARGS}, - {"flush", mmap_flush_method, METH_VARARGS}, -#ifdef HAVE_MADVISE - {"madvise", mmap_madvise_method, METH_VARARGS}, -#endif - {"move", mmap_move_method, METH_VARARGS}, - {"read", mmap_read_method, METH_VARARGS}, - {"read_byte", mmap_read_byte_method, METH_NOARGS}, - {"readline", mmap_read_line_method, METH_NOARGS}, -#if defined(MS_WINDOWS) || defined(HAVE_MREMAP) - {"resize", mmap_resize_method, METH_VARARGS}, -#endif - {"seek", mmap_seek_method, METH_VARARGS}, + MMAP_MMAP_CLOSE_METHODDEF + MMAP_MMAP_FIND_METHODDEF + MMAP_MMAP_RFIND_METHODDEF + MMAP_MMAP_FLUSH_METHODDEF + MMAP_MMAP_MADVISE_METHODDEF + MMAP_MMAP_MOVE_METHODDEF + MMAP_MMAP_READ_METHODDEF + MMAP_MMAP_READ_BYTE_METHODDEF + MMAP_MMAP_READLINE_METHODDEF + MMAP_MMAP_RESIZE_METHODDEF + MMAP_MMAP_SEEK_METHODDEF {"seekable", mmap_seekable_method, METH_NOARGS}, - {"size", mmap_size_method, METH_NOARGS}, - {"tell", mmap_tell_method, METH_NOARGS}, - {"write", mmap_write_method, METH_VARARGS}, - {"write_byte", mmap_write_byte_method, METH_VARARGS}, + MMAP_MMAP_SIZE_METHODDEF + MMAP_MMAP_TELL_METHODDEF + MMAP_MMAP_WRITE_METHODDEF + MMAP_MMAP_WRITE_BYTE_METHODDEF {"__enter__", mmap__enter__method, METH_NOARGS}, {"__exit__", mmap__exit__method, METH_VARARGS}, -#ifdef MS_WINDOWS - {"__sizeof__", mmap__sizeof__method, METH_NOARGS}, -#ifdef Py_DEBUG - {"_protect", mmap_protect_method, METH_VARARGS}, -#endif // Py_DEBUG -#endif // MS_WINDOWS + MMAP_MMAP___SIZEOF___METHODDEF + MMAP_MMAP__PROTECT_METHODDEF {NULL, NULL} /* sentinel */ }; @@ -1309,7 +1382,7 @@ mmap_buffer_getbuf_lock_held(PyObject *op, Py_buffer *view, int flags) static int mmap_buffer_getbuf(PyObject *op, Py_buffer *view, int flags) { - int result = -1; + int result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_buffer_getbuf_lock_held(op, view, flags); Py_END_CRITICAL_SECTION(); @@ -1336,7 +1409,7 @@ mmap_length_lock_held(PyObject *op) static Py_ssize_t mmap_length(PyObject *op) { - Py_ssize_t result = -1; + Py_ssize_t result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_length_lock_held(op); Py_END_CRITICAL_SECTION(); @@ -1362,7 +1435,7 @@ mmap_item_lock_held(PyObject *op, Py_ssize_t i) static PyObject * mmap_item(PyObject *op, Py_ssize_t i) { - PyObject *result = NULL; + PyObject *result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_item_lock_held(op, i); Py_END_CRITICAL_SECTION(); @@ -1435,7 +1508,7 @@ mmap_subscript_lock_held(PyObject *op, PyObject *item) static PyObject * mmap_subscript(PyObject *op, PyObject *item) { - PyObject *result = NULL; + PyObject *result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_subscript_lock_held(op, item); Py_END_CRITICAL_SECTION(); @@ -1476,7 +1549,7 @@ mmap_ass_item_lock_held(PyObject *op, Py_ssize_t i, PyObject *v) static int mmap_ass_item(PyObject *op, Py_ssize_t i, PyObject *v) { - int result = -1; + int result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_ass_item_lock_held(op, i, v); Py_END_CRITICAL_SECTION(); @@ -1583,7 +1656,7 @@ mmap_ass_subscript_lock_held(PyObject *op, PyObject *item, PyObject *value) static int mmap_ass_subscript(PyObject *op, PyObject *item, PyObject *value) { - int result = -1; + int result; Py_BEGIN_CRITICAL_SECTION(op); result = mmap_ass_subscript_lock_held(op, item, value); Py_END_CRITICAL_SECTION(); From c80e8ba2ff53c152f34fb54d9749185ba728a577 Mon Sep 17 00:00:00 2001 From: alperyoney Date: Wed, 1 Oct 2025 10:31:22 -0700 Subject: [PATCH 3/5] gh-116738: Fix Windows build --- Modules/clinic/mmapmodule.c.h | 12 ++++++------ Modules/mmapmodule.c | 9 ++++----- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h index 119bab342982b3..ecc60b2fbaf539 100644 --- a/Modules/clinic/mmapmodule.c.h +++ b/Modules/clinic/mmapmodule.c.h @@ -545,7 +545,7 @@ mmap_mmap___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored)) #if (defined(MS_WINDOWS) && defined(Py_DEBUG)) PyDoc_STRVAR(mmap_mmap__protect__doc__, -"_protect($self, flNewProtect, start, end, /)\n" +"_protect($self, flNewProtect, start, length, /)\n" "--\n" "\n"); @@ -554,7 +554,7 @@ PyDoc_STRVAR(mmap_mmap__protect__doc__, static PyObject * mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, - Py_ssize_t start, Py_ssize_t end); + Py_ssize_t start, Py_ssize_t length); static PyObject * mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) @@ -562,7 +562,7 @@ mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) PyObject *return_value = NULL; unsigned int flNewProtect; Py_ssize_t start; - Py_ssize_t end; + Py_ssize_t length; if (!_PyArg_CheckPositional("_protect", nargs, 3, 3)) { goto exit; @@ -605,10 +605,10 @@ mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) if (ival == -1 && PyErr_Occurred()) { goto exit; } - end = ival; + length = ival; } Py_BEGIN_CRITICAL_SECTION(self); - return_value = mmap_mmap__protect_impl((mmap_object *)self, flNewProtect, start, end); + return_value = mmap_mmap__protect_impl((mmap_object *)self, flNewProtect, start, length); Py_END_CRITICAL_SECTION(); exit: @@ -668,4 +668,4 @@ mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #ifndef MMAP_MMAP_MADVISE_METHODDEF #define MMAP_MMAP_MADVISE_METHODDEF #endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ -/*[clinic end generated code: output=6af04d6644f6dfb0 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f2bbd1cba452c773 input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 34f906e19134fe..8937b4e4080460 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1249,17 +1249,16 @@ mmap.mmap._protect flNewProtect: unsigned_int(bitwise=True) start: Py_ssize_t - end: Py_ssize_t + length: Py_ssize_t / [clinic start generated code]*/ static PyObject * mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, - Py_ssize_t start, Py_ssize_t end) -/*[clinic end generated code: output=126138a77e74e532 input=85b4fe22b2bf086f]*/ -static PyObject * -mmap_protect_method_lock_held(PyObject *op, PyObject *args) { + Py_ssize_t start, Py_ssize_t length) +/*[clinic end generated code: output=a87271a34d1ad6cf input=9170498c5e1482da]*/ +{ DWORD flOldProtect; CHECK_VALID(NULL); From e4549fa753a7c8c864b0dc5dcdf5eb751732a6ac Mon Sep 17 00:00:00 2001 From: alperyoney Date: Fri, 3 Oct 2025 11:08:30 -0700 Subject: [PATCH 4/5] gh-116738: Port all methods to Argument Clinic --- Modules/clinic/mmapmodule.c.h | 76 ++++++++++++++++++++++++++++++++++- Modules/mmapmodule.c | 46 +++++++++++++++------ 2 files changed, 108 insertions(+), 14 deletions(-) diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h index ecc60b2fbaf539..3b9c60b85d202c 100644 --- a/Modules/clinic/mmapmodule.c.h +++ b/Modules/clinic/mmapmodule.c.h @@ -448,6 +448,23 @@ mmap_mmap_seek(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(mmap_mmap_seekable__doc__, +"seekable($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP_SEEKABLE_METHODDEF \ + {"seekable", (PyCFunction)mmap_mmap_seekable, METH_NOARGS, mmap_mmap_seekable__doc__}, + +static PyObject * +mmap_mmap_seekable_impl(mmap_object *self); + +static PyObject * +mmap_mmap_seekable(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + return mmap_mmap_seekable_impl((mmap_object *)self); +} + PyDoc_STRVAR(mmap_mmap_move__doc__, "move($self, dest, src, count, /)\n" "--\n" @@ -515,6 +532,63 @@ mmap_mmap_move(PyObject *self, PyObject *const *args, Py_ssize_t nargs) return return_value; } +PyDoc_STRVAR(mmap_mmap___enter____doc__, +"__enter__($self, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___ENTER___METHODDEF \ + {"__enter__", (PyCFunction)mmap_mmap___enter__, METH_NOARGS, mmap_mmap___enter____doc__}, + +static PyObject * +mmap_mmap___enter___impl(mmap_object *self); + +static PyObject * +mmap_mmap___enter__(PyObject *self, PyObject *Py_UNUSED(ignored)) +{ + PyObject *return_value = NULL; + + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___enter___impl((mmap_object *)self); + Py_END_CRITICAL_SECTION(); + + return return_value; +} + +PyDoc_STRVAR(mmap_mmap___exit____doc__, +"__exit__($self, exc_type, exc_value, traceback, /)\n" +"--\n" +"\n"); + +#define MMAP_MMAP___EXIT___METHODDEF \ + {"__exit__", _PyCFunction_CAST(mmap_mmap___exit__), METH_FASTCALL, mmap_mmap___exit____doc__}, + +static PyObject * +mmap_mmap___exit___impl(mmap_object *self, PyObject *exc_type, + PyObject *exc_value, PyObject *traceback); + +static PyObject * +mmap_mmap___exit__(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + PyObject *exc_type; + PyObject *exc_value; + PyObject *traceback; + + if (!_PyArg_CheckPositional("__exit__", nargs, 3, 3)) { + goto exit; + } + exc_type = args[0]; + exc_value = args[1]; + traceback = args[2]; + Py_BEGIN_CRITICAL_SECTION(self); + return_value = mmap_mmap___exit___impl((mmap_object *)self, exc_type, exc_value, traceback); + Py_END_CRITICAL_SECTION(); + +exit: + return return_value; +} + #if defined(MS_WINDOWS) PyDoc_STRVAR(mmap_mmap___sizeof____doc__, @@ -668,4 +742,4 @@ mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #ifndef MMAP_MMAP_MADVISE_METHODDEF #define MMAP_MMAP_MADVISE_METHODDEF #endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ -/*[clinic end generated code: output=f2bbd1cba452c773 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=32a1121886e2fcd3 input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 8937b4e4080460..0747157ce7e29f 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -1088,8 +1088,14 @@ mmap_mmap_seek_impl(mmap_object *self, Py_ssize_t dist, int how) return NULL; } +/*[clinic input] +mmap.mmap.seekable + +[clinic start generated code]*/ + static PyObject * -mmap_seekable_method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap_seekable_impl(mmap_object *self) +/*[clinic end generated code: output=6311dc3ea300fa38 input=5132505f6e259001]*/ { Py_RETURN_TRUE; } @@ -1148,24 +1154,38 @@ mmap_closed_get(PyObject *op, void *Py_UNUSED(closure)) return result; } +/*[clinic input] +@critical_section +mmap.mmap.__enter__ + +[clinic start generated code]*/ + static PyObject * -mmap__enter__method(PyObject *op, PyObject *Py_UNUSED(ignored)) +mmap_mmap___enter___impl(mmap_object *self) +/*[clinic end generated code: output=92cfc59f4c4e2d26 input=a446541fbfe0b890]*/ { - mmap_object *self = mmap_object_CAST(op); CHECK_VALID(NULL); return Py_NewRef(self); } +/*[clinic input] +@critical_section +mmap.mmap.__exit__ + + exc_type: object + exc_value: object + traceback: object + / + +[clinic start generated code]*/ + static PyObject * -mmap__exit__method(PyObject *op, PyObject *Py_UNUSED(args)) +mmap_mmap___exit___impl(mmap_object *self, PyObject *exc_type, + PyObject *exc_value, PyObject *traceback) +/*[clinic end generated code: output=bec7e3e319c1f07e input=5f28e91cf752bc64]*/ { - mmap_object *self = mmap_object_CAST(op); - PyObject *result; - Py_BEGIN_CRITICAL_SECTION(op); - result = mmap_mmap_close_impl(self); - Py_END_CRITICAL_SECTION(); - return result; + return mmap_mmap_close_impl(self); } static PyObject * @@ -1341,13 +1361,13 @@ static struct PyMethodDef mmap_object_methods[] = { MMAP_MMAP_READLINE_METHODDEF MMAP_MMAP_RESIZE_METHODDEF MMAP_MMAP_SEEK_METHODDEF - {"seekable", mmap_seekable_method, METH_NOARGS}, + MMAP_MMAP_SEEKABLE_METHODDEF MMAP_MMAP_SIZE_METHODDEF MMAP_MMAP_TELL_METHODDEF MMAP_MMAP_WRITE_METHODDEF MMAP_MMAP_WRITE_BYTE_METHODDEF - {"__enter__", mmap__enter__method, METH_NOARGS}, - {"__exit__", mmap__exit__method, METH_VARARGS}, + MMAP_MMAP___ENTER___METHODDEF + MMAP_MMAP___EXIT___METHODDEF MMAP_MMAP___SIZEOF___METHODDEF MMAP_MMAP__PROTECT_METHODDEF {NULL, NULL} /* sentinel */ From 01cad24509277f174aa7f6385f990e5672f7ab09 Mon Sep 17 00:00:00 2001 From: Alper Date: Sun, 5 Oct 2025 19:25:46 -0500 Subject: [PATCH 5/5] gh-116738: Convert args to AC --- Lib/test/test_mmap.py | 8 ++ Modules/clinic/mmapmodule.c.h | 108 ++++++++++++++++------ Modules/mmapmodule.c | 168 ++++++++++++++++++++-------------- 3 files changed, 190 insertions(+), 94 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index 0571eed23f72dc..368af0cf89c300 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -871,6 +871,10 @@ def test_madvise(self): size = 2 * PAGESIZE m = mmap.mmap(-1, size) + class Number: + def __index__(self): + return 2 + with self.assertRaisesRegex(ValueError, "madvise start out of bounds"): m.madvise(mmap.MADV_NORMAL, size) with self.assertRaisesRegex(ValueError, "madvise start out of bounds"): @@ -879,10 +883,14 @@ def test_madvise(self): m.madvise(mmap.MADV_NORMAL, 0, -1) with self.assertRaisesRegex(OverflowError, "madvise length too large"): m.madvise(mmap.MADV_NORMAL, PAGESIZE, sys.maxsize) + with self.assertRaisesRegex( + TypeError, "'str' object cannot be interpreted as an integer"): + m.madvise(mmap.MADV_NORMAL, PAGESIZE, "Not a Number") self.assertEqual(m.madvise(mmap.MADV_NORMAL), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, PAGESIZE, size), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, 2), None) + self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, Number()), None) self.assertEqual(m.madvise(mmap.MADV_NORMAL, 0, size), None) @unittest.skipUnless(hasattr(mmap.mmap, 'resize'), 'requires mmap.resize') diff --git a/Modules/clinic/mmapmodule.c.h b/Modules/clinic/mmapmodule.c.h index 3b9c60b85d202c..f7fc172b3af705 100644 --- a/Modules/clinic/mmapmodule.c.h +++ b/Modules/clinic/mmapmodule.c.h @@ -5,7 +5,6 @@ preserve #include "pycore_abstract.h" // _PyNumber_Index() #include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION() #include "pycore_modsupport.h" // _PyArg_CheckPositional() -#include "pycore_tuple.h" // _PyTuple_FromArray() PyDoc_STRVAR(mmap_mmap_close__doc__, "close($self, /)\n" @@ -112,7 +111,7 @@ mmap_mmap_read(PyObject *self, PyObject *const *args, Py_ssize_t nargs) } PyDoc_STRVAR(mmap_mmap_find__doc__, -"find($self, /, *args)\n" +"find($self, view, start=None, end=None, /)\n" "--\n" "\n"); @@ -120,31 +119,47 @@ PyDoc_STRVAR(mmap_mmap_find__doc__, {"find", _PyCFunction_CAST(mmap_mmap_find), METH_FASTCALL, mmap_mmap_find__doc__}, static PyObject * -mmap_mmap_find_impl(mmap_object *self, PyObject *args); +mmap_mmap_find_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end); static PyObject * mmap_mmap_find(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - PyObject *__clinic_args = NULL; + Py_buffer view = {NULL, NULL}; + PyObject *start = Py_None; + PyObject *end = Py_None; - __clinic_args = _PyTuple_FromArray(args, nargs); - if (__clinic_args == NULL) { + if (!_PyArg_CheckPositional("find", nargs, 1, 3)) { goto exit; } + if (PyObject_GetBuffer(args[0], &view, PyBUF_SIMPLE) != 0) { + goto exit; + } + if (nargs < 2) { + goto skip_optional; + } + start = args[1]; + if (nargs < 3) { + goto skip_optional; + } + end = args[2]; +skip_optional: Py_BEGIN_CRITICAL_SECTION(self); - return_value = mmap_mmap_find_impl((mmap_object *)self, __clinic_args); + return_value = mmap_mmap_find_impl((mmap_object *)self, &view, start, end); Py_END_CRITICAL_SECTION(); exit: - /* Cleanup for args */ - Py_XDECREF(__clinic_args); + /* Cleanup for view */ + if (view.obj) { + PyBuffer_Release(&view); + } return return_value; } PyDoc_STRVAR(mmap_mmap_rfind__doc__, -"rfind($self, /, *args)\n" +"rfind($self, view, start=None, end=None, /)\n" "--\n" "\n"); @@ -152,25 +167,41 @@ PyDoc_STRVAR(mmap_mmap_rfind__doc__, {"rfind", _PyCFunction_CAST(mmap_mmap_rfind), METH_FASTCALL, mmap_mmap_rfind__doc__}, static PyObject * -mmap_mmap_rfind_impl(mmap_object *self, PyObject *args); +mmap_mmap_rfind_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end); static PyObject * mmap_mmap_rfind(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - PyObject *__clinic_args = NULL; + Py_buffer view = {NULL, NULL}; + PyObject *start = Py_None; + PyObject *end = Py_None; - __clinic_args = _PyTuple_FromArray(args, nargs); - if (__clinic_args == NULL) { + if (!_PyArg_CheckPositional("rfind", nargs, 1, 3)) { + goto exit; + } + if (PyObject_GetBuffer(args[0], &view, PyBUF_SIMPLE) != 0) { goto exit; } + if (nargs < 2) { + goto skip_optional; + } + start = args[1]; + if (nargs < 3) { + goto skip_optional; + } + end = args[2]; +skip_optional: Py_BEGIN_CRITICAL_SECTION(self); - return_value = mmap_mmap_rfind_impl((mmap_object *)self, __clinic_args); + return_value = mmap_mmap_rfind_impl((mmap_object *)self, &view, start, end); Py_END_CRITICAL_SECTION(); exit: - /* Cleanup for args */ - Py_XDECREF(__clinic_args); + /* Cleanup for view */ + if (view.obj) { + PyBuffer_Release(&view); + } return return_value; } @@ -694,7 +725,7 @@ mmap_mmap__protect(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #if defined(HAVE_MADVISE) PyDoc_STRVAR(mmap_mmap_madvise__doc__, -"madvise($self, /, *args)\n" +"madvise($self, option, start=0, length=None, /)\n" "--\n" "\n"); @@ -702,26 +733,49 @@ PyDoc_STRVAR(mmap_mmap_madvise__doc__, {"madvise", _PyCFunction_CAST(mmap_mmap_madvise), METH_FASTCALL, mmap_mmap_madvise__doc__}, static PyObject * -mmap_mmap_madvise_impl(mmap_object *self, PyObject *args); +mmap_mmap_madvise_impl(mmap_object *self, int option, Py_ssize_t start, + PyObject *length_obj); static PyObject * mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) { PyObject *return_value = NULL; - PyObject *__clinic_args = NULL; + int option; + Py_ssize_t start = 0; + PyObject *length_obj = Py_None; - __clinic_args = _PyTuple_FromArray(args, nargs); - if (__clinic_args == NULL) { + if (!_PyArg_CheckPositional("madvise", nargs, 1, 3)) { + goto exit; + } + option = PyLong_AsInt(args[0]); + if (option == -1 && PyErr_Occurred()) { goto exit; } + if (nargs < 2) { + goto skip_optional; + } + { + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(args[1]); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + if (ival == -1 && PyErr_Occurred()) { + goto exit; + } + start = ival; + } + if (nargs < 3) { + goto skip_optional; + } + length_obj = args[2]; +skip_optional: Py_BEGIN_CRITICAL_SECTION(self); - return_value = mmap_mmap_madvise_impl((mmap_object *)self, __clinic_args); + return_value = mmap_mmap_madvise_impl((mmap_object *)self, option, start, length_obj); Py_END_CRITICAL_SECTION(); exit: - /* Cleanup for args */ - Py_XDECREF(__clinic_args); - return return_value; } @@ -742,4 +796,4 @@ mmap_mmap_madvise(PyObject *self, PyObject *const *args, Py_ssize_t nargs) #ifndef MMAP_MMAP_MADVISE_METHODDEF #define MMAP_MMAP_MADVISE_METHODDEF #endif /* !defined(MMAP_MMAP_MADVISE_METHODDEF) */ -/*[clinic end generated code: output=32a1121886e2fcd3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=381f6cf4986ac867 input=a9049054013a1b77]*/ diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 0747157ce7e29f..ac8521f8aa9b6e 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -137,6 +137,24 @@ typedef struct { #include "clinic/mmapmodule.c.h" + +/* Return a Py_ssize_t from the object arg. This conversion logic is similar + to what AC uses for `Py_ssize_t` arguments. + + Returns -1 on error. Use PyErr_Occurred() to disambiguate. +*/ +static Py_ssize_t +_As_Py_ssize_t(PyObject *arg) { + assert(arg != NULL); + Py_ssize_t ival = -1; + PyObject *iobj = _PyNumber_Index(arg); + if (iobj != NULL) { + ival = PyLong_AsSsize_t(iobj); + Py_DECREF(iobj); + } + return ival; +} + static void mmap_object_dealloc(PyObject *op) { @@ -576,95 +594,105 @@ mmap_mmap_read_impl(mmap_object *self, Py_ssize_t num_bytes) } static PyObject * -mmap_gfind_lock_held(mmap_object *self, PyObject *args, int reverse) +mmap_gfind_lock_held(mmap_object *self, Py_buffer *view, PyObject *start_obj, + PyObject *end_obj, int reverse) { Py_ssize_t start = self->pos; Py_ssize_t end = self->size; - Py_buffer view; CHECK_VALID(NULL); - if (!PyArg_ParseTuple(args, reverse ? "y*|nn:rfind" : "y*|nn:find", - &view, &start, &end)) { - return NULL; - } - else { - if (start < 0) - start += self->size; - if (start < 0) - start = 0; - else if (start > self->size) - start = self->size; - - if (end < 0) - end += self->size; - if (end < 0) - end = 0; - else if (end > self->size) - end = self->size; - - Py_ssize_t index; - PyObject *result; - CHECK_VALID_OR_RELEASE(NULL, view); - if (end < start) { - result = PyLong_FromSsize_t(-1); + if (start_obj != Py_None) { + start = _As_Py_ssize_t(start_obj); + if (start == -1 && PyErr_Occurred()) { + return NULL; } - else if (reverse) { - assert(0 <= start && start <= end && end <= self->size); - if (_safe_PyBytes_ReverseFind(&index, self, - self->data + start, end - start, - view.buf, view.len, start) < 0) - { - result = NULL; - } - else { - result = PyLong_FromSsize_t(index); + + if (end_obj != Py_None) { + end = _As_Py_ssize_t(end_obj); + if (end == -1 && PyErr_Occurred()) { + return NULL; } } + } + + if (start < 0) + start += self->size; + if (start < 0) + start = 0; + else if (start > self->size) + start = self->size; + + if (end < 0) + end += self->size; + if (end < 0) + end = 0; + else if (end > self->size) + end = self->size; + + Py_ssize_t index; + PyObject *result; + CHECK_VALID(NULL); + if (end < start) { + result = PyLong_FromSsize_t(-1); + } + else if (reverse) { + assert(0 <= start && start <= end && end <= self->size); + if (_safe_PyBytes_ReverseFind(&index, self, + self->data + start, end - start, + view->buf, view->len, start) < 0) + { + result = NULL; + } else { - assert(0 <= start && start <= end && end <= self->size); - if (_safe_PyBytes_Find(&index, self, - self->data + start, end - start, - view.buf, view.len, start) < 0) - { - result = NULL; - } - else { - result = PyLong_FromSsize_t(index); - } + result = PyLong_FromSsize_t(index); + } + } + else { + assert(0 <= start && start <= end && end <= self->size); + if (_safe_PyBytes_Find(&index, self, + self->data + start, end - start, + view->buf, view->len, start) < 0) + { + result = NULL; + } + else { + result = PyLong_FromSsize_t(index); } - PyBuffer_Release(&view); - return result; } + return result; } /*[clinic input] @critical_section mmap.mmap.find - *args: tuple + view: Py_buffer + start: object = None + end: object = None + / [clinic start generated code]*/ static PyObject * -mmap_mmap_find_impl(mmap_object *self, PyObject *args) -/*[clinic end generated code: output=6e0dfd51873d7263 input=dc56119de60c458f]*/ +mmap_mmap_find_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end) +/*[clinic end generated code: output=ef8878a322f00192 input=0135504494b52c2b]*/ { - return mmap_gfind_lock_held(self, args, 0); + return mmap_gfind_lock_held(self, view, start, end, 0); } /*[clinic input] @critical_section -mmap.mmap.rfind - - *args: tuple +mmap.mmap.rfind = mmap.mmap.find [clinic start generated code]*/ static PyObject * -mmap_mmap_rfind_impl(mmap_object *self, PyObject *args) -/*[clinic end generated code: output=a8dbff2d7090cf2c input=ab496c4db0a37948]*/ +mmap_mmap_rfind_impl(mmap_object *self, Py_buffer *view, PyObject *start, + PyObject *end) +/*[clinic end generated code: output=73b918940d67c2b8 input=8aecdd1f70c06c62]*/ { - return mmap_gfind_lock_held(self, args, 1); + return mmap_gfind_lock_held(self, view, start, end, 1); } static int @@ -1299,22 +1327,28 @@ mmap_mmap__protect_impl(mmap_object *self, unsigned int flNewProtect, @critical_section mmap.mmap.madvise - *args: tuple + option: int + start: Py_ssize_t = 0 + length as length_obj: object = None + / [clinic start generated code]*/ static PyObject * -mmap_mmap_madvise_impl(mmap_object *self, PyObject *args) -/*[clinic end generated code: output=237b3c0176f65b4f input=14e3ccbd25a38f22]*/ +mmap_mmap_madvise_impl(mmap_object *self, int option, Py_ssize_t start, + PyObject *length_obj) +/*[clinic end generated code: output=816be656f08c0e3c input=2d37f7a4c87f1053]*/ { - int option; - Py_ssize_t start = 0, length; + Py_ssize_t length; CHECK_VALID(NULL); - length = self->size; - - if (!PyArg_ParseTuple(args, "i|nn:madvise", &option, &start, &length)) { - return NULL; + if (length_obj == Py_None) { + length = self->size; + } else { + length = _As_Py_ssize_t(length_obj); + if (length == -1 && PyErr_Occurred()) { + return NULL; + } } if (start < 0 || start >= self->size) {