Subject: Zero-length mmaps
To: None <>
From: Peter Bex <>
List: tech-kern
Date: 08/20/2006 15:06:24
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable


I'm afraid the following mail is a little long, but the problem
needs some background to explain (or I'm just bad with words),
so please bear with me.

While working on a port of Valgrind to NetBSD (,
we ran into a problem with mmaps of size 0.  As some of you may know,
Valgrind traces memory usage and allocation, so it needs to intercept
mmap calls, among other things.

When an ELF binary is loaded, ld.elf_so's map_object.c does an mmap
of the bss segment.  It gets the size of the segment by looking at
the PHDR structure's second PT_LOAD entry.  It looks like the following:
  base_vlimit =3D round_up(segs[1]->p_vaddr + segs[1]->p_memsz);
  data_vlimit =3D round_up(segs[1]->p_vaddr + segs[1]->p_filesz);

In a typical program, the difference between p_memsz and p_filesz is
only 0x20.  These rounded up segment values (segments are > 0x20 bytes)
are the same, thus.  Because of this, the following piece of code will
call mmap with a zero length:
 if (mmap(mapbase + data_vlimit - base_vaddr, base_vlimit - data_vlimit,
      data_flags, MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0) =3D=3D
      MAP_FAILED) {
	_rtld_error("mmap of bss failed: %s", xstrerror(errno));
	goto bad;

The kernel then proceeds to simply map a full page (sys/uvm/uvm_mmap.c)

The Valgrind code says:
   if (arg2 < 0 ) {
	/* SuSV3 says: If len is zero, mmap() shall fail and no mapping
	    shall be established. */
	return VG_(mk_SysRes_Error)( VKI_EINVAL );
When we look at,
I don't see these exact words, but I do see the following:
    If a MAP_FIXED request is successful, the mapping established by
    mmap() replaces any previous mappings for the process' pages in
    the range [pa,pa+len).
If the len argument is 0, this amounts to as much as [pa,pa), which
would make no sense mathematically.  I can only conclude that
Valgrind's comment is a correct summary of SUSv3.

Stevens (Advanced Programming in the Unix Environment) states the
following (p410):
    Since the starting offset of the mapped file is tied to the system's
    virtual memory page size, what happens if the length of the mapped
    region isn't a multiple of the page size?
    Assume the file size is 12 bytes and the system's page size is 512
    bytes.  In this case the system normally provides a mapped region
    of 512 bytes and the final 500 bytes of this region are set to 0.
    We can modify the final 500 bytes, but any changes we make to them
    are not reflected in the file.

NetBSD's behavior seems to fit Stevens' description more than SUSv3.

There's also an unclosed PR kern/2801, which mentions that zero-length
mmap emulation for Solaris is wrong.  This is the same thing in a
different guise.

The bottom line questions are: is NetBSD correct in implementing SUSv3,
if it's incorrect, should it be fixed, and what should Valgrind do in
this case?  Should it behave differently on NetBSD than on Linux?
After all, a program that worked fine under NetBSD might just fail
under any other Unix, if its mmap works differently.

"The process of preparing programs for a digital computer
 is especially attractive, not only because it can be economically
 and scientifically rewarding, but also because it can be an aesthetic
 experience much like composing poetry or music."
							-- Donald Knuth

Content-Type: application/pgp-signature
Content-Disposition: inline

Version: GnuPG v1.4.5 (NetBSD)