Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Jun 2006 18:22:46 +0200
From:      Bruno Haible <bruno@clisp.org>
To:        hackers@freebsd.org
Cc:        Vasil Dimov <vd@freebsd.org>
Subject:   valid VMA ranges and mincore()
Message-ID:  <200606101822.46437.bruno@clisp.org>

next in thread | raw e-mail | index | archive | help
Hi memory management hackers,

The mincore(2) system call is, on FreeBSD, not usable for some purposes
for which it can be used on other platforms. Let me explain the purpose,
the problem and two proposed solutions.


The purpose
===========

The task at hand is to enumerate the VMAs of the current process.
In other words, determine which address ranges are mapped and which aren't.
If the /proc filesystem is available, the /proc/curproc/map file
can be opened and parsed; it contains the necessary information.
But I'm being told that /proc is not mounted by default, and as an
application developer I have no control over that. So, I must look for
a solution that works also when /proc is not mounted.

The purpose of this task can be
  a) To detect whether a SIGSEGV is actually a stack overflow, a
     write access to a read-only memory page, or simply a bug in
     the program. If the fault address is near to the stack segment,
     it's likely a stack overflow; if it's nearer to a data segment,
     it's more likely a bug.
  b) To choose optimal addresses for mmap with MAP_FIXED that obey
     some constraints about lengths and bit patterns.

Ideally the OS would have a system call that allows to iterate over
the VMAs of the current process (corresponding to the lines of
/proc/curproc/map), or to retrieve the list of VMAs as a big array.

Lacking such a system call, on platforms other than FreeBSD, for example
NetBSD, I can use mincore() instead.


The problem
===========

On NetBSD, Linux, Solaris, mincore() applied to a range of addresses that
is partially not mapped, returns -1 with errno set to ENOMEM. See

  NetBSD:  
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/sys/mincore.2?rev=1.19&content-type=text/plain
  Linux:    http://linux.about.com/library/cmd/blcmdl2_mincore.htm
  Solaris:  http://docs.sun.com/app/docs/doc/816-5167/6mbb2jaib?a=view

This is consistent with mprotect(), which also fails with errno = ENOMEM
if the address range is not fully mapped.

FreeBSD doesn't work this way: it fills 0 values into the array passed
as argument instead, a 0 for each unmapped page. This makes it impossible
to distinguish
   a page which is valid address range but currently swapped out
from
   a page which is unmapped.

As a consequence, mincore() does not help for the aforementioned purpose.


Proposals
=========

Alternatively:

Proposal 1: Change mincore() to behave like the one on NetBSD, Linux,
Solaris.

Proposal 2: Define a new constant MINCORE_MAPPED != 0, and change mincore()
to set the per-page value to
   - MINCORE_MAPPED for a page that is mapped but swapped out,
   - 0 for a page which is unmapped address range.

Proposal 1 would have the advantage to lead to the same code across
platforms.

Proposal 2 would have the advantage to be backward compatible.


Can you do something about this?

           Bruno  (an application programmer, not a FreeBSD kernel hacker)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200606101822.46437.bruno>