Reading the POSIX standard for Unix functions is not straightforward
I recently wrote about exploring
munmap() on page zero, and in the process looked at the POSIX specification
One of my discoveries about the practical behavior of Unixes here
is that OpenBSD specifically disallows using
munmap() on address
space that isn't currently mapped (see
munmap(2)). In my entry, I said that it
wasn't clear whether POSIX strictly authorized this behavior,
although you could put forward an interpretation where it was okay.
In a comment, Jakob Kaivo put forward
the view that POSIX permitted this and any other behavior for when
munmap() was applied to unmapped address space because of a
sentence in the end of the Description:
The behavior of this function is unspecified if the mapping was not established by a call to
At first reading this seems clear. But wait, it's time to get confused.
Earlier in the same description of
munmap()'s behavior, POSIX clearly
says that it can be used if there is no mapping:
[...] If there are no mappings in the specified address range, then
munmap()has no effect.
(Note that 'has no effect' is different from 'unspecified'.)
POSIX doesn't require that this not raise an error, but you can
read its description of when you can get
EINVAL to require that
you don't (some of the time). Assuming
addr is aligned and
is not zero, you get EINVAL if some of the address space you're
unmapping is 'outside the valid range for the address space of a
process', and perhaps implicitly not otherwise. And then you have
the question of what POSIX intended here by saying 'a process space'
instead of 'the (current) process'.
One of the things we can see here is that it's hard for non-specialists to truly read and understand the POSIX standards. Both Jakob Kaivo and I are at least reasonably competent C and Unix programmers and we've both attempted to read a reasonably straightforward POSIX specification of a single function, yet we've wound up somewhere between disagreeing and being uncertain about what it allows.
This is a useful lesson for me to remember any time I'm tempted to appeal to a POSIX standard for how something should work. POSIX standards are written in specifications language, and if they're not completely clear I should be cautious about how correct I am. Probably I should be cautious even if they seem perfectly clear.
(And anyway, the actual behavior of current Unixes matters more than what POSIX says. A POSIX specification is merely a potential lower bound on behavior, especially future behavior. If a Unix does something today and that something is required by POSIX, the odds are good that it will keep doing that in the future.)
PS: My interpretation of the unspecified behavior versus 'no behavior'
here is that POSIX is saying that it's unspecified what happens if
munmap() legitimate address space that wasn't obtained through
mmap(). For instance, if you
munmap() part of something
that you got with
malloc(), anything goes as far as POSIX is
concerned. It might work and not produce future problems, it might
have no effect, it might kill your program immediately, and it might
cause your program to malfunction or blow up in the future.