#![cfg_attr(docsrs, feature(doc_cfg))]
#![cfg_attr(docsrs, deny(broken_intra_doc_links))]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
use std::io;
use std::os::raw::c_void;
#[inline]
fn unsupported(msg: &'static str) -> io::Result<()> {
Err(io::Error::new(io::ErrorKind::Unsupported, msg))
}
#[cfg(unix)]
mod unix {
use super::{c_void, io};
pub unsafe fn mlock(addr: *const c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let rc = unsafe { libc::mlock(addr, len) };
if rc == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub unsafe fn munlock(addr: *const c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let rc = unsafe { libc::munlock(addr, len) };
if rc == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(target_os = "linux")]
pub unsafe fn madvise_dontdump(addr: *mut c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let rc = libc::madvise(addr, len, libc::MADV_DONTDUMP);
if rc == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(target_os = "freebsd")]
pub unsafe fn madvise_dontdump(addr: *mut c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let rc = libc::madvise(addr, len, libc::MADV_NOCORE);
if rc == 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
pub unsafe fn madvise_dontdump(_addr: *mut c_void, _len: usize) -> io::Result<()> {
super::unsupported("madvise-based dump exclusion unsupported on this platform")
}
}
#[cfg(not(unix))]
mod non_unix {
use super::{c_void, io};
pub unsafe fn mlock(_addr: *const c_void, _len: usize) -> io::Result<()> {
super::unsupported("mlock unsupported on this platform")
}
pub unsafe fn munlock(_addr: *const c_void, _len: usize) -> io::Result<()> {
super::unsupported("munlock unsupported on this platform")
}
pub unsafe fn madvise_dontdump(_addr: *mut c_void, _len: usize) -> io::Result<()> {
super::unsupported("madvise(MADV_DONTDUMP) unsupported on this platform")
}
}
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
pub fn disable_core_dumps_for_process() -> io::Result<()> {
let mut old = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
let rc = unsafe { libc::getrlimit(libc::RLIMIT_CORE, &mut old as *mut _) };
if rc != 0 {
return Err(io::Error::last_os_error());
}
let new_lim = libc::rlimit {
rlim_cur: 0,
rlim_max: old.rlim_max,
};
let rc2 = unsafe { libc::setrlimit(libc::RLIMIT_CORE, &new_lim as *const _) };
if rc2 != 0 {
return Err(io::Error::last_os_error());
}
Ok(())
}
#[cfg(not(target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "macos"))))]
pub fn disable_core_dumps_for_process() -> io::Result<()> {
unsupported("disable_core_dumps_for_process unsupported on this platform")
}
#[derive(Debug)]
pub struct CoreDumpsDisabledGuard {
#[cfg(target_os = "macos")]
old: libc::rlimit,
}
#[cfg(target_os = "macos")]
impl Drop for CoreDumpsDisabledGuard {
fn drop(&mut self) {
let rc = unsafe { libc::setrlimit(libc::RLIMIT_CORE, &self.old as *const _) };
if rc != 0 {
eprintln!(
"os-memlock: failed to restore RLIMIT_CORE: {}",
io::Error::last_os_error()
);
}
}
}
#[cfg(target_os = "macos")]
#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))]
pub fn disable_core_dumps_with_guard() -> io::Result<CoreDumpsDisabledGuard> {
let mut old = libc::rlimit {
rlim_cur: 0,
rlim_max: 0,
};
let rc = unsafe { libc::getrlimit(libc::RLIMIT_CORE, &mut old as *mut _) };
if rc != 0 {
return Err(io::Error::last_os_error());
}
let new_lim = libc::rlimit {
rlim_cur: 0,
rlim_max: old.rlim_max,
};
let rc2 = unsafe { libc::setrlimit(libc::RLIMIT_CORE, &new_lim as *const _) };
if rc2 != 0 {
return Err(io::Error::last_os_error());
}
Ok(CoreDumpsDisabledGuard { old })
}
#[cfg(not(target_os = "macos"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "macos"))))]
pub fn disable_core_dumps_with_guard() -> io::Result<CoreDumpsDisabledGuard> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"disable_core_dumps_with_guard unsupported on this platform",
))
}
#[cfg(unix)]
#[cfg_attr(docsrs, doc(cfg(unix)))]
pub use unix::{madvise_dontdump, mlock, munlock};
#[cfg(windows)]
mod windows {
use super::{c_void, io};
use windows_sys::Win32::System::Memory::{VirtualLock, VirtualUnlock};
pub unsafe fn mlock(addr: *const c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let ok = unsafe { VirtualLock(addr as *mut _, len) };
if ok != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub unsafe fn munlock(addr: *const c_void, len: usize) -> io::Result<()> {
if len == 0 {
return Ok(());
}
let ok = unsafe { VirtualUnlock(addr as *mut _, len) };
if ok != 0 {
Ok(())
} else {
Err(io::Error::last_os_error())
}
}
pub unsafe fn madvise_dontdump(_addr: *mut c_void, _len: usize) -> io::Result<()> {
super::unsupported("madvise_dontdump unsupported on Windows")
}
pub const SEM_FAILCRITICALERRORS: u32 = 0x0001;
pub const SEM_NOGPFAULTERRORBOX: u32 = 0x0002;
pub const SEM_NOOPENFILEERRORBOX: u32 = 0x8000;
unsafe extern "system" {
fn SetErrorMode(uMode: u32) -> u32;
}
pub fn set_windows_error_mode(new_mode: u32) -> io::Result<u32> {
let previous = unsafe { SetErrorMode(new_mode) };
Ok(previous)
}
pub fn suppress_windows_error_dialogs_for_process() -> io::Result<u32> {
let desired = SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
let previous = unsafe { SetErrorMode(desired) };
Ok(previous)
}
}
#[cfg(windows)]
#[cfg_attr(docsrs, doc(cfg(windows)))]
pub use windows::{
SEM_FAILCRITICALERRORS, SEM_NOGPFAULTERRORBOX, SEM_NOOPENFILEERRORBOX, madvise_dontdump, mlock,
munlock, set_windows_error_mode, suppress_windows_error_dialogs_for_process,
};
#[cfg(not(windows))]
pub fn set_windows_error_mode(_new_mode: u32) -> io::Result<u32> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"set_windows_error_mode unsupported on this platform",
))
}
#[cfg(not(windows))]
pub fn suppress_windows_error_dialogs_for_process() -> io::Result<u32> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"suppress_windows_error_dialogs_for_process unsupported on this platform",
))
}
#[cfg(all(not(unix), not(windows)))]
#[cfg_attr(docsrs, doc(cfg(all(not(unix), not(windows)))))]
pub use non_unix::{madvise_dontdump, mlock, munlock};
#[cfg(test)]
mod tests {
#[test]
fn smoke_disable_core_dumps_for_process() {
let _ = crate::disable_core_dumps_for_process();
let _ = crate::disable_core_dumps_with_guard();
}
}