Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 393b4c0

Browse files
committedFeb 14, 2025
Auto merge of rust-lang#137025 - oli-obk:mmap, r=<try>
Lock mmapped files to at least get some safety out of it Unfortunately this only is a guarantee on windows. Double-unfortunately I don't know what's gonna happen when rustc segfaults on windows and a file is locked. Possibly the file is now deadlocked. Linux just locks file as a hint, so only tools that know about file locking will actually respect it, others will just access it. I guess if we had some sort of story for volatile memory we could use that as we're only reading bytes out of it and not actually mapping data structures to that memory.
2 parents d88ffcd + 57ff16e commit 393b4c0

File tree

10 files changed

+63
-83
lines changed

10 files changed

+63
-83
lines changed
 

‎compiler/rustc_codegen_llvm/src/back/lto.rs

+1-4
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,7 @@ fn prepare_lto(
112112
.extend(exported_symbols[&cnum].iter().filter_map(symbol_filter));
113113
}
114114

115-
let archive_data = unsafe {
116-
Mmap::map(std::fs::File::open(&path).expect("couldn't open rlib"))
117-
.expect("couldn't map rlib")
118-
};
115+
let archive_data = unsafe { Mmap::map(&path).expect("couldn't map rlib") };
119116
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
120117
let obj_files = archive
121118
.members()

‎compiler/rustc_codegen_ssa/src/back/archive.rs

+19-25
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,8 @@ pub trait ArchiveBuilderBuilder {
138138
bundled_lib_file_names: &FxIndexSet<Symbol>,
139139
) -> Result<(), ExtractBundledLibsError<'a>> {
140140
let archive_map = unsafe {
141-
Mmap::map(
142-
File::open(rlib)
143-
.map_err(|e| ExtractBundledLibsError::OpenFile { rlib, error: Box::new(e) })?,
144-
)
145-
.map_err(|e| ExtractBundledLibsError::MmapFile { rlib, error: Box::new(e) })?
141+
Mmap::map(rlib)
142+
.map_err(|e| ExtractBundledLibsError::MmapFile { rlib, error: Box::new(e) })?
146143
};
147144
let archive = ArchiveFile::parse(&*archive_map)
148145
.map_err(|e| ExtractBundledLibsError::ParseArchive { rlib, error: Box::new(e) })?;
@@ -363,7 +360,7 @@ pub fn try_extract_macho_fat_archive(
363360
sess: &Session,
364361
archive_path: &Path,
365362
) -> io::Result<Option<PathBuf>> {
366-
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
363+
let archive_map = unsafe { Mmap::map(&archive_path)? };
367364
let target_arch = match sess.target.arch.as_ref() {
368365
"aarch64" => object::Architecture::Aarch64,
369366
"x86_64" => object::Architecture::X86_64,
@@ -400,7 +397,7 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
400397
return Ok(());
401398
}
402399

403-
let archive_map = unsafe { Mmap::map(File::open(&archive_path)?)? };
400+
let archive_map = unsafe { Mmap::map(&archive_path)? };
404401
let archive = ArchiveFile::parse(&*archive_map)
405402
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
406403
let archive_index = self.src_archives.len();
@@ -463,25 +460,22 @@ impl<'a> ArArchiveBuilder<'a> {
463460
let mut entries = Vec::new();
464461

465462
for (entry_name, entry) in self.entries {
466-
let data =
467-
match entry {
468-
ArchiveEntry::FromArchive { archive_index, file_range } => {
469-
let src_archive = &self.src_archives[archive_index];
470-
471-
let data = &src_archive.1
472-
[file_range.0 as usize..file_range.0 as usize + file_range.1 as usize];
473-
474-
Box::new(data) as Box<dyn AsRef<[u8]>>
475-
}
476-
ArchiveEntry::File(file) => unsafe {
477-
Box::new(
478-
Mmap::map(File::open(file).map_err(|err| {
479-
io_error_context("failed to open object file", err)
480-
})?)
463+
let data = match entry {
464+
ArchiveEntry::FromArchive { archive_index, file_range } => {
465+
let src_archive = &self.src_archives[archive_index];
466+
467+
let data = &src_archive.1
468+
[file_range.0 as usize..file_range.0 as usize + file_range.1 as usize];
469+
470+
Box::new(data) as Box<dyn AsRef<[u8]>>
471+
}
472+
ArchiveEntry::File(file) => unsafe {
473+
Box::new(
474+
Mmap::map(file)
481475
.map_err(|err| io_error_context("failed to map object file", err))?,
482-
) as Box<dyn AsRef<[u8]>>
483-
},
484-
};
476+
) as Box<dyn AsRef<[u8]>>
477+
},
478+
};
485479

486480
entries.push(NewArchiveMember {
487481
buf: data,

‎compiler/rustc_codegen_ssa/src/back/link.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::collections::BTreeSet;
22
use std::ffi::OsString;
3-
use std::fs::{File, OpenOptions, read};
3+
use std::fs::{OpenOptions, read};
44
use std::io::{BufWriter, Write};
55
use std::ops::{ControlFlow, Deref};
66
use std::path::{Path, PathBuf};
@@ -680,8 +680,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
680680
}
681681

682682
fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
683-
let file = File::open(&path)?;
684-
let mmap = (unsafe { Mmap::map(file) })?;
683+
let mmap = (unsafe { Mmap::map(&path) })?;
685684
Ok(self.alloc_mmap(mmap))
686685
}
687686
}

‎compiler/rustc_codegen_ssa/src/back/metadata.rs

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
//! Reading of the rustc metadata for rlibs and dylibs
22
33
use std::borrow::Cow;
4-
use std::fs::File;
54
use std::io::Write;
65
use std::path::Path;
76

@@ -45,10 +44,7 @@ fn load_metadata_with(
4544
path: &Path,
4645
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
4746
) -> Result<OwnedSlice, String> {
48-
let file =
49-
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
50-
51-
unsafe { Mmap::map(file) }
47+
unsafe { Mmap::map(&path) }
5248
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
5349
.and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
5450
}

‎compiler/rustc_codegen_ssa/src/back/write.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -2142,11 +2142,9 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
21422142
) {
21432143
let filename = pre_lto_bitcode_filename(&module.name);
21442144
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
2145-
let file = fs::File::open(&bc_path)
2146-
.unwrap_or_else(|e| panic!("failed to open bitcode file `{}`: {}", bc_path.display(), e));
21472145

21482146
let mmap = unsafe {
2149-
Mmap::map(file).unwrap_or_else(|e| {
2147+
Mmap::map(&bc_path).unwrap_or_else(|e| {
21502148
panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
21512149
})
21522150
};

‎compiler/rustc_codegen_ssa/src/lib.rs

+6-8
Original file line numberDiff line numberDiff line change
@@ -276,24 +276,22 @@ impl CodegenResults {
276276
) -> Result<(Self, OutputFilenames), CodegenErrors> {
277277
// The Decodable machinery is not used here because it panics if the input data is invalid
278278
// and because its internal representation may change.
279-
if !data.starts_with(RLINK_MAGIC) {
279+
let Some(data) = data.strip_prefix(RLINK_MAGIC) else {
280280
return Err(CodegenErrors::WrongFileType);
281-
}
282-
let data = &data[RLINK_MAGIC.len()..];
283-
if data.len() < 4 {
281+
};
282+
283+
let Some((&version_array, data)) = data.split_first_chunk() else {
284284
return Err(CodegenErrors::EmptyVersionNumber);
285-
}
285+
};
286286

287-
let mut version_array: [u8; 4] = Default::default();
288-
version_array.copy_from_slice(&data[..4]);
289287
if u32::from_be_bytes(version_array) != RLINK_VERSION {
290288
return Err(CodegenErrors::EncodingVersionMismatch {
291289
version_array: String::from_utf8_lossy(&version_array).to_string(),
292290
rlink_version: RLINK_VERSION,
293291
});
294292
}
295293

296-
let Ok(mut decoder) = MemDecoder::new(&data[4..], 0) else {
294+
let Ok(mut decoder) = MemDecoder::new(data, 0) else {
297295
return Err(CodegenErrors::CorruptFile);
298296
};
299297
let rustc_version = decoder.read_str();

‎compiler/rustc_data_structures/src/memmap.rs

+24-15
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
use std::fs::File;
22
use std::io;
33
use std::ops::{Deref, DerefMut};
4+
use std::path::Path;
5+
6+
use crate::flock::Lock;
47

58
/// A trivial wrapper for [`memmap2::Mmap`] (or `Vec<u8>` on WASM).
69
#[cfg(not(any(miri, target_arch = "wasm32")))]
7-
pub struct Mmap(memmap2::Mmap);
10+
pub struct Mmap {
11+
map: memmap2::Mmap,
12+
_lock: Option<Lock>,
13+
}
814

915
#[cfg(any(miri, target_arch = "wasm32"))]
10-
pub struct Mmap(Vec<u8>);
16+
pub struct Mmap {
17+
map: Vec<u8>,
18+
}
1119

1220
#[cfg(not(any(miri, target_arch = "wasm32")))]
1321
impl Mmap {
@@ -17,27 +25,28 @@ impl Mmap {
1725
///
1826
/// However in practice most callers do not ensure this, so uses of this function are likely unsound.
1927
#[inline]
20-
pub unsafe fn map(file: File) -> io::Result<Self> {
28+
pub unsafe fn map(path: impl AsRef<Path>) -> io::Result<Self> {
29+
let path = path.as_ref();
30+
let file = File::open(path)?;
31+
let _lock = Some(Lock::new(path, true, false, false)?);
2132
// By default, memmap2 creates shared mappings, implying that we could see updates to the
2233
// file through the mapping. That would violate our precondition; so by requesting a
2334
// map_copy_read_only we do not lose anything.
2435
// This mapping mode also improves our support for filesystems such as cacheless virtiofs.
2536
// For more details see https://github.com/rust-lang/rust/issues/122262
2637
//
2738
// SAFETY: The caller must ensure that this is safe.
28-
unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file).map(Mmap) }
39+
40+
let map = unsafe { memmap2::MmapOptions::new().map_copy_read_only(&file)? };
41+
Ok(Self { _lock, map })
2942
}
3043
}
3144

3245
#[cfg(any(miri, target_arch = "wasm32"))]
3346
impl Mmap {
3447
#[inline]
35-
pub unsafe fn map(mut file: File) -> io::Result<Self> {
36-
use std::io::Read;
37-
38-
let mut data = Vec::new();
39-
file.read_to_end(&mut data)?;
40-
Ok(Mmap(data))
48+
pub unsafe fn map(path: impl AsRef<Path>) -> io::Result<Self> {
49+
Ok(Mmap(std::fs::read(path)?))
4150
}
4251
}
4352

@@ -46,13 +55,13 @@ impl Deref for Mmap {
4655

4756
#[inline]
4857
fn deref(&self) -> &[u8] {
49-
&self.0
58+
&self.map
5059
}
5160
}
5261

5362
impl AsRef<[u8]> for Mmap {
5463
fn as_ref(&self) -> &[u8] {
55-
&self.0
64+
&self.map
5665
}
5766
}
5867

@@ -77,8 +86,8 @@ impl MmapMut {
7786

7887
#[inline]
7988
pub fn make_read_only(self) -> std::io::Result<Mmap> {
80-
let mmap = self.0.make_read_only()?;
81-
Ok(Mmap(mmap))
89+
let map = self.0.make_read_only()?;
90+
Ok(Mmap { map, _lock: None })
8291
}
8392
}
8493

@@ -97,7 +106,7 @@ impl MmapMut {
97106

98107
#[inline]
99108
pub fn make_read_only(self) -> std::io::Result<Mmap> {
100-
Ok(Mmap(self.0))
109+
Ok(Mmap { map: self.0 })
101110
}
102111
}
103112

‎compiler/rustc_incremental/src/persist/file_format.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -95,18 +95,17 @@ pub(crate) fn read_file(
9595
is_nightly_build: bool,
9696
cfg_version: &'static str,
9797
) -> io::Result<Option<(Mmap, usize)>> {
98-
let file = match fs::File::open(path) {
99-
Ok(file) => file,
100-
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
101-
Err(err) => return Err(err),
102-
};
10398
// SAFETY: This process must not modify nor remove the backing file while the memory map lives.
10499
// For the dep-graph and the work product index, it is as soon as the decoding is done.
105100
// For the query result cache, the memory map is dropped in save_dep_graph before calling
106101
// save_in and trying to remove the backing file.
107102
//
108103
// There is no way to prevent another process from modifying this file.
109-
let mmap = unsafe { Mmap::map(file) }?;
104+
let mmap = match unsafe { Mmap::map(path) } {
105+
Ok(file) => file,
106+
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
107+
Err(err) => return Err(err),
108+
};
110109

111110
let mut file = io::Cursor::new(&*mmap);
112111

‎compiler/rustc_metadata/src/locator.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -822,13 +822,7 @@ fn get_metadata_section<'p>(
822822
}
823823
CrateFlavor::Rmeta => {
824824
// mmap the file, because only a small fraction of it is read.
825-
let file = std::fs::File::open(filename).map_err(|_| {
826-
MetadataError::LoadFailure(format!(
827-
"failed to open rmeta metadata: '{}'",
828-
filename.display()
829-
))
830-
})?;
831-
let mmap = unsafe { Mmap::map(file) };
825+
let mmap = unsafe { Mmap::map(filename) };
832826
let mmap = mmap.map_err(|_| {
833827
MetadataError::LoadFailure(format!(
834828
"failed to mmap rmeta metadata: '{}'",

‎compiler/rustc_metadata/src/rmeta/encoder.rs

+3-7
Original file line numberDiff line numberDiff line change
@@ -2245,12 +2245,10 @@ pub struct EncodedMetadata {
22452245
impl EncodedMetadata {
22462246
#[inline]
22472247
pub fn from_path(path: PathBuf, temp_dir: Option<MaybeTempDir>) -> std::io::Result<Self> {
2248-
let file = std::fs::File::open(&path)?;
2249-
let file_metadata = file.metadata()?;
2250-
if file_metadata.len() == 0 {
2248+
if std::fs::metadata(&path)?.len() == 0 {
22512249
return Ok(Self { mmap: None, _temp_dir: None });
22522250
}
2253-
let mmap = unsafe { Some(Mmap::map(file)?) };
2251+
let mmap = unsafe { Some(Mmap::map(path)?) };
22542252
Ok(Self { mmap, _temp_dir: temp_dir })
22552253
}
22562254

@@ -2272,9 +2270,7 @@ impl<D: Decoder> Decodable<D> for EncodedMetadata {
22722270
let len = d.read_usize();
22732271
let mmap = if len > 0 {
22742272
let mut mmap = MmapMut::map_anon(len).unwrap();
2275-
for _ in 0..len {
2276-
(&mut mmap[..]).write_all(&[d.read_u8()]).unwrap();
2277-
}
2273+
mmap.copy_from_slice(d.read_raw_bytes(len));
22782274
mmap.flush().unwrap();
22792275
Some(mmap.make_read_only().unwrap())
22802276
} else {

0 commit comments

Comments
 (0)
Failed to load comments.