diff options
author | Andrew Gallant <jamslam@gmail.com> | 2018-01-31 19:20:36 -0500 |
---|---|---|
committer | Andrew Gallant <jamslam@gmail.com> | 2018-01-31 19:20:36 -0500 |
commit | 93943793c314e0566ed57d7c0642c3b818c76c50 (patch) | |
tree | 3b464a4a4b6f77e8e95d75b0e6eddff9ca2475ec /src | |
parent | 0fedaa7d28549ee0b534281acb18423ef3b3648c (diff) |
worker: better error handling for memory maps
Previously, we would bail out of using memory maps if we could detect
ahead of time that opening a memory map would fail. The only case we
checked was whether the file size was 0 or not.
This is actually insufficient. The mmap call can return ENODEV errors
when a file doesn't support memory maps. This is the case for new files
exposed by Linux, for example,
/sys/devices/system/cpu/vulnerabilities/meltdown.
We fix this by checking the actual error codes returned by the mmap call.
If ENODEV (or EOVERFLOW) is returned, then we fall back to regular `read`
calls. If any other error occurs, we report it to the user.
Fixes #760
Diffstat (limited to 'src')
-rw-r--r-- | src/main.rs | 2 | ||||
-rw-r--r-- | src/worker.rs | 29 |
2 files changed, 29 insertions, 2 deletions
diff --git a/src/main.rs b/src/main.rs index f7407eab..7d39aa66 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,6 +9,7 @@ extern crate grep; extern crate ignore; #[macro_use] extern crate lazy_static; +extern crate libc; #[macro_use] extern crate log; extern crate memchr; @@ -339,7 +340,6 @@ fn eprint_nothing_searched() { // https://github.com/BurntSushi/ripgrep/issues/200. #[cfg(unix)] fn reset_sigpipe() { - extern crate libc; unsafe { libc::signal(libc::SIGPIPE, libc::SIG_DFL); } diff --git a/src/worker.rs b/src/worker.rs index 3c00cc07..eee7c67f 100644 --- a/src/worker.rs +++ b/src/worker.rs @@ -310,7 +310,10 @@ impl Worker { // regular read calls. return self.search(printer, path, file); } - let mmap = unsafe { Mmap::map(file)? }; + let mmap = match self.mmap(file)? { + None => return self.search(printer, path, file), + Some(mmap) => mmap, + }; let buf = &*mmap; if buf.len() >= 3 && Encoding::for_bom(buf).is_some() { // If we have a UTF-16 bom in our memory map, then we need to fall @@ -330,4 +333,28 @@ impl Worker { .text(self.opts.text) .run()) } + + #[cfg(not(unix))] + fn mmap(&self, file: &File) -> Result<Option<Mmap>> { + Ok(Some(mmap_readonly(file)?)) + } + + #[cfg(unix)] + fn mmap(&self, file: &File) -> Result<Option<Mmap>> { + use libc::{ENODEV, EOVERFLOW}; + + let err = match mmap_readonly(file) { + Ok(mmap) => return Ok(Some(mmap)), + Err(err) => err, + }; + let code = err.raw_os_error(); + if code == Some(ENODEV) || code == Some(EOVERFLOW) { + return Ok(None); + } + Err(From::from(err)) + } +} + +fn mmap_readonly(file: &File) -> io::Result<Mmap> { + unsafe { Mmap::map(file) } } |