Skip to content

Commit 9b3d926

Browse files
committed
Mark Mmap::map as safe
1 parent dba7216 commit 9b3d926

File tree

7 files changed

+37
-32
lines changed

7 files changed

+37
-32
lines changed

compiler/rustc_codegen_llvm/src/back/lto.rs

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

116-
let archive_data = unsafe { Mmap::map(&path).expect("couldn't map rlib") };
116+
let archive_data = Mmap::map(&path).expect("couldn't map rlib");
117117
let archive = ArchiveFile::parse(&*archive_data).expect("wanted an rlib");
118118
let obj_files = archive
119119
.members()

compiler/rustc_codegen_ssa/src/back/archive.rs

+8-12
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,8 @@ pub trait ArchiveBuilderBuilder {
137137
outdir: &Path,
138138
bundled_lib_file_names: &FxIndexSet<Symbol>,
139139
) -> Result<(), ExtractBundledLibsError<'a>> {
140-
let archive_map = unsafe {
141-
Mmap::map(rlib)
142-
.map_err(|e| ExtractBundledLibsError::MmapFile { rlib, error: Box::new(e) })?
143-
};
140+
let archive_map = Mmap::map(rlib)
141+
.map_err(|e| ExtractBundledLibsError::MmapFile { rlib, error: Box::new(e) })?;
144142
let archive = ArchiveFile::parse(&*archive_map)
145143
.map_err(|e| ExtractBundledLibsError::ParseArchive { rlib, error: Box::new(e) })?;
146144

@@ -360,7 +358,7 @@ pub fn try_extract_macho_fat_archive(
360358
sess: &Session,
361359
archive_path: &Path,
362360
) -> io::Result<Option<PathBuf>> {
363-
let archive_map = unsafe { Mmap::map(&archive_path)? };
361+
let archive_map = Mmap::map(&archive_path)?;
364362
let target_arch = match sess.target.arch.as_ref() {
365363
"aarch64" => object::Architecture::Aarch64,
366364
"x86_64" => object::Architecture::X86_64,
@@ -397,7 +395,7 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> {
397395
return Ok(());
398396
}
399397

400-
let archive_map = unsafe { Mmap::map(&archive_path)? };
398+
let archive_map = Mmap::map(&archive_path)?;
401399
let archive = ArchiveFile::parse(&*archive_map)
402400
.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
403401
let archive_index = self.src_archives.len();
@@ -469,12 +467,10 @@ impl<'a> ArArchiveBuilder<'a> {
469467

470468
Box::new(data) as Box<dyn AsRef<[u8]>>
471469
}
472-
ArchiveEntry::File(file) => unsafe {
473-
Box::new(
474-
Mmap::map(file)
475-
.map_err(|err| io_error_context("failed to map object file", err))?,
476-
) as Box<dyn AsRef<[u8]>>
477-
},
470+
ArchiveEntry::File(file) => Box::new(
471+
Mmap::map(file)
472+
.map_err(|err| io_error_context("failed to map object file", err))?,
473+
) as Box<dyn AsRef<[u8]>>,
478474
};
479475

480476
entries.push(NewArchiveMember {

compiler/rustc_codegen_ssa/src/back/link.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -578,7 +578,7 @@ fn link_dwarf_object(sess: &Session, cg_results: &CodegenResults, executable_out
578578
}
579579

580580
fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
581-
let mmap = (unsafe { Mmap::map(&path) })?;
581+
let mmap = Mmap::map(&path)?;
582582
Ok(self.alloc_mmap(mmap))
583583
}
584584
}

compiler/rustc_codegen_ssa/src/back/metadata.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ fn load_metadata_with(
4343
path: &Path,
4444
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
4545
) -> Result<OwnedSlice, String> {
46-
unsafe { Mmap::map(&path) }
46+
Mmap::map(&path)
4747
.map_err(|e| format!("failed to mmap file '{}': {}", path.display(), e))
4848
.and_then(|mmap| try_slice_owned(mmap, |mmap| f(mmap)))
4949
}

compiler/rustc_codegen_ssa/src/back/write.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -2152,11 +2152,8 @@ pub(crate) fn submit_pre_lto_module_to_llvm<B: ExtraBackendMethods>(
21522152
let filename = pre_lto_bitcode_filename(&module.name);
21532153
let bc_path = in_incr_comp_dir_sess(tcx.sess, &filename);
21542154

2155-
let mmap = unsafe {
2156-
Mmap::map(&bc_path).unwrap_or_else(|e| {
2157-
panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e)
2158-
})
2159-
};
2155+
let mmap = Mmap::map(&bc_path)
2156+
.unwrap_or_else(|e| panic!("failed to mmap bitcode file `{}`: {}", bc_path.display(), e));
21602157
// Schedule the module to be loaded
21612158
drop(tx_to_llvm_workers.send(Box::new(Message::AddImportOnlyModule::<B> {
21622159
module_data: SerializedModule::FromUncompressedFile(mmap),

compiler/rustc_data_structures/src/memmap.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,32 @@ pub struct Mmap(Vec<u8>);
1212

1313
#[cfg(not(any(miri, target_arch = "wasm32")))]
1414
impl Mmap {
15-
/// # Safety
16-
///
1715
/// The given file must not be mutated (i.e., not written, not truncated, ...) until the mapping is closed.
1816
///
19-
/// However in practice most callers do not ensure this, so uses of this function are likely unsound.
17+
/// This process must not modify nor remove the backing file while the memory map lives.
18+
/// For the dep-graph and the work product index, it is as soon as the decoding is done.
19+
/// For the query result cache, the memory map is dropped in save_dep_graph before calling
20+
/// save_in and trying to remove the backing file.
21+
///
22+
/// There is no way to prevent another process from modifying this file.
23+
///
24+
/// This means in practice all uses of this function are theoretically unsound, but also
25+
/// the way rustc uses `Mmap` (reading bytes, validating them afterwards *anyway* to detect
26+
/// corrupted files) avoids the actual issues this could cause.
27+
///
28+
/// Someone may truncate our file, but then we'll SIGBUS, which is not great, but at least
29+
/// we won't succeed with corrupted data.
30+
///
31+
/// To get a bit more hardening out of this we will set the file as readonly before opening it.
2032
#[inline]
21-
pub unsafe fn map(path: impl AsRef<Path>) -> io::Result<Self> {
33+
pub fn map(path: impl AsRef<Path>) -> io::Result<Self> {
34+
let path = path.as_ref();
35+
let mut perms = std::fs::metadata(path)?.permissions();
36+
perms.set_readonly(true);
37+
std::fs::set_permissions(path, perms)?;
38+
2239
let file = File::open(path)?;
40+
2341
// By default, memmap2 creates shared mappings, implying that we could see updates to the
2442
// file through the mapping. That would violate our precondition; so by requesting a
2543
// map_copy_read_only we do not lose anything.
@@ -34,7 +52,7 @@ impl Mmap {
3452
#[cfg(any(miri, target_arch = "wasm32"))]
3553
impl Mmap {
3654
#[inline]
37-
pub unsafe fn map(path: impl AsRef<Path>) -> io::Result<Self> {
55+
pub fn map(path: impl AsRef<Path>) -> io::Result<Self> {
3856
Ok(Mmap(std::fs::read(path)?))
3957
}
4058
}

compiler/rustc_incremental/src/persist/file_format.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,7 @@ pub(crate) fn read_file(
9595
is_nightly_build: bool,
9696
cfg_version: &'static str,
9797
) -> io::Result<Option<(Mmap, usize)>> {
98-
// SAFETY: This process must not modify nor remove the backing file while the memory map lives.
99-
// For the dep-graph and the work product index, it is as soon as the decoding is done.
100-
// For the query result cache, the memory map is dropped in save_dep_graph before calling
101-
// save_in and trying to remove the backing file.
102-
//
103-
// There is no way to prevent another process from modifying this file.
104-
let mmap = match unsafe { Mmap::map(path) } {
98+
let mmap = match Mmap::map(path) {
10599
Ok(file) => file,
106100
Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(None),
107101
Err(err) => return Err(err),

0 commit comments

Comments
 (0)