From de4babac869d5d9f4df3db4a7c6f6466bb9951a4 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 24 Aug 2025 00:38:50 +0900 Subject: [PATCH 1/5] Convert mmap.flush to use argument clinic --- Modules/mmapmodule.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 0cb4b62d734550..4d32ec32156650 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -28,6 +28,12 @@ #include "pycore_fileutils.h" // _Py_stat_struct #include "pycore_weakref.h" // FT_CLEAR_WEAKREFS() +/*[clinic input] +module mmap +class mmap.mmap "mmap_object *" "mmap_object_type" +[clinic start generated code]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=4ebde54549b9daa7]*/ + #include // offsetof() #ifndef MS_WINDOWS # include // close() @@ -127,6 +133,9 @@ typedef struct { } mmap_object; #define mmap_object_CAST(op) ((mmap_object *)(op)) +#define MMAP_GET_SIZE(self) (mmap_object_CAST(self)->size) + +#include "clinic/mmapmodule.c.h" static int mmap_object_traverse(PyObject *op, visitproc visit, void *arg) @@ -924,15 +933,26 @@ mmap_tell_method(PyObject *op, PyObject *Py_UNUSED(ignored)) return PyLong_FromSize_t(self->pos); } +/*[clinic input] +mmap.mmap.flush + + offset: Py_ssize_t = 0 + size: Py_ssize_t(c_default="MMAP_GET_SIZE(self)") = None + / + +Flushes changes made to the in-memory copy of a file back to disk. + +If offset and size are specified, only the specified range will +be flushed. If not specified, the entire mapped region will be +flushed. +[clinic start generated code]*/ + static PyObject * -mmap_flush_method(PyObject *op, PyObject *args) +mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size) +/*[clinic end generated code: output=956ced67466149cf input=23ac67c08804a13a]*/ { - 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 (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; @@ -1194,7 +1214,7 @@ 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}, + MMAP_MMAP_FLUSH_METHODDEF #ifdef HAVE_MADVISE {"madvise", mmap_madvise_method, METH_VARARGS}, #endif From 3e284dc2c7be27a7b036ca3924d999fa37dfaa50 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 24 Aug 2025 01:35:32 +0900 Subject: [PATCH 2/5] Add test --- Lib/test/test_mmap.py | 12 ++++++++++++ Modules/mmapmodule.c | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_mmap.py b/Lib/test/test_mmap.py index b2a299ed172967..83def9c31799af 100644 --- a/Lib/test/test_mmap.py +++ b/Lib/test/test_mmap.py @@ -1136,6 +1136,18 @@ def test_access_violations(self): self.assertEqual(stdout.strip(), b'') self.assertEqual(stderr.strip(), b'') + def test_flush_parameters(self): + with open(TESTFN, 'wb+') as f: + f.write(b'x' * PAGESIZE * 3) + f.flush() + + m = mmap.mmap(f.fileno(), PAGESIZE * 3) + self.addCleanup(m.close) + + m.flush() + m.flush(PAGESIZE) + m.flush(PAGESIZE, PAGESIZE) + class LargeMmapTests(unittest.TestCase): diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index 4d32ec32156650..ba658868972aa1 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -133,7 +133,6 @@ typedef struct { } mmap_object; #define mmap_object_CAST(op) ((mmap_object *)(op)) -#define MMAP_GET_SIZE(self) (mmap_object_CAST(self)->size) #include "clinic/mmapmodule.c.h" @@ -937,7 +936,7 @@ mmap_tell_method(PyObject *op, PyObject *Py_UNUSED(ignored)) mmap.mmap.flush offset: Py_ssize_t = 0 - size: Py_ssize_t(c_default="MMAP_GET_SIZE(self)") = None + size: Py_ssize_t(c_default="-1") = None / Flushes changes made to the in-memory copy of a file back to disk. @@ -949,10 +948,15 @@ flushed. static PyObject * mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size) -/*[clinic end generated code: output=956ced67466149cf input=23ac67c08804a13a]*/ +/*[clinic end generated code: output=956ced67466149cf input=07c2c6d4e69263a4]*/ { CHECK_VALID(NULL); + /* If size is -1 (default), calculate size from offset to end */ + if (size == -1) { + size = self->size - offset; + } + if (size < 0 || offset < 0 || self->size - offset < size) { PyErr_SetString(PyExc_ValueError, "flush values out of range"); return NULL; From ff3a039933b3590f776180a4bf982ea774717053 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 24 Aug 2025 01:52:35 +0900 Subject: [PATCH 3/5] Add clinic generated file --- Modules/clinic/mmapmodule.c.h | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) 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..ec4282e8082ab7 --- /dev/null +++ b/Modules/clinic/mmapmodule.c.h @@ -0,0 +1,70 @@ +/*[clinic input] +preserve +[clinic start generated code]*/ + +#include "pycore_abstract.h" // _PyNumber_Index() +#include "pycore_modsupport.h" // _PyArg_CheckPositional() + +PyDoc_STRVAR(mmap_mmap_flush__doc__, +"flush($self, offset=0, size=None, /)\n" +"--\n" +"\n" +"Flushes changes made to the in-memory copy of a file back to disk.\n" +"\n" +"If offset and size are specified, only the specified range will\n" +"be flushed. If not specified, the entire mapped region will be\n" +"flushed."); + +#define MMAP_MMAP_FLUSH_METHODDEF \ + {"flush", _PyCFunction_CAST(mmap_mmap_flush), METH_FASTCALL, mmap_mmap_flush__doc__}, + +static PyObject * +mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size); + +static PyObject * +mmap_mmap_flush(PyObject *self, PyObject *const *args, Py_ssize_t nargs) +{ + PyObject *return_value = NULL; + Py_ssize_t offset = 0; + Py_ssize_t size = -1; + + if (!_PyArg_CheckPositional("flush", nargs, 0, 2)) { + goto exit; + } + if (nargs < 1) { + goto skip_optional; + } + { + 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; + } + offset = ival; + } + 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; + } + size = ival; + } +skip_optional: + return_value = mmap_mmap_flush_impl((mmap_object *)self, offset, size); + +exit: + return return_value; +} +/*[clinic end generated code: output=c95c7ffe05f26c3a input=a9049054013a1b77]*/ From f09fa8a52b8daf26f4404feda5fad82d297671f7 Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 24 Aug 2025 02:05:04 +0900 Subject: [PATCH 4/5] Add news entry --- .../next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst diff --git a/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst b/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst new file mode 100644 index 00000000000000..31421ef5e49489 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst @@ -0,0 +1,2 @@ +Fixed a bug in :meth:mmap.mmap.flush where calling with only an offset +parameter would fail. From 1493fbf7475b42c63edfb8d60c4edd1b68442dfd Mon Sep 17 00:00:00 2001 From: AN Long Date: Sun, 24 Aug 2025 02:12:01 +0900 Subject: [PATCH 5/5] Fix docs --- .../next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst | 2 +- Modules/mmapmodule.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst b/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst index 31421ef5e49489..21c28c49628cba 100644 --- a/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst +++ b/Misc/NEWS.d/next/Library/2025-08-24-02-04-32.gh-issue-138092.V4-wTO.rst @@ -1,2 +1,2 @@ -Fixed a bug in :meth:mmap.mmap.flush where calling with only an offset +Fixed a bug in :meth:`mmap.mmap.flush` where calling with only an offset parameter would fail. diff --git a/Modules/mmapmodule.c b/Modules/mmapmodule.c index ba658868972aa1..f4d739320952f1 100644 --- a/Modules/mmapmodule.c +++ b/Modules/mmapmodule.c @@ -952,7 +952,7 @@ mmap_mmap_flush_impl(mmap_object *self, Py_ssize_t offset, Py_ssize_t size) { CHECK_VALID(NULL); - /* If size is -1 (default), calculate size from offset to end */ + // If size is -1 (default), calculate size from offset to end. if (size == -1) { size = self->size - offset; }