Patch #1407135, bug #1424041, make mmap.mmap(-1, length) work the same
authorNeal Norwitz <nnorwitz@gmail.com>
Sun, 5 Feb 2006 05:45:43 +0000 (05:45 +0000)
committerNeal Norwitz <nnorwitz@gmail.com>
Sun, 5 Feb 2006 05:45:43 +0000 (05:45 +0000)
on both Unix (SVR4 and BSD) and Windows.  Restores behaviour of passing -1
for anonymous memory on Unix.  Use MAP_ANONYMOUS instead of _ANON since
the latter is deprecated according to Linux (gentoo) man pages.

Should we continue to allow mmap.mmap(0, length) to work on Windows?
0 is a valid fd.

Will backport bugfix portions.

Doc/lib/libmmap.tex
Lib/test/output/test_mmap
Lib/test/test_mmap.py
Misc/NEWS
Modules/mmapmodule.c

index e7db81495588b26f2e81ea6e8643bf2fc809d0cc..3dca40f6c4b82c9aa9f4f1fd91550ba712459828 100644 (file)
@@ -37,7 +37,8 @@ taken from the specified file.  Assignment to an
 exception.  Assignment to an \constant{ACCESS_WRITE} memory map
 affects both memory and the underlying file.  Assignment to an
 \constant{ACCESS_COPY} memory map affects memory but does not update
-the underlying file.
+the underlying file.  \versionchanged[To map anonymous memory,
+-1 should be passed as the fileno along with the length]{2.5}
 
 \begin{funcdesc}{mmap}{fileno, length\optional{, tagname\optional{, access}}}
   \strong{(Windows version)} Maps \var{length} bytes from the file
index 1ce49436ab76690a7577bbde6f38d26ec4e71d6b..605f840f5347809b82ba0085be62c5fb099b786c 100644 (file)
@@ -34,4 +34,5 @@ test_mmap
   Try opening a bad file descriptor...
   Ensuring that passing 0 as map length sets map size to current file size.
   Ensuring that passing 0 as map length sets map size to current file size.
+  anonymous mmap.mmap(-1, PAGESIZE)...
  Test passed
index 693031769d28c23706ff877c6a10eeaf30caff54..d2a24770cf203d74620ae71ca14c4e794a9e1064 100644 (file)
@@ -283,7 +283,7 @@ def test_both():
 
     print '  Try opening a bad file descriptor...'
     try:
-        mmap.mmap(-1, 4096)
+        mmap.mmap(-2, 4096)
     except mmap.error:
         pass
     else:
@@ -380,6 +380,16 @@ def test_both():
     finally:
         os.unlink(TESTFN)
 
-    print ' Test passed'
+def test_anon():
+    print "  anonymous mmap.mmap(-1, PAGESIZE)..."
+    m = mmap.mmap(-1, PAGESIZE)
+    for x in xrange(PAGESIZE):
+        verify(m[x] == '\0', "anonymously mmap'ed contents should be zero")
+
+    for x in xrange(PAGESIZE):
+        m[x] = ch = chr(x & 255)
+        vereq(m[x], ch)
 
 test_both()
+test_anon()
+print ' Test passed'
index 7fe03933669deecb18caf5c7569b625f35b02faa..1e828d6a44ca2ac31fdb6e53dda42a8f80f9e59b 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -216,6 +216,10 @@ Core and builtins
 Extension Modules
 -----------------
 
+- Patch #1407135, bug #1424041: harmonize mmap behavior of anonymous memory.
+  mmap.mmap(-1, size) now returns anonymous memory in both Unix and Windows.
+  mmap.mmap(0, size) should not be used on Windows for anonymous memory.
+
 - Patch #1422385: The nis module now supports access to domains other
   than the system default domain.
 
index b01f42f0346c8c9be8c917fb88fe724097a65d9c..b6b2d85301ad05c3dbe17c6fbb5f597acef585c1 100644 (file)
@@ -54,6 +54,11 @@ my_getpagesize(void)
 #include <string.h>
 #include <sys/types.h>
 
+/* maybe define MAP_ANON in terms of MAP_ANONYMOUS */
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#  define MAP_ANONYMOUS MAP_ANON
+#endif
+
 static PyObject *mmap_module_error;
 
 typedef enum
@@ -863,6 +868,7 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
        PyObject *map_size_obj = NULL;
        int map_size;
        int fd, flags = MAP_SHARED, prot = PROT_WRITE | PROT_READ;
+       int devzero = -1;
        int access = (int)ACCESS_DEFAULT;
        static const char *keywords[] = {"fileno", "length", 
                                          "flags", "prot", 
@@ -921,15 +927,41 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
        m_obj->data = NULL;
        m_obj->size = (size_t) map_size;
        m_obj->pos = (size_t) 0;
-       m_obj->fd = dup(fd);
-       if (m_obj->fd == -1) {
-               Py_DECREF(m_obj);
-               PyErr_SetFromErrno(mmap_module_error);
-               return NULL;
+       if (fd == -1) {
+               m_obj->fd = -1;
+               /* Assume the caller wants to map anonymous memory.
+                  This is the same behaviour as Windows.  mmap.mmap(-1, size)
+                  on both Windows and Unix map anonymous memory.
+               */
+#ifdef MAP_ANONYMOUS
+               /* BSD way to map anonymous memory */
+               flags |= MAP_ANONYMOUS;
+#else
+               /* SVR4 method to map anonymous memory is to open /dev/zero */
+               fd = devzero = open("/dev/zero", O_RDWR);
+               if (devzero == -1) {
+                       Py_DECREF(m_obj);
+                       PyErr_SetFromErrno(mmap_module_error);
+                       return NULL;
+               }
+#endif
+       } else {
+               m_obj->fd = dup(fd);
+               if (m_obj->fd == -1) {
+                       Py_DECREF(m_obj);
+                       PyErr_SetFromErrno(mmap_module_error);
+                       return NULL;
+               }
        }
+
        m_obj->data = mmap(NULL, map_size, 
                           prot, flags,
                           fd, 0);
+
+       if (devzero != -1) {
+               close(devzero);
+       }
+
        if (m_obj->data == (char *)-1) {
                m_obj->data = NULL;
                Py_DECREF(m_obj);
@@ -986,8 +1018,15 @@ new_mmap_object(PyObject *self, PyObject *args, PyObject *kwdict)
        if (map_size < 0)
                return NULL;
        
-       /* if an actual filename has been specified */
-       if (fileno != 0) {
+       /* assume -1 and 0 both mean invalid filedescriptor
+          to 'anonymously' map memory.
+          XXX: fileno == 0 is a valid fd, but was accepted prior to 2.5.
+          XXX: Should this code be added?
+          if (fileno == 0)
+               PyErr_Warn(PyExc_DeprecationWarning,
+                          "don't use 0 for anonymous memory");
+        */
+       if (fileno != -1 && fileno != 0) {
                fh = (HANDLE)_get_osfhandle(fileno);
                if (fh==(HANDLE)-1) {
                        PyErr_SetFromErrno(mmap_module_error);
@@ -1123,10 +1162,10 @@ PyMODINIT_FUNC
        PyDict_SetItemString (dict, "MAP_EXECUTABLE",
                              PyInt_FromLong(MAP_EXECUTABLE) );
 #endif
-#ifdef MAP_ANON
-       PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANON) );
+#ifdef MAP_ANONYMOUS
+       PyDict_SetItemString (dict, "MAP_ANON", PyInt_FromLong(MAP_ANONYMOUS) );
        PyDict_SetItemString (dict, "MAP_ANONYMOUS",
-                             PyInt_FromLong(MAP_ANON) );
+                             PyInt_FromLong(MAP_ANONYMOUS) );
 #endif
 
        PyDict_SetItemString (dict, "PAGESIZE",