linuxmmap

mmap flag MAP_UNINITIALIZED not defined


mmap() docs mentions flag MAP_UNINITIALIZED, but the flag doesn't seem to be defined. Tried on Centos7, and Xenial, neither distro has the flag defined in sys/mman.h as alleged.
Astonishingly, the internet doesn't seem to be aware of this. What's the story?

Edit: I understand from the docs that the flag is only honoured on embedded or low-security devices, but that doesn't mean the flag shouldn't be defined... How do you use it in portable code? Google has revealed code where it is defined as 0 in cases where not supported, except in my cases it's not defined at all.


Solution

  • In order to understand what to do about the fact that #include <sys/mman.h> does not define MAP_UNINITIALIZED, it is helpful to understand how the interface to the kernel is defined.

    To build a kernel module, you will need the kernel headers used to build the kernel for the exact version of the kernel for which you wish to build the module. As you wish to run in userspace, you won't need these.

    The headers that define the kernel API for userspace are largely in /usr/include/linux and /usr/include/asm (see this for how they are generated). One of the more important consumers of these headers is the C standard library, e.g., glibc, which must be built against some version of these headers. Since the linux kernel API is backwards compatible, you may have a glibc (or other library implementation) built against an older version of these headers than the kernel you are running. I'm by no means an expert on how all the various distros distribute glibc, but it is my impression that the kernel headers defining its userspace API are generally the version that glibc has been built against.

    Finally, glibc defines its API through headers also installed under /usr/include such as /usr/include/sys. I don't know exactly what, if any, backward or forward compatibility is provided for applications built with older or newer glibc headers, but I'm guessing that the library .so version number gets bumped when backward comparability would be broken.

    So now we can understand your problem to be that the glibc headers don't actually define MAP_UNINITIALIZED for the distros/versions that you tried.

    However, the linux kernel API has exposed MAP_UNINITIALIZED, as this patch demonstrates. If the glibc headers don't define it for you, you can use the linux kernel API headers and #include <linux/mman.h> if this defines it. Note that you will still need to #include <sys/mman.h> in order to get the prototype for mmap, among other things.

    If your linux kernel API headers don't define MAP_UNINITIALIZED but you have a kernel version that implements it, you can define it yourself:

     #define MAP_UNINITIALIZED 0x4000000    
    

    You don't have to worry that you are effectively using "newer" headers than your glibc was built with, because the glibc implementation of mmap is very thin:

    #include <sys/types.h>
    #include <sys/mman.h>
    #include <errno.h>
    #include <sysdep.h>
    
    #ifndef MMAP_PAGE_SHIFT
    #define MMAP_PAGE_SHIFT 12
    #endif
    
    __ptr_t
    __mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
    {
      if (offset & ((1 << MMAP_PAGE_SHIFT) - 1))
        {
          __set_errno (EINVAL);
          return MAP_FAILED;
        }
      return (__ptr_t) INLINE_SYSCALL (mmap2, 6, addr, len, prot, flags, fd,
                                       offset >> MMAP_PAGE_SHIFT);
    }
    
    weak_alias (__mmap, mmap)
    

    It is just passing your flags straight through to the kernel.