You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

105 lines
3.1 KiB

// This test only works on Linux. It may be portable to MacOS as well,
// but the original author did not have a machine available to test it.
#![cfg(target_os = "linux")]
use wasmtime::*;
#[derive(Default)]
struct MemoryGrowFailureDetector {
current: usize,
desired: usize,
error: Option<String>,
}
impl ResourceLimiter for MemoryGrowFailureDetector {
fn memory_growing(
&mut self,
current: usize,
desired: usize,
_maximum: Option<usize>,
) -> Result<bool> {
self.current = current;
self.desired = desired;
Ok(true)
}
fn memory_grow_failed(&mut self, err: anyhow::Error) -> Result<()> {
self.error = Some(err.to_string());
Ok(())
}
fn table_growing(
&mut self,
_current: u32,
_desired: u32,
_maximum: Option<u32>,
) -> Result<bool> {
Ok(true)
}
}
#[test]
#[cfg_attr(miri, ignore)]
fn custom_limiter_detect_os_oom_failure() -> Result<()> {
if std::env::var("WASMTIME_TEST_NO_HOG_MEMORY").is_ok() {
return Ok(());
}
// Default behavior of on-demand memory allocation so that a
// memory grow will hit Linux for a larger mmap.
let mut config = Config::new();
config.wasm_reference_types(false);
let engine = Engine::new(&config)?;
let linker = Linker::new(&engine);
let module = Module::new(&engine, r#"(module (memory (export "m") 0))"#).unwrap();
// Ask Linux to limit this process to 256MiB of memory
let process_max_memory: usize = 256 * 1024 * 1024;
unsafe {
// limit process to 256MiB memory
let rlimit = libc::rlimit {
rlim_cur: 0,
rlim_max: process_max_memory as u64,
};
let res = libc::setrlimit(libc::RLIMIT_DATA, &rlimit);
assert_eq!(res, 0, "setrlimit failed: {}", res);
};
let context = MemoryGrowFailureDetector::default();
let mut store = Store::new(&engine, context);
store.limiter(|s| s as &mut dyn ResourceLimiter);
let instance = linker.instantiate(&mut store, &module).unwrap();
let memory = instance.get_memory(&mut store, "m").unwrap();
// Small (640KiB) grow should succeed
memory.grow(&mut store, 10).unwrap();
assert!(store.data().error.is_none());
assert_eq!(store.data().current, 0);
assert_eq!(store.data().desired, 10 * 64 * 1024);
// Try to grow past the process's memory limit.
// This should fail.
let pages_exceeding_limit = process_max_memory / (64 * 1024);
let err_msg = memory
.grow(&mut store, pages_exceeding_limit as u64)
.unwrap_err()
.to_string();
assert!(
err_msg.starts_with("failed to grow memory"),
"unexpected error: {}",
err_msg
);
assert_eq!(store.data().current, 10 * 64 * 1024);
assert_eq!(
store.data().desired,
(pages_exceeding_limit + 10) * 64 * 1024
);
// The memory_grow_failed hook should show Linux gave OOM:
let err_msg = store.data().error.as_ref().unwrap();
assert!(
err_msg.starts_with("Cannot allocate memory"),
"unexpected error: {}",
err_msg
);
Ok(())
}