cranelift: improve syscall error/oom handling in JIT module (#5173)
* cranelift: improve syscall error/oom handling in JIT module The JIT module has several places where it `expect`s or `panic`s on syscall or allocator errors. For example, `mmap` and `mprotect` can fail if Linux `vm.max_map_count` is not high enough, and some users may wish to handle this error rather than immediately crashing. This commit plumbs these errors upward as new `ModuleError` types, so that callers of jit module functions like `finalize_definitions` and `define_function` can handle them (or just `unwrap()`, as desired). * cranelift: Remove ModuleError::Syscall variant Syscall errors can just be folded into the generic Backend error, which is an anyhow::Error * cranelift-jit: return io::ErrorKind::OutOfMemory for alloc failure Just using `io::Error::last_os_error()` is not correct as global allocator impls are not required to set errno
This commit is contained in:
@@ -427,7 +427,9 @@ impl JITModule {
|
||||
///
|
||||
/// Use `get_finalized_function` and `get_finalized_data` to obtain the final
|
||||
/// artifacts.
|
||||
pub fn finalize_definitions(&mut self) {
|
||||
///
|
||||
/// Returns ModuleError in case of allocation or syscall failure
|
||||
pub fn finalize_definitions(&mut self) -> ModuleResult<()> {
|
||||
for func in std::mem::take(&mut self.functions_to_finalize) {
|
||||
let decl = self.declarations.get_function_decl(func);
|
||||
assert!(decl.linkage.is_definable());
|
||||
@@ -455,12 +457,13 @@ impl JITModule {
|
||||
}
|
||||
|
||||
// Now that we're done patching, prepare the memory for execution!
|
||||
self.memory.readonly.set_readonly();
|
||||
self.memory.code.set_readable_and_executable();
|
||||
self.memory.readonly.set_readonly()?;
|
||||
self.memory.code.set_readable_and_executable()?;
|
||||
|
||||
for update in self.pending_got_updates.drain(..) {
|
||||
unsafe { update.entry.as_ref() }.store(update.ptr as *mut _, Ordering::SeqCst);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a new `JITModule`.
|
||||
@@ -688,7 +691,10 @@ impl Module for JITModule {
|
||||
.memory
|
||||
.code
|
||||
.allocate(size, align)
|
||||
.expect("TODO: handle OOM etc.");
|
||||
.map_err(|e| ModuleError::Allocation {
|
||||
message: "unable to alloc function",
|
||||
err: e,
|
||||
})?;
|
||||
|
||||
{
|
||||
let mem = unsafe { std::slice::from_raw_parts_mut(ptr, size) };
|
||||
@@ -770,7 +776,10 @@ impl Module for JITModule {
|
||||
.memory
|
||||
.code
|
||||
.allocate(size, align)
|
||||
.expect("TODO: handle OOM etc.");
|
||||
.map_err(|e| ModuleError::Allocation {
|
||||
message: "unable to alloc function bytes",
|
||||
err: e,
|
||||
})?;
|
||||
|
||||
unsafe {
|
||||
ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, size);
|
||||
@@ -836,12 +845,18 @@ impl Module for JITModule {
|
||||
self.memory
|
||||
.writable
|
||||
.allocate(size, align.unwrap_or(WRITABLE_DATA_ALIGNMENT))
|
||||
.expect("TODO: handle OOM etc.")
|
||||
.map_err(|e| ModuleError::Allocation {
|
||||
message: "unable to alloc writable data",
|
||||
err: e,
|
||||
})?
|
||||
} else {
|
||||
self.memory
|
||||
.readonly
|
||||
.allocate(size, align.unwrap_or(READONLY_DATA_ALIGNMENT))
|
||||
.expect("TODO: handle OOM etc.")
|
||||
.map_err(|e| ModuleError::Allocation {
|
||||
message: "unable to alloc readonly data",
|
||||
err: e,
|
||||
})?
|
||||
};
|
||||
|
||||
match *init {
|
||||
|
||||
Reference in New Issue
Block a user