Skip to content

Commit 186c021

Browse files
zoobaZackerySpytzerlend-aasland
authored
gh-81489: Use Unicode APIs for mmap tagname on Windows (GH-14133)
Co-authored-by: Zackery Spytz <[email protected]> Co-authored-by: Erlend E. Aasland <[email protected]>
1 parent d15e1ac commit 186c021

File tree

4 files changed

+32
-27
lines changed

4 files changed

+32
-27
lines changed

Doc/library/mmap.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ To map anonymous memory, -1 should be passed as the fileno along with the length
6262
the same file. If you specify the name of an existing tag, that tag is
6363
opened, otherwise a new tag of this name is created. If this parameter is
6464
omitted or ``None``, the mapping is created without a name. Avoiding the
65-
use of the tag parameter will assist in keeping your code portable between
66-
Unix and Windows.
65+
use of the *tagname* parameter will assist in keeping your code portable
66+
between Unix and Windows.
6767

6868
*offset* may be specified as a non-negative integer offset. mmap references
6969
will be relative to the offset from the beginning of the file. *offset*

Lib/test/test_mmap.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -671,14 +671,16 @@ def test_tagname(self):
671671
m2.close()
672672
m1.close()
673673

674+
with self.assertRaisesRegex(TypeError, 'tagname'):
675+
mmap.mmap(-1, 8, tagname=1)
676+
674677
@cpython_only
675678
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
676679
def test_sizeof(self):
677680
m1 = mmap.mmap(-1, 100)
678681
tagname = random_tagname()
679682
m2 = mmap.mmap(-1, 100, tagname=tagname)
680-
self.assertEqual(sys.getsizeof(m2),
681-
sys.getsizeof(m1) + len(tagname) + 1)
683+
self.assertGreater(sys.getsizeof(m2), sys.getsizeof(m1))
682684

683685
@unittest.skipUnless(os.name == 'nt', 'requires Windows')
684686
def test_crasher_on_windows(self):
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix mojibake in :class:`mmap.mmap` when using a non-ASCII *tagname* argument
2+
on Windows.

Modules/mmapmodule.c

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ typedef struct {
109109
#ifdef MS_WINDOWS
110110
HANDLE map_handle;
111111
HANDLE file_handle;
112-
char * tagname;
112+
wchar_t * tagname;
113113
#endif
114114

115115
#ifdef UNIX
@@ -539,7 +539,7 @@ mmap_resize_method(mmap_object *self,
539539
CloseHandle(self->map_handle);
540540
/* if the file mapping still exists, it cannot be resized. */
541541
if (self->tagname) {
542-
self->map_handle = OpenFileMapping(FILE_MAP_WRITE, FALSE,
542+
self->map_handle = OpenFileMappingW(FILE_MAP_WRITE, FALSE,
543543
self->tagname);
544544
if (self->map_handle) {
545545
PyErr_SetFromWindowsErr(ERROR_USER_MAPPED_FILE);
@@ -568,7 +568,7 @@ mmap_resize_method(mmap_object *self,
568568

569569
/* create a new file mapping and map a new view */
570570
/* FIXME: call CreateFileMappingW with wchar_t tagname */
571-
self->map_handle = CreateFileMapping(
571+
self->map_handle = CreateFileMappingW(
572572
self->file_handle,
573573
NULL,
574574
PAGE_READWRITE,
@@ -843,12 +843,11 @@ mmap__repr__method(PyObject *self)
843843
static PyObject *
844844
mmap__sizeof__method(mmap_object *self, void *unused)
845845
{
846-
Py_ssize_t res;
847-
848-
res = _PyObject_SIZE(Py_TYPE(self));
849-
if (self->tagname)
850-
res += strlen(self->tagname) + 1;
851-
return PyLong_FromSsize_t(res);
846+
size_t res = _PyObject_SIZE(Py_TYPE(self));
847+
if (self->tagname) {
848+
res += (wcslen(self->tagname) + 1) * sizeof(self->tagname[0]);
849+
}
850+
return PyLong_FromSize_t(res);
852851
}
853852
#endif
854853

@@ -1400,7 +1399,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
14001399
DWORD off_lo; /* lower 32 bits of offset */
14011400
DWORD size_hi; /* upper 32 bits of size */
14021401
DWORD size_lo; /* lower 32 bits of size */
1403-
const char *tagname = "";
1402+
PyObject *tagname = Py_None;
14041403
DWORD dwErr = 0;
14051404
int fileno;
14061405
HANDLE fh = 0;
@@ -1410,7 +1409,7 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
14101409
"tagname",
14111410
"access", "offset", NULL };
14121411

1413-
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|ziL", keywords,
1412+
if (!PyArg_ParseTupleAndKeywords(args, kwdict, "in|OiL", keywords,
14141413
&fileno, &map_size,
14151414
&tagname, &access, &offset)) {
14161415
return NULL;
@@ -1543,17 +1542,19 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
15431542
m_obj->weakreflist = NULL;
15441543
m_obj->exports = 0;
15451544
/* set the tag name */
1546-
if (tagname != NULL && *tagname != '\0') {
1547-
m_obj->tagname = PyMem_Malloc(strlen(tagname)+1);
1545+
if (!Py_IsNone(tagname)) {
1546+
if (!PyUnicode_Check(tagname)) {
1547+
Py_DECREF(m_obj);
1548+
return PyErr_Format(PyExc_TypeError, "expected str or None for "
1549+
"'tagname', not %.200s",
1550+
Py_TYPE(tagname)->tp_name);
1551+
}
1552+
m_obj->tagname = PyUnicode_AsWideCharString(tagname, NULL);
15481553
if (m_obj->tagname == NULL) {
1549-
PyErr_NoMemory();
15501554
Py_DECREF(m_obj);
15511555
return NULL;
15521556
}
1553-
strcpy(m_obj->tagname, tagname);
15541557
}
1555-
else
1556-
m_obj->tagname = NULL;
15571558

15581559
m_obj->access = (access_mode)access;
15591560
size_hi = (DWORD)(size >> 32);
@@ -1562,12 +1563,12 @@ new_mmap_object(PyTypeObject *type, PyObject *args, PyObject *kwdict)
15621563
off_lo = (DWORD)(offset & 0xFFFFFFFF);
15631564
/* For files, it would be sufficient to pass 0 as size.
15641565
For anonymous maps, we have to pass the size explicitly. */
1565-
m_obj->map_handle = CreateFileMapping(m_obj->file_handle,
1566-
NULL,
1567-
flProtect,
1568-
size_hi,
1569-
size_lo,
1570-
m_obj->tagname);
1566+
m_obj->map_handle = CreateFileMappingW(m_obj->file_handle,
1567+
NULL,
1568+
flProtect,
1569+
size_hi,
1570+
size_lo,
1571+
m_obj->tagname);
15711572
if (m_obj->map_handle != NULL) {
15721573
m_obj->data = (char *) MapViewOfFile(m_obj->map_handle,
15731574
dwDesiredAccess,

0 commit comments

Comments
 (0)