How to create and write to memory mapped files?

mkhq

Editor's note: This code example is from a version of Rust prior to 1.0 and the code it uses does not exist in Rust 1.0. Some answers have been updated to answer the core question for newer versions of Rust.

I'm trying to create a memory mapped file using std::os::MemoryMap. The current approach looks as follows:

use std::os;
use std::ptr;
use std::old_io as io;
use std::os::unix::prelude::AsRawFd;
use std::os::MapOption;

let path = Path::new("test.mmap");

let f = match io::File::open_mode(&path, io::Open, io::ReadWrite) {
    Ok(f) => f,
    Err(err) => panic!("Could not open file: {}", err),
};

let mmap_opts = &[
    MapOption::MapReadable,
    MapOption::MapWritable,
    MapOption::MapFd(f.as_raw_fd())
];

let mmap = match os::MemoryMap::new(1024*1024, mmap_opts) {
    Ok(mmap) => {
        println!("Successfully created the mmap: {}", mmap.len());
        mmap
    }
    Err(err) => panic!("Could not read the mmap: {}", err),
};

unsafe {
   let data = mmap.data();

    if data.is_null() {
        panic!("Could not access data from memory mapped file")
    }

    let src = "Hello!";
    ptr::copy_memory(data, src.as_ptr(), src.as_bytes().len());
}

This program fails with

Process didn't exit successfully: `target/mmap` (status=4)

when calling ptr::copy_memory or any other operations on data.

  • What is the reason I cannot write (or read) the data from the MemoryMap?
  • What is the correct way to use MemoryMap in Rust?
Shepmaster

The real answer is to use a crate that provides this functionality, ideally in a cross-platform manner.

use memmap; // 0.7.0
use std::{
    fs::OpenOptions,
    io::{Seek, SeekFrom, Write},
};

const SIZE: u64 = 1024 * 1024;

fn main() {
    let src = "Hello!";

    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("test.mmap")
        .expect("Unable to open file");

    // Allocate space in the file first
    f.seek(SeekFrom::Start(SIZE)).unwrap();
    f.write_all(&[0]).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();

    let mut data = unsafe {
        memmap::MmapOptions::new()
            .map_mut(&f)
            .expect("Could not access data from memory mapped file")
    };

    data[..src.len()].copy_from_slice(src.as_bytes());
}

Note that this is still possible for this code to lead to undefined behavior. Since the slice is backed by a file, the contents of the file (and thus the slice) may change from outside of the Rust program, breaking the invariants that the unsafe block is supposed to hold. The programmer needs to ensure that the file doesn't change during the lifetime of the map. Unfortunately, the crate itself does not provide much assistance to prevent this from happening or even any documentation warning the user.


If you wish to use lower-level system calls, you are missing two main parts:

  1. mmap doesn't allocate any space on its own, so you need to set some space in the file. Without this, I get Illegal instruction: 4 when running on macOS.

  2. MemoryMap (was) private by default so you need to mark the mapping as public so that changes are written back to the file (I'm assuming you want the writes to be saved). Without this, the code runs, but the file is never changed.

Here's a version that works for me:

use libc; // 0.2.67
use std::{
    fs::OpenOptions,
    io::{Seek, SeekFrom, Write},
    os::unix::prelude::AsRawFd,
    ptr,
};

fn main() {
    let src = "Hello!";

    let size = 1024 * 1024;

    let mut f = OpenOptions::new()
        .read(true)
        .write(true)
        .create(true)
        .open("test.mmap")
        .expect("Unable to open file");

    // Allocate space in the file first
    f.seek(SeekFrom::Start(size as u64)).unwrap();
    f.write_all(&[0]).unwrap();
    f.seek(SeekFrom::Start(0)).unwrap();

    // This refers to the `File` but doesn't use lifetimes to indicate
    // that. This is very dangerous, and you need to be careful.
    unsafe {
        let data = libc::mmap(
            /* addr: */ ptr::null_mut(),
            /* len: */ size,
            /* prot: */ libc::PROT_READ | libc::PROT_WRITE,
            // Then make the mapping *public* so it is written back to the file
            /* flags: */ libc::MAP_SHARED,
            /* fd: */ f.as_raw_fd(),
            /* offset: */ 0,
        );

        if data == libc::MAP_FAILED {
            panic!("Could not access data from memory mapped file")
        }

        ptr::copy_nonoverlapping(src.as_ptr(), data as *mut u8, src.len());
    }
}

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Linux memory mapped files

What are memory mapped files?

How do I write to a memory-mapped address in Rust?

How to work with memory mapped files (numpy.memmap) in PyFilesystem?

How to share memory mapped files between Python and another language?

Memory-mapped files in Java

Linking boost memory mapped files

Java Memory-mapped files?

Atomic operations on memory mapped files

Are multiple memory mapped files bugged?

How to flush memory-mapped files using Boost's `mapped_file_sink` class?

How to create pdf files in memory

Are there any persistence guarantees when using memory mapped files or plain Stream.Write

c++ boost write memory mapped file

How is integer literal mapped in memory?

Monitoring page cache / memory mapped files access

Memory-mapped files: pros and cons?

Named memory-mapped files in Python?

memory mapped files and pointers to volatile objects

How do I communicate between a server and a client on the same computer using memory mapped files?

Boost Memory Mapped File : Read-Write Access

Bus Error when trying to write data into memory mapped file

WRITE and READ memory mapped device registers in Linux on ARM

What happens when I write to a memory-mapped register?

How to validate code that read/write to hardware memory mapped registers (mmio) with frama-c Eva plugin or WP-RTE?

How memory is mapped to gpu (opencl Intel graphics)

How To Use Memory Mapped File in Python Linux

How to write a query for one to many mapped records

Is it possible to store python objects (specifically sklearn models) in memory mapped files?