Consider the following code fragment:
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <fcntl.h>
int fd = open( "/path/to/existing/file/or/device", O_RDONLY);
int numberOfWords = 4096; // chosen to be smaller than file size
int* data = mmap( NULL, nomberOfWords * sizeof(int), PROT_READ, MAP_SHARED, fd, 0);
if (data != MAP_FAILED) {
printf( "%d\n", data[0]);
// oops, forgot to munmap
close(fd);
printf( "%d\n", data[0]); // <-- why doesn't this segfault
}
Background
I am working with a custom kernel driver that uses ioctl()
to setup for DMA, and ultimately requires user space to use mmap()
to access a particular buffer.
While developing unit tests I discovered accidentally that after closing the file descriptor without calling munmap
first, it was still possible to access the buffer memory in user space with the mmap'ed pointer. Thinking there was some bug in the driver I wrote a small program similar to that shown here to exercise mmap() with a "normal" file.
What I was expecting to see is a segfault on the read after close, my thinking being, that the kernel would automatically munmap()
the pages associated with the file descriptor when the use of the open file descriptor was closed, similar to how it happens when the process is terminated.
Instead, I was able to keep using the pointer. This was a bit surprising as I have been using mmap()
for several years, I must have been smart (more likely lucky) enough to avoid bugs that would expose this situation. Nothing was obvious in the mmap
man page.
Problem
Ideally our driver will need to cause a segfault in user space if this happens, because we don't want a buggy user space program writing to the memory of interest.
So, is this behaviour the same across different *nix? In the given example, would it take say deleting the file to cause a segfault? Or perhaps flushing the vm caches?