Coverage Report

Created: 2026-06-30 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/blake3-1.8.4/src/io.rs
Line
Count
Source
1
//! Helper functions for efficient IO.
2
3
#[cfg(feature = "std")]
4
0
pub(crate) fn copy_wide(
5
0
    mut reader: impl std::io::Read,
6
0
    hasher: &mut crate::Hasher,
7
0
) -> std::io::Result<u64> {
8
0
    let mut buffer = [0; 65536];
9
0
    let mut total = 0;
10
    loop {
11
0
        match reader.read(&mut buffer) {
12
0
            Ok(0) => return Ok(total),
13
0
            Ok(n) => {
14
0
                hasher.update(&buffer[..n]);
15
0
                total += n as u64;
16
0
            }
17
            // see test_update_reader_interrupted
18
0
            Err(e) if e.kind() == std::io::ErrorKind::Interrupted => continue,
19
0
            Err(e) => return Err(e),
20
        }
21
    }
22
0
}
23
24
// Mmap a file, if it looks like a good idea. Return None in cases where we know mmap will fail, or
25
// if the file is short enough that mmapping isn't worth it. However, if we do try to mmap and it
26
// fails, return the error.
27
//
28
// SAFETY: Mmaps are fundamentally unsafe, because you can call invariant-checking functions like
29
// str::from_utf8 on them and then have them change out from under you. Letting a safe caller get
30
// their hands on an mmap, or even a &[u8] that's backed by an mmap, is unsound. However, because
31
// this function is crate-private, we can guarantee that all can ever happen in the event of a race
32
// condition is that we either hash nonsense bytes or crash with SIGBUS or similar, neither of
33
// which should risk memory corruption in a safe caller.
34
//
35
// PARANOIA: But a data race...is a data race...is a data race...right? Even if we know that no
36
// platform in the "real world" is ever going to do anything other than compute the "wrong answer"
37
// if we race on this mmap while we hash it, aren't we still supposed to feel bad about doing this?
38
// Well, maybe. This is IO, and IO gets special carve-outs in the memory model. Consider a
39
// memory-mapped register that returns random 32-bit words. (This is actually realistic if you have
40
// a hardware RNG.) It's probably sound to construct a *const i32 pointing to that register and do
41
// some raw pointer reads from it. Those reads should be volatile if you don't want the compiler to
42
// coalesce them, but either way the compiler isn't allowed to just _go nuts_ and insert
43
// should-never-happen branches to wipe your hard drive if two adjacent reads happen to give
44
// different values. As far as I'm aware, there's no such thing as a read that's allowed if it's
45
// volatile but prohibited if it's not (unlike atomics). As mentioned above, it's not ok to
46
// construct a safe &i32 to the register if you're going to leak that reference to unknown callers.
47
// But if you "know what you're doing," I don't think *const i32 and &i32 are fundamentally
48
// different here. Feedback needed.
49
#[cfg(feature = "mmap")]
50
pub(crate) fn maybe_mmap_file(file: &std::fs::File) -> std::io::Result<Option<memmap2::Mmap>> {
51
    let metadata = file.metadata()?;
52
    let file_size = metadata.len();
53
    if !metadata.is_file() {
54
        // Not a real file.
55
        Ok(None)
56
    } else if file_size < 16 * 1024 {
57
        // Mapping small files is not worth it, and some special files that can't be mapped report
58
        // a size of zero.
59
        Ok(None)
60
    } else {
61
        let map = unsafe { memmap2::Mmap::map(file)? };
62
        Ok(Some(map))
63
    }
64
}