Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mmap() with LD_PRELOAD and boost::interprocess does not work

Tags:

c++

c

boost

glibc

libc

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
like image 730
Martin Avatar asked Feb 08 '13 18:02

Martin


1 Answers

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.

like image 88
jmetcalfe Avatar answered Oct 07 '22 18:10

jmetcalfe