8

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
Martin
  • 9,089
  • 11
  • 52
  • 87
  • Can you show the code of your `mmap` replacement? There might be something wrong with it. – Anton Kovalenko Feb 08 '13 at 18:07
  • I will as soon as possible. – Martin Feb 08 '13 at 18:08
  • are you sure you want to replace EVERY single mmap() call in your process with your own implementation? If you are using the LD_PRELOAD trick, that's exactly what will happen... – Forhad Ahmed Feb 08 '13 at 18:11
  • the replacement really only happens on well-defined conditions on pre identified fd's. In all the other cases the original mmap is called. actually the interception per-se is fine, I can get the shared object ,it's size, and I can also get the region start address and return it in mmap(). But once I read the memory after mmap() I get a seg fault. – Martin Feb 08 '13 at 18:18
  • The code that creates the boost:interprocess shared memory segment might be useful too - maybe you are never calling truncate()? – jmetcalfe Feb 08 '13 at 18:37
  • 1
    Is your `mmap()` replacement reentrant? Some things it may be doing (including printing debug output!) may themselves be triggering an allocation which is serviced via an anonymous `mmap()`. –  Feb 09 '13 at 00:37

1 Answers1

7

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.

jmetcalfe
  • 1,296
  • 9
  • 17