6

It seems that every process has private memory mappings that are neither readable nor writeable nor executable (whose flags are "---p"):

grep -- --- /proc/self/maps
7f2bd9bf7000-7f2bd9df6000 ---p 001be000 fc:00 3733                       /lib/x86_64-linux-gnu/libc-2.19.so
7f2bd9e04000-7f2bda003000 ---p 00003000 fc:00 3743                       /lib/x86_64-linux-gnu/libdl-2.19.so
7f2bda042000-7f2bda241000 ---p 0003d000 fc:00 36067                      /lib/x86_64-linux-gnu/libpcre.so.3.13.1

returns some in shared libraries and doing that for java (JVM) processes even returns a dozen of anonymous mappings with hundreds of megabytes.

Edit: If these mappings are placeholders, who will be using these kept places at which events and from which other activity are they protected - in other words: What is the wrong behavior that could happen if these placeholders were not there ?

2nd edit: Given these holes in shared libraries are in fact helpful for some purpose of the compiler and/or dynamic linker, there must be some other purpose for these holes in anonymous mappings visible in JVM processes. Sorted the anonymous mappings of a tomcat JVM process by size:

 20 MB  00007FA0AAB52000-00007FA0AC000000 ---p 00000000 00:00 0
 41 MB  00007FA0B1603000-00007FA0B4000000 ---p 00000000 00:00 0
 50 MB  00007FA090D04000-00007FA094000000 ---p 00000000 00:00 0
 53 MB  00007FA0F8A40000-00007FA0FC000000 ---p 00000000 00:00 0
 61 MB  00007FA0C42C5000-00007FA0C8000000 ---p 00000000 00:00 0
 61 MB  00007FA0CC29A000-00007FA0D0000000 ---p 00000000 00:00 0
 61 MB  00007FA0D0293000-00007FA0D4000000 ---p 00000000 00:00 0
 62 MB  00007FA0D814C000-00007FA0DC000000 ---p 00000000 00:00 0
 62 MB  00007FA0E017E000-00007FA0E4000000 ---p 00000000 00:00 0
 63 MB  00007FA0B803B000-00007FA0BC000000 ---p 00000000 00:00 0
 63 MB  00007FA0BC021000-00007FA0C0000000 ---p 00000000 00:00 0
 63 MB  00007FA0C0021000-00007FA0C4000000 ---p 00000000 00:00 0
 63 MB  00007FA0D4075000-00007FA0D8000000 ---p 00000000 00:00 0
 63 MB  00007FA0DC040000-00007FA0E0000000 ---p 00000000 00:00 0
 63 MB  00007FA0E4067000-00007FA0E8000000 ---p 00000000 00:00 0
189 MB  00007FA0EC300000-00007FA0F8000000 ---p 00000000 00:00 0
1008 MB  0000000100FF5000-0000000140000000 ---p 00000000 00:00 0
6

Note that there are two memory regions of 2044KB with null permissions. As mentioned earlier, the ELF's 'execution view' is concerned with how to load an executable binary into memory. When ld.so brings in the dynamic libraries, it looks at the segments labelled as LOAD (look at "Program Headers" and "Section to Segment mapping" from readelf -a xxx.so command.) Usually there are two LOAD segments, and there is a "hole" between the two segments (look at the VirtAddr and MemSiz of these two segments), so ld.so will make this hole inaccessible deliberately: Look for the PROT_NONE symbol in _dl_map_object_from_fd in elf/dl-load.c

http://www.cs.stevens.edu/~jschauma/810/elf.html

It's also easy to see this happening as a mprotect call, using strace e.g. strace -f grep -- . /proc/self/maps 2>&1 |less.

open("/lib64/libpcre.so.1", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\300\25\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=471728, ...}) = 0
mmap(NULL, 2564360, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f0e3ad2a000
mprotect(0x7f0e3ad9c000, 2093056, PROT_NONE) = 0
mmap(0x7f0e3af9b000, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x71000) = 0x7f0e3af9b000
close(3)                                = 0

There are mirrors of the glibc repo on github, so it wasn't hard to search for PROT_NONE...

/* This implementation assumes (as does the corresponding implementation of _dl_unmap_segments, in dl-unmap-segments.h) that shared objects are always laid out with all segments contiguous (or with gaps between them small enough that it's preferable to reserve all whole pages inside the gaps with PROT_NONE mappings rather than permitting other use of those parts of the address space). */

https://github.com/bminor/glibc/blob/73dfd088936b9237599e4ab737c7ae2ea7d710e1/elf/dl-map-segments.h#L21

/* _dl_map_segments ensures that any whole pages in gaps between segments are filled in with PROT_NONE mappings. So we can just unmap the whole range in one fell swoop. */

https://github.com/bminor/glibc/blob/73dfd088936b9237599e4ab737c7ae2ea7d710e1/elf/dl-unmap-segments.h#L25

Java

OpenJDK ... uses PROT_NONE mappings to reserve uncommitted address space (which is then committed with mprotect calls, as needed).

The natural assumption is that it wishes to have contiguous heap memory for some reason.

It uses PROT_NONE to reserve space, until it actually needs it. The original context of this comment is a discussion about Linux VM overcommit: using unaccessible mappings avoids requiring any commitment from the kernel (until the mapping is needed & made accessible), in case the kernel is configure for strict commit mode.

If you're wondering why it needs to make this reservation in advance in the context of the JVM, consider that native code linked in using JNI or equivalent might also be using mmap.

https://lwn.net/Articles/627728/

  • Thank you for your answer, but I still don't know what the purpose of that hole is. The linked article explains what is done, but not why it is done this way. – Juergen Mar 24 '17 at 21:18
  • @Juergen added one reason. I think this is the only informative comment in the code for your purposes. – sourcejedi Mar 24 '17 at 21:32
  • 1
    Are you suggesting that those hole mappings are created with the purpose of making it easier to unmap them ? That sounds unbelievable. But if the answer is yes, how would unmapping be harder if those holes did not exist at all ? What would be the difference of PROT_NONE holes compared to unmapped holes ? And why should we make efforts when mapping to save the same amount of efforts when unmapping ? – Juergen Mar 24 '17 at 21:42
  • 1
    @Juergen mmaping can occur anywhere in the process's adress space, the kernel gets to choose where (although you can give it a hint about a preferred location). The only constraint is that enough space must be available. – lgeorget Mar 24 '17 at 22:18
  • 1
    Thank you all for your efforts. My conclusion is: There seem to be different reasons for those holes at different places/times. – Juergen Mar 24 '17 at 22:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.