gh-87595: Support mmap.size() for anonymous mapping on Unix (GH-24781)

Previously, the size would be returned on Windows and an OSError would
be raised on Unix.

Also, raise ValueError instead of OSError for trackfd=False.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
Zackery Spytz 2025-09-02 13:24:06 -07:00 committed by GitHub
parent e4e2390a64
commit 32032ee376
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 21 additions and 5 deletions

View file

@ -312,6 +312,10 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
Return the length of the file, which can be larger than the size of the Return the length of the file, which can be larger than the size of the
memory-mapped area. memory-mapped area.
For anonymous mapping, return its size.
.. versionchanged:: next
Supports anonymous mapping on Unix.
.. method:: tell() .. method:: tell()

View file

@ -6,7 +6,6 @@
from test.support.os_helper import TESTFN, unlink from test.support.os_helper import TESTFN, unlink
from test.support.script_helper import assert_python_ok from test.support.script_helper import assert_python_ok
import unittest import unittest
import errno
import os import os
import re import re
import itertools import itertools
@ -282,9 +281,8 @@ def test_trackfd_parameter(self):
if close_original_fd: if close_original_fd:
f.close() f.close()
self.assertEqual(len(m), size) self.assertEqual(len(m), size)
with self.assertRaises(OSError) as err_cm: with self.assertRaises(ValueError):
m.size() m.size()
self.assertEqual(err_cm.exception.errno, errno.EBADF)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
m.resize(size * 2) m.resize(size * 2)
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
@ -309,7 +307,7 @@ def test_trackfd_parameter(self):
def test_trackfd_neg1(self): def test_trackfd_neg1(self):
size = 64 size = 64
with mmap.mmap(-1, size, trackfd=False) as m: with mmap.mmap(-1, size, trackfd=False) as m:
with self.assertRaises(OSError): with self.assertRaises(ValueError):
m.size() m.size()
with self.assertRaises(ValueError): with self.assertRaises(ValueError):
m.resize(size // 2) m.resize(size // 2)
@ -505,6 +503,7 @@ def test_anonymous(self):
b = x & 0xff b = x & 0xff
m[x] = b m[x] = b
self.assertEqual(m[x], b) self.assertEqual(m[x], b)
self.assertEqual(m.size(), PAGESIZE)
def test_read_all(self): def test_read_all(self):
m = mmap.mmap(-1, 16) m = mmap.mmap(-1, 16)

View file

@ -0,0 +1,5 @@
The :meth:`~mmap.mmap.size` method of the :class:`mmap.mmap` class now
returns the size of an anonymous mapping on both Unix and Windows.
Previously, the size would be returned on Windows and an :exc:`OSError`
would be raised on Unix.
Raise :exc:`ValueError` instead of :exc:`OSError` with ``trackfd=False``.

View file

@ -740,7 +740,7 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored))
#endif /* MS_WINDOWS */ #endif /* MS_WINDOWS */
#ifdef UNIX #ifdef UNIX
{ if (self->fd != -1) {
struct _Py_stat_struct status; struct _Py_stat_struct status;
if (_Py_fstat(self->fd, &status) == -1) if (_Py_fstat(self->fd, &status) == -1)
return NULL; return NULL;
@ -750,6 +750,14 @@ mmap_size_method(PyObject *op, PyObject *Py_UNUSED(ignored))
return PyLong_FromLong(status.st_size); return PyLong_FromLong(status.st_size);
#endif #endif
} }
else if (self->trackfd) {
return PyLong_FromSsize_t(self->size);
}
else {
PyErr_SetString(PyExc_ValueError,
"can't get size with trackfd=False");
return NULL;
}
#endif /* UNIX */ #endif /* UNIX */
} }