summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2018-01-31 19:20:36 -0500
committerAndrew Gallant <jamslam@gmail.com>2018-01-31 19:20:36 -0500
commit93943793c314e0566ed57d7c0642c3b818c76c50 (patch)
tree3b464a4a4b6f77e8e95d75b0e6eddff9ca2475ec /src
parent0fedaa7d28549ee0b534281acb18423ef3b3648c (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.rs2
-rw-r--r--src/worker.rs29
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) }
}