Search code examples
c++boostshared-memoryinterprocess

processes needs remap when one process truncate the shared memory created by boost interprocess library


Boost interprocess shared memory needs remap also get address again when one of processes truncates shared memory for dynamically growing size. Codes are below and in real cases consumer mapping can get to know the new bound of memory created by productor trunc for each time. However when larger memory created by trunc, mapping will crash when input bigger offset to mapping.

./trunc 10
./mapping
input 9, output is 9.
./trunc 10000, 
input 9999 to mapping process, then segmentation fault.

trunc.cpp

#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bi = boost::interprocess;

int main(int argc, char* argv[]) {
    bi::shared_memory_object shm(bi::open_or_create, "testshm", bi::read_write);
    shm.truncate(sizeof(int) * std::atoi(argv[1]));
    bi::mapped_region reg(shm, bi::read_write, 0);
    int* p = (int*)reg.get_address();
    for(std::size_t i = 0; i < std::atoi(argv[1]); ++i)
        p[i] = i;

    return 0;
}

mapping.cpp

#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bi = boost::interprocess;

int main(int argc, char* argv[]) {

    bi::shared_memory_object shm(bi::open_only, "testshm", bi::read_only);
    bi::mapped_region reg(shm, bi::read_only, 0);
    int* p = (int*)reg.get_address();
    do {
        std::cout << "Please input offset:" << std::endl;
        int offset;
        std::cin >> offset;
        std::cout << "Integer @" << offset << " is " << p[offset] << std::endl;


    } while(true);
    return 0;
}

Solution

  • It doesn't happen like that on my system.

    Sadly, I can't show you live on Coliru (because shared memory is not supported), but you can perhaps retest with the following code:

    #include <iostream>
    #include <boost/interprocess/shared_memory_object.hpp>
    #include <boost/interprocess/mapped_region.hpp>
    
    namespace bi = boost::interprocess;
    
    static char const* const SHM_NAME = "sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4";
    
    int main(int argc, char** argv) {
        if (argc>1) {
            bi::shared_memory_object shm(bi::open_or_create, SHM_NAME, bi::read_write);
    
            shm.truncate(sizeof(int) * std::atoi(argv[1]));
            bi::mapped_region reg(shm, bi::read_write);
    
            int* p = reinterpret_cast<int*>(reg.get_address());
    
            for(int i = 0; i < std::atoi(argv[1]); ++i)
                p[i] = i;
    
            std::cout << "Truncated and filled to " << reg.get_size() << "\n";
        } else {
            bi::shared_memory_object shm(bi::open_only, SHM_NAME, bi::read_only);
            bi::mapped_region reg(shm, bi::read_only, 0);
    
            size_t N = reg.get_size() / 4;
            int const* p = reinterpret_cast<int const*>(reg.get_address());
    
            size_t index;
            while (std::cout << "Please input index: " && std::cin >> index) {
                if (index < N)
                    std::cout << "Integer @" << index << " is " << p[index] << "\n";
                else
                    std::cout << "Index " << index << " out of bounds [0.." << N << ")\n";
            }
            std::cout << "Bye\n";
        }
    }
    

    It mostly changes minor things:

    • the name
    • checking the size as truncated/before indexing
    • spelling reinterpret_cast
    • const-correctness
    • combining trunc and mapping into a single file

    I test it with:

    Test Case 1: trunc 10

    ./sotest 10
    xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
    ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    ./sotest <<< "0 1 2 3 999 9999 10000"
    

    Output:

    Truncated and filled to 40
    00000000: 0000 0000 0100 0000 0200 0000 0300 0000  ................
    00000010: 0400 0000 0500 0000 0600 0000 0700 0000  ................
    00000020: 0800 0000 0900 0000                      ........
    -rw-r--r-- 1 sehe sehe 40 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    Please input index: Integer @0 is 0
    Please input index: Integer @1 is 1
    Please input index: Integer @2 is 2
    Please input index: Integer @3 is 3
    Please input index: Index 999 out of bounds [0..10)
    Please input index: Index 9999 out of bounds [0..10)
    Please input index: Index 10000 out of bounds [0..10)
    Please input index: Bye
    

    Test Case 1: trunc 10000

    sotest 10000
    xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
    ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    ./sotest <<< "0 1 2 3 999 9999 10000"
    

    Output:

    Truncated and filled to 40000
    00009bf0: fc26 0000 fd26 0000 fe26 0000 ff26 0000  .&...&...&...&..
    00009c00: 0027 0000 0127 0000 0227 0000 0327 0000  .'...'...'...'..
    00009c10: 0427 0000 0527 0000 0627 0000 0727 0000  .'...'...'...'..
    00009c20: 0827 0000 0927 0000 0a27 0000 0b27 0000  .'...'...'...'..
    00009c30: 0c27 0000 0d27 0000 0e27 0000 0f27 0000  .'...'...'...'..
    -rw-r--r-- 1 sehe sehe 40000 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    Please input index: Integer @0 is 0
    Please input index: Integer @1 is 1
    Please input index: Integer @2 is 2
    Please input index: Integer @3 is 3
    Please input index: Integer @999 is 999
    Please input index: Integer @9999 is 9999
    Please input index: Index 10000 out of bounds [0..10000)
    Please input index: Bye
    

    Test Case 1: trunc 10001

    sotest 10001
    xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
    ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    ./sotest <<< "0 1 2 3 999 9999 10000"
    

    Output:

    Truncated and filled to 40004
    00009c00: 0027 0000 0127 0000 0227 0000 0327 0000  .'...'...'...'..
    00009c10: 0427 0000 0527 0000 0627 0000 0727 0000  .'...'...'...'..
    00009c20: 0827 0000 0927 0000 0a27 0000 0b27 0000  .'...'...'...'..
    00009c30: 0c27 0000 0d27 0000 0e27 0000 0f27 0000  .'...'...'...'..
    00009c40: 1027 0000                                .'..
    -rw-r--r-- 1 sehe sehe 40004 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
    Please input index: Integer @0 is 0
    Please input index: Integer @1 is 1
    Please input index: Integer @2 is 2
    Please input index: Integer @3 is 3
    Please input index: Integer @999 is 999
    Please input index: Integer @9999 is 9999
    Please input index: Integer @10000 is 10000
    Please input index: Bye
    

    If that gives different results on your system, let me know. Also, report platform details/versions used that case.