I am trying to replace the original mmap()
system call on a pre-identified fd via LD_PRELOAD
, so that the process calling it can read a shared memory object created previously by another process with boost::interprocess
. Everything goes well, except when I finally try to read the mmap'ed memory. In that case the first process aborts with a segmentation fault. What could the reason be? I don't need write permissions on the shared memory object.
This is the code in the pre-loaded library:
void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset) {
static void* (*o_mmap) ( void *, size_t, int, int, int, off_t ) =
o_mmap = (void*(*)( void *, size_t, int, int, int, off_t )) dlsym(RTLD_NEXT, "mmap");
if (!o_mmap)
std::cout << "mmap() preload failed\n";
if (fd != my_fd)
return (*o_mmap)( start, length, prot, flags, fd, offset );
interprocess::shared_memory_object shm (interprocess::open_only, "obj", interprocess::read_only);
interprocess::mapped_region region(shm, interprocess::read_only, 0, length, start);
std::cout << "mmap() overridden. addr =" << region.get_address() << " length: " << region.get_size() << " start: " << start << "\n";
return region.get_address();
}
The code of the program creating the shared memory object is:
//Create a shared memory object.
shared_memory_object shm (create_only, "obj", read_write);
//Set size
shm.truncate(1000);
//Map the whole shared memory in this process
mapped_region region(shm, read_write);
//Write all the memory to 1
std::memset(region.get_address(), 1, region.get_size());
The code of the program (which segfaults) trying to read the shared memory above is:
int fd = open(my_file, O_RDONLY);
void* addr = mmap(0, 1000, PROT_READ, MAP_SHARED, fd, 0); // Okay
//Check that memory was initialized to 1
char *mem = static_cast<char*>(addr);
for(std::size_t i = 0; i < 1000; ++i)
if(*mem++ != 1) // SEGFAULT!
return 1; //Error checking memory
Your problem is that you are effectively returning a reference to a local, but in a slightly obfuscated way. Your mmap() override has a interprocess::shared_memory_object
and interprocess::mapped_region
on the stack, which are destroyed when you return to the client. During destruction, the boost wrappers will unmap the memory area, so it is no longer valid to access it in your client code. As a simple fix, making these variables static would prevent the seg fault, though depending on the structure of your application a more complicated solution might be needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With