ソースを参照

Exit gracefully on program exit (#38)

Modify interfaces to support Result
jackcmay 6 年 前
コミット
b31d366489
9 ファイル変更511 行追加546 行削除
  1. 22 21
      README.md
  2. 5 5
      examples/load_elf.rs
  3. 5 5
      examples/uptime.rs
  4. 19 12
      src/jit.rs
  5. 113 156
      src/lib.rs
  6. 40 40
      tests/misc.rs
  7. 187 187
      tests/ubpf_jit_x86_64.rs
  8. 12 12
      tests/ubpf_verifier.rs
  9. 108 108
      tests/ubpf_vm.rs

+ 22 - 21
README.md

@@ -194,7 +194,8 @@ method when creating the VM).
 ```rust,ignore
 pub fn register_helper(&mut self,
                        key: u32,
-                       function: fn (u64, u64, u64, u64, u64) -> u64)
+                       function: fn (u64, u64, u64, u64, u64) -> u64) 
+                       -> Result<(), Error>
 ```
 
 This function is used to register a helper function. The VM stores its
@@ -206,14 +207,14 @@ therefore must use specific helper numbers.
 // for struct EbpfVmMbuff
 pub fn prog_exec(&self,
                  mem: &'a mut [u8],
-                 mbuff: &'a mut [u8]) -> u64
+                 mbuff: &'a mut [u8]) -> Result<(u64), Error>
 
 // for struct EbpfVmFixedMbuff and struct EbpfVmRaw
 pub fn prog_exec(&self,
-                 mem: &'a mut [u8]) -> u64
+                 mem: &'a mut [u8]) -> Result<(u64), Error>
 
 // for struct EbpfVmNoData
-pub fn prog_exec(&self) -> u64
+pub fn prog_exec(&self) -> Result<(u64), Error>
 ```
 
 Interprets the loaded program. The function takes a reference to the packet
@@ -222,7 +223,7 @@ depending on the kind of the VM used. The value returned is the result of the
 eBPF program.
 
 ```rust,ignore
-pub fn jit_compile(&mut self)
+pub fn jit_compile(&mut self) -> Result<(), Error>
 ```
 
 JIT-compile the loaded program, for x86_64 architecture. If the program is to
@@ -232,13 +233,13 @@ is called. The generated assembly function is internally stored in the VM.
 ```rust,ignore
 // for struct EbpfVmMbuff
 pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8],
-                            mbuff: &'a mut [u8]) -> u64
+                            mbuff: &'a mut [u8]) -> Result<(u64), Error>
 
 // for struct EbpfVmFixedMbuff and struct EbpfVmRaw
-pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> u64
+pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> Result<(u64), Error>
 
 // for struct EbpfVmNoData
-pub unsafe fn prog_exec_jit(&self) -> u64
+pub unsafe fn prog_exec_jit(&self) -> Result<(u64), Error>
 ```
 
 Calls the JIT-compiled program. The arguments to provide are the same as for
@@ -274,7 +275,7 @@ fn main() {
     let vm = rbpf::EbpfVmNoData::new(prog).unwrap();
 
     // Execute (interpret) the program. No argument required for this VM.
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 ```
 
@@ -301,11 +302,11 @@ fn main() {
     let mut vm = rbpf::EbpfVmRaw::new(prog).unwrap();
 
     // This time we JIT-compile the program.
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
 
     // Then we execute it. For this kind of VM, a reference to the packet data
     // must be passed to the function that executes the program.
-    unsafe { assert_eq!(vm.prog_exec_jit(mem), 0x11); }
+    unsafe { assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x11); }
 }
 ```
 ### Using a metadata buffer
@@ -342,11 +343,11 @@ fn main() {
     let mut vm = rbpf::EbpfVmMbuff::new(prog).unwrap();
 
     // Here again we JIT-compile the program.
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
 
     // Here we must provide both a reference to the packet data, and to the
     // metadata buffer we use.
-    unsafe { assert_eq!(vm.prog_exec_jit(mem, mbuff), 0x2211); }
+    unsafe { assert_eq!(vm.prog_exec_jit(mem, mbuff).unwrap(), 0x2211); }
 }
 ```
 
@@ -430,12 +431,13 @@ fn main() {
 
     // We register a helper function, that can be called by the program, into
     // the VM.
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);
+    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX,
+                       helpers::bpf_trace_printf).unwrap();
 
     // This kind of VM takes a reference to the packet data, but does not need
     // any reference to the metadata buffer: a fixed buffer is handled
     // internally by the VM.
-    let res = vm.prog_exec(packet);
+    let res = vm.prog_exec(packet).unwrap();
     println!("Program returned: {:?} ({:#x})", res, res);
 }
 ```
@@ -458,7 +460,7 @@ let prog = assemble("add64 r1, 0x605
                      mov64 r1, r0
                      be16 r0
                      neg64 r2
-                     exit");
+                     exit").unwrap();
 
 println!("{:?}", prog);
 ```
@@ -561,9 +563,9 @@ Other than the language, obviously? Well, there are some differences:
   stack, differs between uBPF and rbpf. The latter uses the same values as the
   Linux kernel, while uBPF has its own values.
 
-* When an error occur while a program is run by uBPF, the function running the
+* When an error occurs while a program is run by uBPF, the function running the
   program silently returns the maximum value as an error code, while rbpf
-  `panic!()`.
+  returns Rust type `Error`.
 
 * The registration of helper functions, that can be called from within an eBPF
   program, is not handled in the same way.
@@ -615,8 +617,8 @@ not trivial, and we cannot “copy” it since it is under GPL license.
 ### What about safety then?
 
 Rust has a strong emphasize on safety. Yet to have the eBPF VM work, some
-“unsafe” blocks of code are used. The VM, taken as an eBPF interpreter, can
-`panic!()` but should not crash. Please file an issue otherwise.
+`unsafe` blocks of code are used. The VM, taken as an eBPF interpreter, can
+return an error but should not crash. Please file an issue otherwise.
 
 As for the JIT-compiler, it is a different story, since runtime memory checks
 are more complicated to implement in assembly. It _will_ crash if your
@@ -648,7 +650,6 @@ on your own.
 * Implement some traits (`Clone`, `Drop`, `Debug` are good candidate).
 * Provide built-in support for user-space array and hash BPF maps.
 * Improve safety of JIT-compiled programs with runtime memory checks.
-* Replace `panic!()` by cleaner error handling.
 * Add helpers (some of those supported in the kernel, such as checksum update,
   could be helpful).
 * Improve verifier. Could we find a way to directly support programs compiled

+ 5 - 5
examples/load_elf.rs

@@ -112,24 +112,24 @@ fn main() {
     ];
 
     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);
+    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf).unwrap();
 
-    let res = vm.prog_exec(packet1);
+    let res = vm.prog_exec(packet1).unwrap();
     println!("Packet #1, program returned: {:?} ({:#x})", res, res);
     assert_eq!(res, 0xffffffff);
 
     #[cfg(not(windows))]
     {
-        vm.jit_compile();
+        vm.jit_compile().unwrap();
 
-        let res = unsafe { vm.prog_exec_jit(packet2) };
+        let res = unsafe { vm.prog_exec_jit(packet2).unwrap() };
         println!("Packet #2, program returned: {:?} ({:#x})", res, res);
         assert_eq!(res, 0);
     }
 
     #[cfg(windows)]
     {
-        let res = vm.prog_exec(packet2);
+        let res = vm.prog_exec(packet2).unwrap();
         println!("Packet #2, program returned: {:?} ({:#x})", res, res);
         assert_eq!(res, 0);
     }

+ 5 - 5
examples/uptime.rs

@@ -41,7 +41,7 @@ fn main() {
     // Create a VM: this one takes no data. Load prog1 in it.
     let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();
     // Execute prog1.
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 
     // As struct EbpfVmNoData does not takes any memory area, its return value is mostly
     // deterministic. So we know prog1 will always return 3. There is an exception: when it uses
@@ -52,20 +52,20 @@ fn main() {
     // reimplement uptime in eBPF, in Rust. Because why not.
 
     vm.set_prog(prog2).unwrap();
-    vm.register_helper(helpers::BPF_KTIME_GETNS_IDX, helpers::bpf_time_getns);
+    vm.register_helper(helpers::BPF_KTIME_GETNS_IDX, helpers::bpf_time_getns).unwrap();
 
     let time;
 
     #[cfg(not(windows))]
     {
-        vm.jit_compile();
+        vm.jit_compile().unwrap();
 
-        time = unsafe { vm.prog_exec_jit() };
+        time = unsafe { vm.prog_exec_jit().unwrap() };
     }
 
     #[cfg(windows)]
     {
-        time = vm.prog_exec();
+        time = vm.prog_exec().unwrap();
     }
 
     let days    =  time / 10u64.pow(9)  / 60   / 60  / 24;

+ 19 - 12
src/jit.rs

@@ -12,10 +12,13 @@
 use std;
 use std::mem;
 use std::collections::HashMap;
-use std::fmt::{Error, Formatter};
+use std::fmt::Formatter;
+use std::fmt::Error as FormatterError;
+use std::io::{Error, ErrorKind};
 use std::ops::{Index, IndexMut};
 
 use ebpf;
+use JitProgram;
 
 extern crate libc;
 
@@ -453,7 +456,7 @@ impl<'a> JitMemory<'a> {
     }
 
     fn jit_compile(&mut self, prog: &[u8], use_mbuff: bool, update_data_ptr: bool,
-                   helpers: &HashMap<u32, ebpf::Helper>) {
+                   helpers: &HashMap<u32, ebpf::Helper>) -> Result<(), Error> {
         emit_push(self, RBP);
         emit_push(self, RBX);
         emit_push(self, R13);
@@ -778,8 +781,9 @@ impl<'a> JitMemory<'a> {
                         emit_mov(self, R9, RCX);
                         emit_call(self, *helper as usize);
                     } else {
-                        panic!("[JIT] Error: unknown helper function (id: {:#x})",
-                               insn.imm as u32);
+                        Err(Error::new(ErrorKind::Other,
+                                       format!("[JIT] Error: unknown helper function (id: {:#x})",
+                                               insn.imm as u32)))?;
                     };
                 },
                 ebpf::TAIL_CALL  => { unimplemented!() },
@@ -790,8 +794,9 @@ impl<'a> JitMemory<'a> {
                 },
 
                 _                => {
-                    panic!("[JIT] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
-                           insn.opc, insn_ptr);
+                    Err(Error::new(ErrorKind::Other,
+                                   format!("[JIT] Error: unknown eBPF opcode {:#2x} (insn #{:?})",
+                                           insn.opc, insn_ptr)))?;
                 },
             }
 
@@ -836,9 +841,10 @@ impl<'a> JitMemory<'a> {
         emit_call(self, log as usize);
         emit_load_imm(self, map_register(0), -1);
         emit_jmp(self, TARGET_PC_EXIT);
+        Ok(())
     }
 
-    fn resolve_jumps(&mut self)
+    fn resolve_jumps(&mut self) -> Result<(), Error>
     {
         for jump in &self.jumps {
             let target_loc = match self.special_targets.get(&jump.target_pc) {
@@ -857,6 +863,7 @@ impl<'a> JitMemory<'a> {
                              std::mem::size_of::<i32>());
             }
         }
+        Ok(())
     }
 } // struct JitMemory
 
@@ -875,7 +882,7 @@ impl<'a> IndexMut<usize> for JitMemory<'a> {
 }
 
 impl<'a> std::fmt::Debug for JitMemory<'a> {
-    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
+    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FormatterError> {
         fmt.write_str("JIT contents: [")?;
         for i in self.contents as &[u8] {
             fmt.write_fmt(format_args!(" {:#04x},", i))?;
@@ -894,13 +901,13 @@ impl<'a> std::fmt::Debug for JitMemory<'a> {
 pub fn compile(prog: &[u8],
                helpers: &HashMap<u32, ebpf::Helper>,
                use_mbuff: bool, update_data_ptr: bool)
-    -> (unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64) {
+    -> Result<(JitProgram), Error> {
 
     // TODO: check how long the page must be to be sure to support an eBPF program of maximum
     // possible length
     let mut jit = JitMemory::new(1);
-    jit.jit_compile(prog, use_mbuff, update_data_ptr, helpers);
-    jit.resolve_jumps();
+    jit.jit_compile(prog, use_mbuff, update_data_ptr, helpers)?;
+    jit.resolve_jumps()?;
 
-    unsafe { mem::transmute(jit.contents.as_ptr()) }
+    Ok(unsafe { mem::transmute(jit.contents.as_ptr()) })
 }

+ 113 - 156
src/lib.rs

@@ -27,7 +27,7 @@ extern crate time;
 
 use std::u32;
 use std::collections::HashMap;
-use std::io::Error;
+use std::io::{Error, ErrorKind};
 use byteorder::{ByteOrder, LittleEndian};
 
 pub mod assembler;
@@ -50,6 +50,9 @@ mod verifier;
 ///   - Unknown eBPF helper index.
 pub type Verifier = fn(prog: &[u8]) -> Result<(), Error>;
 
+/// eBPF Jit-compiled program.
+pub type JitProgram = unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64;
+
 // A metadata buffer with two offset indications. It can be used in one kind of eBPF VM to simulate
 // the use of a metadata buffer each time the program is executed, without the user having to
 // actually handle it. The offsets are used to tell the VM where in the buffer the pointers to
@@ -89,13 +92,13 @@ struct MetaBuff {
 /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
 ///
 /// // Provide both a reference to the packet data, and to the metadata buffer.
-/// let res = vm.prog_exec(mem, &mut mbuff);
+/// let res = vm.prog_exec(mem, &mut mbuff).unwrap();
 /// assert_eq!(res, 0x2211);
 /// ```
 pub struct EbpfVmMbuff<'a> {
     prog:     Option<&'a [u8]>,
     verifier: Verifier,
-    jit:      (unsafe fn(*mut u8, usize, *mut u8, usize, usize, usize) -> u64),
+    jit:      Option<JitProgram>,
     helpers:  HashMap<u32, ebpf::Helper>,
 }
 
@@ -121,15 +124,10 @@ impl<'a> EbpfVmMbuff<'a> {
             verifier::check(prog)?;
         }
 
-        fn no_jit(_mbuff: *mut u8, _len: usize, _mem: *mut u8, _mem_len: usize,
-                  _nodata_offset: usize, _nodata_end_offset: usize) -> u64 {
-            panic!("Error: program has not been JIT-compiled");
-        }
-
         Ok(EbpfVmMbuff {
             prog:     prog,
             verifier: verifier::check,
-            jit:      no_jit,
+            jit:      None,
             helpers:  HashMap::new(),
         })
     }
@@ -230,10 +228,11 @@ impl<'a> EbpfVmMbuff<'a> {
     /// // Register a helper.
     /// // On running the program this helper will print the content of registers r3, r4 and r5 to
     /// // standard output.
-    /// vm.register_helper(6, helpers::bpf_trace_printf);
+    /// vm.register_helper(6, helpers::bpf_trace_printf).unwrap();
     /// ```
-    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
+    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
         self.helpers.insert(key, function);
+        Ok(())
     }
 
     /// Execute the program loaded, with the given packet data and metadata buffer.
@@ -243,12 +242,6 @@ impl<'a> EbpfVmMbuff<'a> {
     /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
     /// pointers are correctly stored in the buffer.
     ///
-    /// # Panics
-    ///
-    /// This function is currently expected to panic if it encounters any error during the program
-    /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
-    /// in the future (we could raise errors instead).
-    ///
     /// # Examples
     ///
     /// ```
@@ -275,17 +268,18 @@ impl<'a> EbpfVmMbuff<'a> {
     /// let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
     ///
     /// // Provide both a reference to the packet data, and to the metadata buffer.
-    /// let res = vm.prog_exec(mem, &mut mbuff);
+    /// let res = vm.prog_exec(mem, &mut mbuff).unwrap();
     /// assert_eq!(res, 0x2211);
     /// ```
     #[allow(unknown_lints)]
     #[allow(cyclomatic_complexity)]
-    pub fn prog_exec(&self, mem: &[u8], mbuff: &[u8]) -> u64 {
+    pub fn prog_exec(&self, mem: &[u8], mbuff: &[u8]) -> Result<u64, Error> {
         const U32MAX: u64 = u32::MAX as u64;
 
         let prog = match self.prog { 
             Some(prog) => prog,
-            None => panic!("Error: No program set, call prog_set() to load one"),
+            None => Err(Error::new(ErrorKind::Other,
+                        "Error: No program set, call prog_set() to load one"))?,
         };
         let stack = vec![0u8;ebpf::STACK_SIZE];
 
@@ -301,10 +295,10 @@ impl<'a> EbpfVmMbuff<'a> {
         }
 
         let check_mem_load = | addr: u64, len: usize, insn_ptr: usize | {
-            EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, mbuff, mem, &stack);
+            EbpfVmMbuff::check_mem(addr, len, "load", insn_ptr, mbuff, mem, &stack)
         };
         let check_mem_store = | addr: u64, len: usize, insn_ptr: usize | {
-            EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, mbuff, mem, &stack);
+            EbpfVmMbuff::check_mem(addr, len, "store", insn_ptr, mbuff, mem, &stack)
         };
 
         // Loop on instructions
@@ -323,42 +317,42 @@ impl<'a> EbpfVmMbuff<'a> {
                 // bother re-fetching it, just use mem already.
                 ebpf::LD_ABS_B   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u8;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_ABS_H   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u16;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_ABS_W   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u32;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_ABS_DW  => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + (insn.imm as u32) as u64) as *const u64;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_IND_B   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u8;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_IND_H   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u16;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_IND_W   => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u32;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_IND_DW  => reg[0] = unsafe {
                     let x = (mem.as_ptr() as u64 + reg[_src] + (insn.imm as u32) as u64) as *const u64;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
 
@@ -372,75 +366,75 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::LD_B_REG   => reg[_dst] = unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u8;
-                    check_mem_load(x as u64, 1, insn_ptr);
+                    check_mem_load(x as u64, 1, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_H_REG   => reg[_dst] = unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u16;
-                    check_mem_load(x as u64, 2, insn_ptr);
+                    check_mem_load(x as u64, 2, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_W_REG   => reg[_dst] = unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u32;
-                    check_mem_load(x as u64, 4, insn_ptr);
+                    check_mem_load(x as u64, 4, insn_ptr)?;
                     *x as u64
                 },
                 ebpf::LD_DW_REG  => reg[_dst] = unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_src] as *const u8).offset(insn.off as isize) as *const u64;
-                    check_mem_load(x as u64, 8, insn_ptr);
+                    check_mem_load(x as u64, 8, insn_ptr)?;
                     *x as u64
                 },
 
                 // BPF_ST class
                 ebpf::ST_B_IMM   => unsafe {
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
-                    check_mem_store(x as u64, 1, insn_ptr);
+                    check_mem_store(x as u64, 1, insn_ptr)?;
                     *x = insn.imm as u8;
                 },
                 ebpf::ST_H_IMM   => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
-                    check_mem_store(x as u64, 2, insn_ptr);
+                    check_mem_store(x as u64, 2, insn_ptr)?;
                     *x = insn.imm as u16;
                 },
                 ebpf::ST_W_IMM   => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
-                    check_mem_store(x as u64, 4, insn_ptr);
+                    check_mem_store(x as u64, 4, insn_ptr)?;
                     *x = insn.imm as u32;
                 },
                 ebpf::ST_DW_IMM  => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
-                    check_mem_store(x as u64, 8, insn_ptr);
+                    check_mem_store(x as u64, 8, insn_ptr)?;
                     *x = insn.imm as u64;
                 },
 
                 // BPF_STX class
                 ebpf::ST_B_REG   => unsafe {
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u8;
-                    check_mem_store(x as u64, 1, insn_ptr);
+                    check_mem_store(x as u64, 1, insn_ptr)?;
                     *x = reg[_src] as u8;
                 },
                 ebpf::ST_H_REG   => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u16;
-                    check_mem_store(x as u64, 2, insn_ptr);
+                    check_mem_store(x as u64, 2, insn_ptr)?;
                     *x = reg[_src] as u16;
                 },
                 ebpf::ST_W_REG   => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u32;
-                    check_mem_store(x as u64, 4, insn_ptr);
+                    check_mem_store(x as u64, 4, insn_ptr)?;
                     *x = reg[_src] as u32;
                 },
                 ebpf::ST_DW_REG  => unsafe {
                     #[allow(cast_ptr_alignment)]
                     let x = (reg[_dst] as *const u8).offset(insn.off as isize) as *mut u64;
-                    check_mem_store(x as u64, 8, insn_ptr);
+                    check_mem_store(x as u64, 8, insn_ptr)?;
                     *x = reg[_src] as u64;
                 },
                 ebpf::ST_W_XADD  => unimplemented!(),
@@ -459,7 +453,7 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::DIV32_IMM  => reg[_dst] = (reg[_dst] as u32 / insn.imm              as u32) as u64,
                 ebpf::DIV32_REG  => {
                     if reg[_src] == 0 {
-                        panic!("Error: division by 0");
+                        Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
                     }
                     reg[_dst] = (reg[_dst] as u32 / reg[_src] as u32) as u64;
                 },
@@ -475,7 +469,7 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::MOD32_IMM  =>   reg[_dst] = (reg[_dst] as u32             % insn.imm  as u32) as u64,
                 ebpf::MOD32_REG  => {
                     if reg[_src] == 0 {
-                        panic!("Error: division by 0");
+                        Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
                     }
                     reg[_dst] = (reg[_dst] as u32 % reg[_src] as u32) as u64;
                 },
@@ -512,7 +506,7 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::DIV64_IMM  => reg[_dst]                       /= insn.imm as u64,
                 ebpf::DIV64_REG  => {
                     if reg[_src] == 0 {
-                        panic!("Error: division by 0");
+                        Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
                     }
                     reg[_dst] /= reg[_src];
                 },
@@ -528,7 +522,7 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::MOD64_IMM  => reg[_dst] %=  insn.imm as u64,
                 ebpf::MOD64_REG  => {
                     if reg[_src] == 0 {
-                        panic!("Error: division by 0");
+                        Err(Error::new(ErrorKind::Other,"Error: division by 0"))?;
                     }
                     reg[_dst] %= reg[_src];
                 },
@@ -569,10 +563,10 @@ impl<'a> EbpfVmMbuff<'a> {
                 ebpf::CALL       => if let Some(function) = self.helpers.get(&(insn.imm as u32)) {
                     reg[0] = function(reg[1], reg[2], reg[3], reg[4], reg[5]);
                 } else {
-                    panic!("Error: unknown helper function (id: {:#x})", insn.imm as u32);
+                    Err(Error::new(ErrorKind::Other, format!("Error: unknown helper function (id: {:#x})", insn.imm as u32)))?;
                 },
                 ebpf::TAIL_CALL  => unimplemented!(),
-                ebpf::EXIT       => return reg[0],
+                ebpf::EXIT       => return Ok(reg[0]),
 
                 _                => unreachable!()
             }
@@ -582,24 +576,24 @@ impl<'a> EbpfVmMbuff<'a> {
     }
 
     fn check_mem(addr: u64, len: usize, access_type: &str, insn_ptr: usize,
-                 mbuff: &[u8], mem: &[u8], stack: &[u8]) {
+                 mbuff: &[u8], mem: &[u8], stack: &[u8]) -> Result<(), Error> {
         if mbuff.as_ptr() as u64 <= addr && addr + len as u64 <= mbuff.as_ptr() as u64 + mbuff.len() as u64 {
-            return
+            return Ok(())
         }
         if mem.as_ptr() as u64 <= addr && addr + len as u64 <= mem.as_ptr() as u64 + mem.len() as u64 {
-            return
+            return Ok(())
         }
         if stack.as_ptr() as u64 <= addr && addr + len as u64 <= stack.as_ptr() as u64 + stack.len() as u64 {
-            return
+            return Ok(())
         }
 
-        panic!(
+        Err(Error::new(ErrorKind::Other, format!(
             "Error: out of bounds memory {} (insn #{:?}), addr {:#x}, size {:?}\nmbuff: {:#x}/{:#x}, mem: {:#x}/{:#x}, stack: {:#x}/{:#x}",
             access_type, insn_ptr, addr, len,
             mbuff.as_ptr() as u64, mbuff.len(),
             mem.as_ptr() as u64, mem.len(),
             stack.as_ptr() as u64, stack.len()
-        );
+        )))
     }
 
     /// JIT-compile the loaded program. No argument required for this.
@@ -607,11 +601,6 @@ impl<'a> EbpfVmMbuff<'a> {
     /// If using helper functions, be sure to register them into the VM before calling this
     /// function.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
-    /// unknown eBPF operation code.
-    ///
     /// # Examples
     ///
     /// ```
@@ -627,12 +616,13 @@ impl<'a> EbpfVmMbuff<'a> {
     /// vm.jit_compile();
     /// ```
     #[cfg(not(windows))]
-    pub fn jit_compile(&mut self) {
+    pub fn jit_compile(&mut self) -> Result<(), Error> {
         let prog = match self.prog { 
             Some(prog) => prog,
-            None => panic!("Error: No program set, call prog_set() to load one"),
+            None => Err(Error::new(ErrorKind::Other, "Error: No program set, call prog_set() to load one"))?,
         };
-        self.jit = jit::compile(prog, &self.helpers, true, false);
+        self.jit = Some(jit::compile(prog, &self.helpers, true, false)?);
+        Ok(())
     }
 
     /// Execute the previously JIT-compiled program, with the given packet data and metadata
@@ -643,10 +633,6 @@ impl<'a> EbpfVmMbuff<'a> {
     /// metadata buffer, at some appointed offsets. It is up to the user to ensure that these
     /// pointers are correctly stored in the buffer.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during the execution of the program.
-    ///
     /// # Safety
     ///
     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
@@ -687,11 +673,11 @@ impl<'a> EbpfVmMbuff<'a> {
     /// // Provide both a reference to the packet data, and to the metadata buffer.
     /// # #[cfg(not(windows))]
     /// unsafe {
-    ///     let res = vm.prog_exec_jit(mem, &mut mbuff);
+    ///     let res = vm.prog_exec_jit(mem, &mut mbuff).unwrap();
     ///     assert_eq!(res, 0x2211);
     /// }
     /// ```
-    pub unsafe fn prog_exec_jit(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> u64 {
+    pub unsafe fn prog_exec_jit(&self, mem: &mut [u8], mbuff: &'a mut [u8]) -> Result<u64, Error> {
         // If packet data is empty, do not send the address of an empty slice; send a null pointer
         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
@@ -703,7 +689,11 @@ impl<'a> EbpfVmMbuff<'a> {
         // The last two arguments are not used in this function. They would be used if there was a
         // need to indicate to the JIT at which offset in the mbuff mem_ptr and mem_ptr + mem.len()
         // should be stored; this is what happens with struct EbpfVmFixedMbuff.
-        (self.jit)(mbuff.as_ptr() as *mut u8, mbuff.len(), mem_ptr, mem.len(), 0, 0)
+        match self.jit {
+            Some(jit) => Ok(jit(mbuff.as_ptr() as *mut u8, mbuff.len(), mem_ptr, mem.len(), 0, 0)),
+            None => Err(Error::new(ErrorKind::Other,
+                        "Error: program has not been JIT-compiled")),
+        }
     }
 }
 
@@ -768,10 +758,10 @@ impl<'a> EbpfVmMbuff<'a> {
 /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
 ///
 /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-/// let res = vm.prog_exec(mem1);
+/// let res = vm.prog_exec(mem1).unwrap();
 /// assert_eq!(res, 0xffffffffffffffdd);
 ///
-/// let res = vm.prog_exec(mem2);
+/// let res = vm.prog_exec(mem2).unwrap();
 /// assert_eq!(res, 0x27);
 /// ```
 pub struct EbpfVmFixedMbuff<'a> {
@@ -844,7 +834,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog1), 0, 0).unwrap();
     /// vm.set_prog(prog2, 0x40, 0x50);
     ///
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 0x27);
     /// ```
     pub fn set_prog(&mut self, prog: &'a [u8], data_offset: usize, data_end_offset: usize) -> Result<(), Error> {
@@ -930,11 +920,11 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// // Register a helper. This helper will store the result of the square root of r1 into r0.
     /// vm.register_helper(1, helpers::sqrti);
     ///
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 3);
     /// ```
-    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
-        self.parent.register_helper(key, function);
+    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
+        self.parent.register_helper(key, function)
     }
 
     /// Execute the program loaded, with the given packet data.
@@ -944,12 +934,6 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
     /// the addresses should be placed should have be set at the creation of the VM.
     ///
-    /// # Panics
-    ///
-    /// This function is currently expected to panic if it encounters any error during the program
-    /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
-    /// in the future (we could raise errors instead).
-    ///
     /// # Examples
     ///
     /// ```
@@ -970,15 +954,15 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
     ///
     /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 0xdd);
     /// ```
-    pub fn prog_exec(&mut self, mem: &'a mut [u8]) -> u64 {
+    pub fn prog_exec(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
         let l = self.mbuff.buffer.len();
         // Can this ever happen? Probably not, should be ensured at mbuff creation.
         if self.mbuff.data_offset + 8 > l || self.mbuff.data_end_offset + 8 > l {
-            panic!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
-            l, self.mbuff.data_offset, self.mbuff.data_end_offset);
+            Err(Error::new(ErrorKind::Other, format!("Error: buffer too small ({:?}), cannot use data_offset {:?} and data_end_offset {:?}",
+            l, self.mbuff.data_offset, self.mbuff.data_end_offset)))?;
         }
         LittleEndian::write_u64(&mut self.mbuff.buffer[(self.mbuff.data_offset) .. ], mem.as_ptr() as u64);
         LittleEndian::write_u64(&mut self.mbuff.buffer[(self.mbuff.data_end_offset) .. ], mem.as_ptr() as u64 + mem.len() as u64);
@@ -990,11 +974,6 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// If using helper functions, be sure to register them into the VM before calling this
     /// function.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
-    /// unknown eBPF operation code.
-    ///
     /// # Examples
     ///
     /// ```
@@ -1014,12 +993,13 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// vm.jit_compile();
     /// ```
     #[cfg(not(windows))]
-    pub fn jit_compile(&mut self) {
+    pub fn jit_compile(&mut self) -> Result<(), Error> {
         let prog = match self.parent.prog { 
             Some(prog) => prog,
-            None => panic!("Error: No program set, call prog_set() to load one"),
+            None => Err(Error::new(ErrorKind::Other, "Error: No program set, call prog_set() to load one"))?,
         };
-        self.parent.jit = jit::compile(prog, &self.parent.helpers, true, true);
+        self.parent.jit = Some(jit::compile(prog, &self.parent.helpers, true, true)?);
+        Ok(())
     }
 
     /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
@@ -1030,10 +1010,6 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// metadata buffer, which in the case of this VM is handled internally. The offsets at which
     /// the addresses should be placed should have be set at the creation of the VM.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during the execution of the program.
-    ///
     /// # Safety
     ///
     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
@@ -1068,13 +1044,13 @@ impl<'a> EbpfVmFixedMbuff<'a> {
     /// // Provide only a reference to the packet data. We do not manage the metadata buffer.
     /// # #[cfg(not(windows))]
     /// unsafe {
-    ///     let res = vm.prog_exec_jit(mem);
+    ///     let res = vm.prog_exec_jit(mem).unwrap();
     ///     assert_eq!(res, 0xdd);
     /// }
     /// ```
     // This struct redefines the `prog_exec_jit()` function, in order to pass the offsets
     // associated with the fixed mbuff.
-    pub unsafe fn prog_exec_jit(&mut self, mem: &'a mut [u8]) -> u64 {
+    pub unsafe fn prog_exec_jit(&mut self, mem: &'a mut [u8]) -> Result<u64, Error> {
         // If packet data is empty, do not send the address of an empty slice; send a null pointer
         //  as first argument instead, as this is uBPF's behavior (empty packet should not happen
         //  in the kernel; anyway the verifier would prevent the use of uninitialized registers).
@@ -1083,8 +1059,17 @@ impl<'a> EbpfVmFixedMbuff<'a> {
             0 => std::ptr::null_mut(),
             _ => mem.as_ptr() as *mut u8
         };
-        (self.parent.jit)(self.mbuff.buffer.as_ptr() as *mut u8, self.mbuff.buffer.len(),
-                          mem_ptr, mem.len(), self.mbuff.data_offset, self.mbuff.data_end_offset)
+        
+        match self.parent.jit {
+            Some(jit) => Ok(jit(self.mbuff.buffer.as_ptr() as *mut u8,
+                                self.mbuff.buffer.len(),
+                                mem_ptr,
+                                mem.len(), 
+                                self.mbuff.data_offset,
+                                self.mbuff.data_end_offset)),
+            None => Err(Error::new(ErrorKind::Other,
+                                   "Error: program has not been JIT-compiled"))
+        }
     }
 }
 
@@ -1108,7 +1093,7 @@ impl<'a> EbpfVmFixedMbuff<'a> {
 /// let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
 ///
 /// // Provide only a reference to the packet data.
-/// let res = vm.prog_exec(mem);
+/// let res = vm.prog_exec(mem).unwrap();
 /// assert_eq!(res, 0x22cc);
 /// ```
 pub struct EbpfVmRaw<'a> {
@@ -1163,7 +1148,7 @@ impl<'a> EbpfVmRaw<'a> {
     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog1)).unwrap();
     /// vm.set_prog(prog2);
     ///
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 0x22cc);
     /// ```
     pub fn set_prog(&mut self, prog: &'a [u8]) -> Result<(), Error> {
@@ -1237,21 +1222,15 @@ impl<'a> EbpfVmRaw<'a> {
     /// // Register a helper. This helper will store the result of the square root of r1 into r0.
     /// vm.register_helper(1, helpers::sqrti);
     ///
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 0x10000000);
     /// ```
-    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
-        self.parent.register_helper(key, function);
+    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
+        self.parent.register_helper(key, function)
     }
 
     /// Execute the program loaded, with the given packet data.
     ///
-    /// # Panics
-    ///
-    /// This function is currently expected to panic if it encounters any error during the program
-    /// execution, such as out of bounds accesses or division by zero attempts. This may be changed
-    /// in the future (we could raise errors instead).
-    ///
     /// # Examples
     ///
     /// ```
@@ -1268,10 +1247,10 @@ impl<'a> EbpfVmRaw<'a> {
     ///
     /// let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
     ///
-    /// let res = vm.prog_exec(mem);
+    /// let res = vm.prog_exec(mem).unwrap();
     /// assert_eq!(res, 0x22cc);
     /// ```
-    pub fn prog_exec(&self, mem: &'a mut [u8]) -> u64 {
+    pub fn prog_exec(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
         self.parent.prog_exec(mem, &[])
     }
 
@@ -1280,11 +1259,6 @@ impl<'a> EbpfVmRaw<'a> {
     /// If using helper functions, be sure to register them into the VM before calling this
     /// function.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
-    /// unknown eBPF operation code.
-    ///
     /// # Examples
     ///
     /// ```
@@ -1300,21 +1274,19 @@ impl<'a> EbpfVmRaw<'a> {
     /// vm.jit_compile();
     /// ```
     #[cfg(not(windows))]
-    pub fn jit_compile(&mut self) {
+    pub fn jit_compile(&mut self) -> Result<(), Error> {
         let prog = match self.parent.prog { 
             Some(prog) => prog,
-            None => panic!("Error: No program set, call prog_set() to load one"),
+            None => Err(Error::new(ErrorKind::Other,
+                        "Error: No program set, call prog_set() to load one"))?,
         };
-        self.parent.jit = jit::compile(prog, &self.parent.helpers, false, false);
+        self.parent.jit = Some(jit::compile(prog, &self.parent.helpers, false, false)?);
+        Ok(())
     }
 
     /// Execute the previously JIT-compiled program, with the given packet data, in a manner very
     /// similar to `prog_exec()`.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during the execution of the program.
-    ///
     /// # Safety
     ///
     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
@@ -1345,11 +1317,11 @@ impl<'a> EbpfVmRaw<'a> {
     ///
     /// # #[cfg(not(windows))]
     /// unsafe {
-    ///     let res = vm.prog_exec_jit(mem);
+    ///     let res = vm.prog_exec_jit(mem).unwrap();
     ///     assert_eq!(res, 0x22cc);
     /// }
     /// ```
-    pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> u64 {
+    pub unsafe fn prog_exec_jit(&self, mem: &'a mut [u8]) -> Result<u64, Error> {
         let mut mbuff = vec![];
         self.parent.prog_exec_jit(mem, &mut mbuff)
     }
@@ -1391,7 +1363,7 @@ impl<'a> EbpfVmRaw<'a> {
 /// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
 ///
 /// // Provide only a reference to the packet data.
-/// let res = vm.prog_exec();
+/// let res = vm.prog_exec().unwrap();
 /// assert_eq!(res, 0x11);
 /// ```
 pub struct EbpfVmNoData<'a> {
@@ -1439,12 +1411,12 @@ impl<'a> EbpfVmNoData<'a> {
     ///
     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog1)).unwrap();
     ///
-    /// let res = vm.prog_exec();
+    /// let res = vm.prog_exec().unwrap();
     /// assert_eq!(res, 0x2211);
     ///
     /// vm.set_prog(prog2);
     ///
-    /// let res = vm.prog_exec();
+    /// let res = vm.prog_exec().unwrap();
     /// assert_eq!(res, 0x1122);
     /// ```
     pub fn set_prog(&mut self, prog: &'a [u8]) -> Result<(), Error> {
@@ -1511,13 +1483,13 @@ impl<'a> EbpfVmNoData<'a> {
     /// let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
     ///
     /// // Register a helper. This helper will store the result of the square root of r1 into r0.
-    /// vm.register_helper(1, helpers::sqrti);
+    /// vm.register_helper(1, helpers::sqrti).unwrap();
     ///
-    /// let res = vm.prog_exec();
+    /// let res = vm.prog_exec().unwrap();
     /// assert_eq!(res, 0x1000);
     /// ```
-    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) {
-        self.parent.register_helper(key, function);
+    pub fn register_helper(&mut self, key: u32, function: fn (u64, u64, u64, u64, u64) -> u64) -> Result<(), Error> {
+        self.parent.register_helper(key, function)
     }
 
     /// JIT-compile the loaded program. No argument required for this.
@@ -1525,11 +1497,6 @@ impl<'a> EbpfVmNoData<'a> {
     /// If using helper functions, be sure to register them into the VM before calling this
     /// function.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during JIT-compiling, such as the occurrence of an
-    /// unknown eBPF operation code.
-    ///
     /// # Examples
     ///
     /// ```
@@ -1545,18 +1512,12 @@ impl<'a> EbpfVmNoData<'a> {
     /// vm.jit_compile();
     /// ```
     #[cfg(not(windows))]
-    pub fn jit_compile(&mut self) {
-        self.parent.jit_compile();
+    pub fn jit_compile(&mut self) -> Result<(), Error> {
+        self.parent.jit_compile()
     }
 
     /// Execute the program loaded, without providing pointers to any memory area whatsoever.
     ///
-    /// # Panics
-    ///
-    /// This function is currently expected to panic if it encounters any error during the program
-    /// execution, such as memory accesses or division by zero attempts. This may be changed in the
-    /// future (we could raise errors instead).
-    ///
     /// # Examples
     ///
     /// ```
@@ -1569,20 +1530,16 @@ impl<'a> EbpfVmNoData<'a> {
     /// let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
     ///
     /// // For this kind of VM, the `prog_exec()` function needs no argument.
-    /// let res = vm.prog_exec();
+    /// let res = vm.prog_exec().unwrap();
     /// assert_eq!(res, 0x1122);
     /// ```
-    pub fn prog_exec(&self) -> u64 {
+    pub fn prog_exec(&self) -> Result<(u64), Error> {
         self.parent.prog_exec(&mut [])
     }
 
     /// Execute the previously JIT-compiled program, without providing pointers to any memory area
     /// whatsoever, in a manner very similar to `prog_exec()`.
     ///
-    /// # Panics
-    ///
-    /// This function panics if an error occurs during the execution of the program.
-    ///
     /// # Safety
     ///
     /// **WARNING:** JIT-compiled assembly code is not safe, in particular there is no runtime
@@ -1608,11 +1565,11 @@ impl<'a> EbpfVmNoData<'a> {
     ///
     /// # #[cfg(not(windows))]
     /// unsafe {
-    ///     let res = vm.prog_exec_jit();
+    ///     let res = vm.prog_exec_jit().unwrap();
     ///     assert_eq!(res, 0x1122);
     /// }
     /// ```
-    pub unsafe fn prog_exec_jit(&self) -> u64 {
+    pub unsafe fn prog_exec_jit(&self) -> Result<(u64), Error> {
         self.parent.prog_exec_jit(&mut [])
     }
 }

+ 40 - 40
tests/misc.rs

@@ -166,9 +166,9 @@ fn test_vm_block_port() {
     ];
 
     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);
+    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf).unwrap();
 
-    let res = vm.prog_exec(packet);
+    let res = vm.prog_exec(packet).unwrap();
     println!("Program returned: {:?} ({:#x})", res, res);
     assert_eq!(res, 0xffffffff);
 }
@@ -248,11 +248,11 @@ fn test_jit_block_port() {
     ];
 
     let mut vm = rbpf::EbpfVmFixedMbuff::new(Some(prog), 0x40, 0x50).unwrap();
-    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf);
-    vm.jit_compile();
+    vm.register_helper(helpers::BPF_TRACE_PRINTK_IDX, helpers::bpf_trace_printf).unwrap();
+    vm.jit_compile().unwrap();
 
     unsafe {
-        let res = vm.prog_exec_jit(packet);
+        let res = vm.prog_exec_jit(packet).unwrap();
         println!("Program returned: {:?} ({:#x})", res, res);
         assert_eq!(res, 0xffffffff);
     }
@@ -281,7 +281,7 @@ fn test_vm_mbuff() {
     }
 
     let vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem, &mbuff), 0x2211);
+    assert_eq!(vm.prog_exec(mem, &mbuff).unwrap(), 0x2211);
 }
 
 // Program and memory come from uBPF test ldxh.
@@ -308,7 +308,7 @@ fn test_vm_mbuff_with_rust_api() {
     }
 
     let vm = rbpf::EbpfVmMbuff::new(Some(program.into_bytes())).unwrap();
-    assert_eq!(vm.prog_exec(mem, &mbuff), 0x2211);
+    assert_eq!(vm.prog_exec(mem, &mbuff).unwrap(), 0x2211);
 }
 
 // Program and memory come from uBPF test ldxh.
@@ -336,8 +336,8 @@ fn test_jit_mbuff() {
 
     unsafe {
         let mut vm = rbpf::EbpfVmMbuff::new(Some(prog)).unwrap();
-        vm.jit_compile();
-        assert_eq!(vm.prog_exec_jit(mem, &mut mbuff), 0x2211);
+        vm.jit_compile().unwrap();
+        assert_eq!(vm.prog_exec_jit(mem, &mut mbuff).unwrap(), 0x2211);
     }
 }
 
@@ -353,11 +353,11 @@ fn test_vm_jit_ldabsb() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x33);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x33);
 
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x33);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x33);
     };
 }
 
@@ -373,11 +373,11 @@ fn test_vm_jit_ldabsh() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x4433);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x4433);
 
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x4433);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x4433);
     };
 }
 
@@ -393,11 +393,11 @@ fn test_vm_jit_ldabsw() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x66554433);
-    vm.jit_compile();
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x66554433);
+    vm.jit_compile().unwrap();
 
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x66554433);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x66554433);
     };
 }
 
@@ -413,11 +413,11 @@ fn test_vm_jit_ldabsdw() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0xaa99887766554433);
-    vm.jit_compile();
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0xaa99887766554433);
+    vm.jit_compile().unwrap();
 
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0xaa99887766554433);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0xaa99887766554433);
     };
 }
 
@@ -433,7 +433,7 @@ fn test_vm_err_ldabsb_oob() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.prog_exec(mem);
+    vm.prog_exec(mem).unwrap();
 
     // Memory check not implemented for JIT yet.
 }
@@ -446,7 +446,7 @@ fn test_vm_err_ldabsb_nomem() {
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 
     // Memory check not implemented for JIT yet.
 }
@@ -464,11 +464,11 @@ fn test_vm_jit_ldindb() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x88);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x88);
 
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x88);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x88);
     };
 }
 
@@ -485,11 +485,11 @@ fn test_vm_jit_ldindh() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x9988);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x9988);
 
-    vm.jit_compile();
+    vm.jit_compile().unwrap();
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x9988);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x9988);
     };
 }
 
@@ -506,11 +506,11 @@ fn test_vm_jit_ldindw() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x88776655);
-    vm.jit_compile();
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x88776655);
+    vm.jit_compile().unwrap();
 
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0x88776655);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0x88776655);
     };
 }
 
@@ -527,11 +527,11 @@ fn test_vm_jit_ldinddw() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0xccbbaa9988776655);
-    vm.jit_compile();
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0xccbbaa9988776655);
+    vm.jit_compile().unwrap();
 
     unsafe {
-        assert_eq!(vm.prog_exec_jit(mem), 0xccbbaa9988776655);
+        assert_eq!(vm.prog_exec_jit(mem).unwrap(), 0xccbbaa9988776655);
     };
 }
 
@@ -548,7 +548,7 @@ fn test_vm_err_ldindb_oob() {
         0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    vm.prog_exec(mem);
+    vm.prog_exec(mem).unwrap();
 
     // Memory check not implemented for JIT yet.
 }
@@ -562,7 +562,7 @@ fn test_vm_err_ldindb_nomem() {
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 
     // Memory check not implemented for JIT yet.
 }
@@ -571,7 +571,7 @@ fn test_vm_err_ldindb_nomem() {
 #[should_panic(expected = "Error: No program set, call prog_set() to load one")]
 fn test_vm_exec_no_program() {
     let vm = rbpf::EbpfVmNoData::new(None).unwrap();
-    assert_eq!(vm.prog_exec(), 0xBEE);
+    assert_eq!(vm.prog_exec().unwrap(), 0xBEE);
 }
 
 fn verifier_success(_prog: &[u8]) -> Result<(), Error> {
@@ -592,7 +592,7 @@ fn test_verifier_success() {
     let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
     vm.set_verifier(verifier_success).unwrap();
     vm.set_prog(&prog).unwrap();
-    assert_eq!(vm.prog_exec(), 0xBEE);
+    assert_eq!(vm.prog_exec().unwrap(), 0xBEE);
 }
 
 #[test]
@@ -605,5 +605,5 @@ fn test_verifier_fail() {
     let mut vm = rbpf::EbpfVmNoData::new(None).unwrap();
     vm.set_verifier(verifier_fail).unwrap();
     vm.set_prog(&prog).unwrap();
-    assert_eq!(vm.prog_exec(), 0xBEE);
+    assert_eq!(vm.prog_exec().unwrap(), 0xBEE);
 }

ファイルの差分が大きいため隠しています
+ 187 - 187
tests/ubpf_jit_x86_64.rs


+ 12 - 12
tests/ubpf_verifier.rs

@@ -34,7 +34,7 @@ fn test_verifier_err_div_by_zero_imm() {
         div32 r0, 0
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -46,7 +46,7 @@ fn test_verifier_err_endian_size() {
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -57,7 +57,7 @@ fn test_verifier_err_incomplete_lddw() { // Note: ubpf has test-err-incomplete-l
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -67,7 +67,7 @@ fn test_verifier_err_infinite_loop() {
         ja -1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -77,7 +77,7 @@ fn test_verifier_err_invalid_reg_dst() {
         mov r11, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -87,7 +87,7 @@ fn test_verifier_err_invalid_reg_src() {
         mov r0, r11
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -98,7 +98,7 @@ fn test_verifier_err_jmp_lddw() {
         lddw r0, 0x1122334455667788
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -108,7 +108,7 @@ fn test_verifier_err_jmp_out() {
         ja +2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -117,7 +117,7 @@ fn test_verifier_err_no_exit() {
     let prog = assemble("
         mov32 r0, 0").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -133,7 +133,7 @@ fn test_verifier_err_too_many_instructions() {
     prog.append(&mut vec![ 0x95, 0, 0, 0, 0, 0, 0, 0 ]);
 
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -144,7 +144,7 @@ fn test_verifier_err_unknown_opcode() {
         0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -154,5 +154,5 @@ fn test_verifier_err_write_r10() {
         mov r10, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }

+ 108 - 108
tests/ubpf_vm.rs

@@ -38,7 +38,7 @@ fn test_vm_add() {
         add32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 
 #[test]
@@ -64,7 +64,7 @@ fn test_vm_alu64_arith() {
         div r0, r4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x2a);
+    assert_eq!(vm.prog_exec().unwrap(), 0x2a);
 }
 
 #[test]
@@ -94,7 +94,7 @@ fn test_vm_alu64_bit() {
         xor r0, r2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x11);
+    assert_eq!(vm.prog_exec().unwrap(), 0x11);
 }
 
 #[test]
@@ -120,7 +120,7 @@ fn test_vm_alu_arith() {
         div32 r0, r4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x2a);
+    assert_eq!(vm.prog_exec().unwrap(), 0x2a);
 }
 
 #[test]
@@ -148,7 +148,7 @@ fn test_vm_alu_bit() {
         xor32 r0, r2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x11);
+    assert_eq!(vm.prog_exec().unwrap(), 0x11);
 }
 
 #[test]
@@ -159,7 +159,7 @@ fn test_vm_arsh32_high_shift() {
         arsh32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x4);
+    assert_eq!(vm.prog_exec().unwrap(), 0x4);
 }
 
 #[test]
@@ -170,7 +170,7 @@ fn test_vm_arsh() {
         arsh32 r0, 16
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xffff8000);
+    assert_eq!(vm.prog_exec().unwrap(), 0xffff8000);
 }
 
 #[test]
@@ -183,7 +183,7 @@ fn test_vm_arsh64() {
         arsh r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xfffffffffffffff8);
+    assert_eq!(vm.prog_exec().unwrap(), 0xfffffffffffffff8);
 }
 
 #[test]
@@ -195,7 +195,7 @@ fn test_vm_arsh_reg() {
         arsh32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xffff8000);
+    assert_eq!(vm.prog_exec().unwrap(), 0xffff8000);
 }
 
 #[test]
@@ -208,7 +208,7 @@ fn test_vm_be16() {
         0x11, 0x22
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1122);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1122);
 }
 
 #[test]
@@ -221,7 +221,7 @@ fn test_vm_be16_high() {
         0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1122);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1122);
 }
 
 #[test]
@@ -234,7 +234,7 @@ fn test_vm_be32() {
         0x11, 0x22, 0x33, 0x44
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11223344);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11223344);
 }
 
 #[test]
@@ -247,7 +247,7 @@ fn test_vm_be32_high() {
         0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11223344);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11223344);
 }
 
 #[test]
@@ -260,7 +260,7 @@ fn test_vm_be64() {
         0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1122334455667788);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1122334455667788);
 }
 
 #[test]
@@ -274,8 +274,8 @@ fn test_vm_call() {
         call 0
         exit").unwrap();
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes);
-    assert_eq!(vm.prog_exec(), 0x0102030405);
+    vm.register_helper(0, helpers::gather_bytes).unwrap();
+    assert_eq!(vm.prog_exec().unwrap(), 0x0102030405);
 }
 
 #[test]
@@ -292,8 +292,8 @@ fn test_vm_call_memfrob() {
         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08
     ];
     let mut vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    vm.register_helper(1, helpers::memfrob);
-    assert_eq!(vm.prog_exec(mem), 0x102292e2f2c0708);
+    vm.register_helper(1, helpers::memfrob).unwrap();
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x102292e2f2c0708);
 }
 
 // TODO: helpers::trash_registers needs asm!().
@@ -315,7 +315,7 @@ fn test_vm_call_memfrob() {
     //];
     //let mut vm = rbpf::EbpfVmNoData::new(Some(prog)).unwrap();
     //vm.register_helper(2, helpers::trash_registers);
-    //assert_eq!(vm.prog_exec(), 0x4321);
+    //assert_eq!(vm.prog_exec().unwrap(), 0x4321);
 //}
 
 #[test]
@@ -326,7 +326,7 @@ fn test_vm_div32_high_divisor() {
         div32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 
 #[test]
@@ -336,7 +336,7 @@ fn test_vm_div32_imm() {
         div32 r0, 4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 
 #[test]
@@ -347,7 +347,7 @@ fn test_vm_div32_reg() {
         div32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 
 #[test]
@@ -358,7 +358,7 @@ fn test_vm_div64_imm() {
         div r0, 4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x300000000);
+    assert_eq!(vm.prog_exec().unwrap(), 0x300000000);
 }
 
 #[test]
@@ -370,7 +370,7 @@ fn test_vm_div64_reg() {
         div r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x300000000);
+    assert_eq!(vm.prog_exec().unwrap(), 0x300000000);
 }
 
 #[test]
@@ -381,7 +381,7 @@ fn test_vm_early_exit() {
         mov r0, 4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x3);
+    assert_eq!(vm.prog_exec().unwrap(), 0x3);
 }
 
 // uBPF limits the number of user functions at 64. We don't.
@@ -401,7 +401,7 @@ fn test_vm_err_call_unreg() {
         call 63
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -413,7 +413,7 @@ fn test_vm_err_div64_by_zero_reg() {
         div r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -425,7 +425,7 @@ fn test_vm_err_div_by_zero_reg() {
         div32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -437,7 +437,7 @@ fn test_vm_err_mod64_by_zero_reg() {
         mod r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -449,7 +449,7 @@ fn test_vm_err_mod_by_zero_reg() {
         mod32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -459,7 +459,7 @@ fn test_vm_err_stack_out_of_bound() {
         stb [r10], 0
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.prog_exec();
+    vm.prog_exec().unwrap();
 }
 
 #[test]
@@ -468,7 +468,7 @@ fn test_vm_exit() {
         mov r0, 0
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x0);
+    assert_eq!(vm.prog_exec().unwrap(), 0x0);
 }
 
 #[test]
@@ -479,7 +479,7 @@ fn test_vm_ja() {
         mov r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -494,7 +494,7 @@ fn test_vm_jeq_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -510,7 +510,7 @@ fn test_vm_jeq_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -525,7 +525,7 @@ fn test_vm_jge_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -541,7 +541,7 @@ fn test_vm_jle_imm() {
         mov32 r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -559,7 +559,7 @@ fn test_vm_jle_reg() {
         mov r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -574,7 +574,7 @@ fn test_vm_jgt_imm() {
         mov32 r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -591,7 +591,7 @@ fn test_vm_jgt_reg() {
         mov r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -606,7 +606,7 @@ fn test_vm_jlt_imm() {
         mov32 r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -623,7 +623,7 @@ fn test_vm_jlt_reg() {
         mov r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -637,7 +637,7 @@ fn test_vm_jit_bounce() {
         mov r0, r9
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -653,7 +653,7 @@ fn test_vm_jne_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -668,7 +668,7 @@ fn test_vm_jset_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -684,7 +684,7 @@ fn test_vm_jset_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -700,7 +700,7 @@ fn test_vm_jsge_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -718,7 +718,7 @@ fn test_vm_jsge_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -734,7 +734,7 @@ fn test_vm_jsle_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -753,7 +753,7 @@ fn test_vm_jsle_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -768,7 +768,7 @@ fn test_vm_jsgt_imm() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -784,7 +784,7 @@ fn test_vm_jsgt_reg() {
         mov32 r0, 2
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -799,7 +799,7 @@ fn test_vm_jslt_imm() {
         mov32 r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -816,7 +816,7 @@ fn test_vm_jslt_reg() {
         mov32 r0, 1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -824,7 +824,7 @@ fn test_vm_lddw() {
     let prog = assemble("lddw r0, 0x1122334455667788
                          exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1122334455667788);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1122334455667788);
 }
 
 #[test]
@@ -833,7 +833,7 @@ fn test_vm_lddw2() {
         lddw r0, 0x0000000080000000
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x80000000);
+    assert_eq!(vm.prog_exec().unwrap(), 0x80000000);
 }
 
 #[test]
@@ -875,7 +875,7 @@ fn test_vm_ldxb_all() {
         0x08, 0x09
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x9876543210);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x9876543210);
 }
 
 #[test]
@@ -887,7 +887,7 @@ fn test_vm_ldxb() {
         0xaa, 0xbb, 0x11, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11);
 }
 
 #[test]
@@ -900,7 +900,7 @@ fn test_vm_ldxdw() {
         0x77, 0x88, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x8877665544332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x8877665544332211);
 }
 
 #[test]
@@ -953,7 +953,7 @@ fn test_vm_ldxh_all() {
         0x00, 0x08, 0x00, 0x09
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x9876543210);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x9876543210);
 }
 
 #[test]
@@ -996,7 +996,7 @@ fn test_vm_ldxh_all2() {
         0x01, 0x00, 0x02, 0x00
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x3ff);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x3ff);
 }
 
 #[test]
@@ -1008,7 +1008,7 @@ fn test_vm_ldxh() {
         0xaa, 0xbb, 0x11, 0x22, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x2211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x2211);
 }
 
 #[test]
@@ -1022,7 +1022,7 @@ fn test_vm_ldxh_same_reg() {
         0xff, 0xff
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1234);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1234);
 }
 
 #[test]
@@ -1067,7 +1067,7 @@ fn test_vm_ldxw_all() {
         0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x030f0f);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x030f0f);
 }
 
 #[test]
@@ -1079,7 +1079,7 @@ fn test_vm_ldxw() {
         0xaa, 0xbb, 0x11, 0x22, 0x33, 0x44, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x44332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x44332211);
 }
 
 #[test]
@@ -1092,7 +1092,7 @@ fn test_vm_le16() {
         0x22, 0x11
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1122);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1122);
 }
 
 #[test]
@@ -1105,7 +1105,7 @@ fn test_vm_le32() {
         0x44, 0x33, 0x22, 0x11
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11223344);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11223344);
 }
 
 #[test]
@@ -1118,7 +1118,7 @@ fn test_vm_le64() {
         0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1122334455667788);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1122334455667788);
 }
 
 #[test]
@@ -1129,7 +1129,7 @@ fn test_vm_lsh_reg() {
         lsh r0, r7
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x10);
+    assert_eq!(vm.prog_exec().unwrap(), 0x10);
 }
 
 #[test]
@@ -1141,7 +1141,7 @@ fn test_vm_mod() {
         mod32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x5);
+    assert_eq!(vm.prog_exec().unwrap(), 0x5);
 }
 
 #[test]
@@ -1151,7 +1151,7 @@ fn test_vm_mod32() {
         mod32 r0, 3
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x0);
+    assert_eq!(vm.prog_exec().unwrap(), 0x0);
 }
 
 #[test]
@@ -1167,7 +1167,7 @@ fn test_vm_mod64() {
         mod r0, 0x658f1778
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x30ba5a04);
+    assert_eq!(vm.prog_exec().unwrap(), 0x30ba5a04);
 }
 
 #[test]
@@ -1177,7 +1177,7 @@ fn test_vm_mov() {
         mov32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -1187,7 +1187,7 @@ fn test_vm_mul32_imm() {
         mul32 r0, 4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xc);
+    assert_eq!(vm.prog_exec().unwrap(), 0xc);
 }
 
 #[test]
@@ -1198,7 +1198,7 @@ fn test_vm_mul32_reg() {
         mul32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xc);
+    assert_eq!(vm.prog_exec().unwrap(), 0xc);
 }
 
 #[test]
@@ -1209,7 +1209,7 @@ fn test_vm_mul32_reg_overflow() {
         mul32 r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x4);
+    assert_eq!(vm.prog_exec().unwrap(), 0x4);
 }
 
 #[test]
@@ -1219,7 +1219,7 @@ fn test_vm_mul64_imm() {
         mul r0, 4
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x100000004);
+    assert_eq!(vm.prog_exec().unwrap(), 0x100000004);
 }
 
 #[test]
@@ -1230,7 +1230,7 @@ fn test_vm_mul64_reg() {
         mul r0, r1
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x100000004);
+    assert_eq!(vm.prog_exec().unwrap(), 0x100000004);
 }
 
 #[test]
@@ -1247,7 +1247,7 @@ fn test_vm_mul_loop() {
         jne r1, 0x0, -3
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x75db9c97);
+    assert_eq!(vm.prog_exec().unwrap(), 0x75db9c97);
 }
 
 #[test]
@@ -1257,7 +1257,7 @@ fn test_vm_neg64() {
         neg r0
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xfffffffffffffffe);
+    assert_eq!(vm.prog_exec().unwrap(), 0xfffffffffffffffe);
 }
 
 #[test]
@@ -1267,7 +1267,7 @@ fn test_vm_neg() {
         neg32 r0
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xfffffffe);
+    assert_eq!(vm.prog_exec().unwrap(), 0xfffffffe);
 }
 
 #[test]
@@ -1290,7 +1290,7 @@ fn test_vm_prime() {
         jne r4, 0x0, -10
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -1301,7 +1301,7 @@ fn test_vm_rhs32() {
         rsh32 r0, 8
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x00ffffff);
+    assert_eq!(vm.prog_exec().unwrap(), 0x00ffffff);
 }
 
 #[test]
@@ -1312,7 +1312,7 @@ fn test_vm_rsh_reg() {
         rsh r0, r7
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0x1);
+    assert_eq!(vm.prog_exec().unwrap(), 0x1);
 }
 
 #[test]
@@ -1328,7 +1328,7 @@ fn test_vm_stack() {
         ldxdw r0, [r2-16]
         exit").unwrap();
     let vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(), 0xcd);
+    assert_eq!(vm.prog_exec().unwrap(), 0xcd);
 }
 
 #[test]
@@ -1351,9 +1351,9 @@ fn test_vm_stack2() {
         xor r0, 0x2a2a2a2a
         exit").unwrap();
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(0, helpers::gather_bytes);
-    vm.register_helper(1, helpers::memfrob);
-    assert_eq!(vm.prog_exec(), 0x01020304);
+    vm.register_helper(0, helpers::gather_bytes).unwrap();
+    vm.register_helper(1, helpers::memfrob).unwrap();
+    assert_eq!(vm.prog_exec().unwrap(), 0x01020304);
 }
 
 #[test]
@@ -1366,7 +1366,7 @@ fn test_vm_stb() {
         0xaa, 0xbb, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11);
 }
 
 #[test]
@@ -1380,7 +1380,7 @@ fn test_vm_stdw() {
         0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x44332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x44332211);
 }
 
 #[test]
@@ -1393,7 +1393,7 @@ fn test_vm_sth() {
         0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x2211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x2211);
 }
 
 #[test]
@@ -1428,8 +1428,8 @@ fn test_vm_string_stack() {
         mov r0, 0x0
         exit").unwrap();
     let mut vm = rbpf::EbpfVmNoData::new(Some(&prog)).unwrap();
-    vm.register_helper(4, helpers::strcmp);
-    assert_eq!(vm.prog_exec(), 0x0);
+    vm.register_helper(4, helpers::strcmp).unwrap();
+    assert_eq!(vm.prog_exec().unwrap(), 0x0);
 }
 
 #[test]
@@ -1442,7 +1442,7 @@ fn test_vm_stw() {
         0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x44332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x44332211);
 }
 
 #[test]
@@ -1456,7 +1456,7 @@ fn test_vm_stxb() {
         0xaa, 0xbb, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x11);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x11);
 }
 
 #[test]
@@ -1485,7 +1485,7 @@ fn test_vm_stxb_all() {
         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0xf0f2f3f4f5f6f7f8);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0xf0f2f3f4f5f6f7f8);
 }
 
 #[test]
@@ -1503,7 +1503,7 @@ fn test_vm_stxb_all2() {
         0xff, 0xff
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0xf1f9);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0xf1f9);
 }
 
 #[test]
@@ -1535,7 +1535,7 @@ fn test_vm_stxb_chain() {
         0x00, 0x00
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x2a);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x2a);
 }
 
 #[test]
@@ -1552,7 +1552,7 @@ fn test_vm_stxdw() {
         0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x8877665544332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x8877665544332211);
 }
 
 #[test]
@@ -1566,7 +1566,7 @@ fn test_vm_stxh() {
         0xaa, 0xbb, 0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x2211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x2211);
 }
 
 #[test]
@@ -1580,7 +1580,7 @@ fn test_vm_stxw() {
         0xaa, 0xbb, 0xff, 0xff, 0xff, 0xff, 0xcc, 0xdd
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x44332211);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x44332211);
 }
 
 #[test]
@@ -1613,7 +1613,7 @@ fn test_vm_subnet() {
         0x03, 0x00
     ];
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1);
 }
 
 
@@ -1658,7 +1658,7 @@ fn test_vm_tcp_port80_match() {
     ];
     let prog = &PROG_TCP_PORT_80;
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x1);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x1);
 }
 
 #[test]
@@ -1680,7 +1680,7 @@ fn test_vm_tcp_port80_nomatch() {
     ];
     let prog = &PROG_TCP_PORT_80;
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x0);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x0);
 }
 
 #[test]
@@ -1702,7 +1702,7 @@ fn test_vm_tcp_port80_nomatch_ethertype() {
     ];
     let prog = &PROG_TCP_PORT_80;
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x0);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x0);
 }
 
 #[test]
@@ -1724,7 +1724,7 @@ fn test_vm_tcp_port80_nomatch_proto() {
     ];
     let prog = &PROG_TCP_PORT_80;
     let vm = rbpf::EbpfVmRaw::new(Some(prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem), 0x0);
+    assert_eq!(vm.prog_exec(mem).unwrap(), 0x0);
 }
 
 #[test]
@@ -1732,7 +1732,7 @@ fn test_vm_tcp_sack_match() {
     let mut mem = TCP_SACK_MATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem.as_mut_slice()), 0x1);
+    assert_eq!(vm.prog_exec(mem.as_mut_slice()).unwrap(), 0x1);
 }
 
 #[test]
@@ -1740,5 +1740,5 @@ fn test_vm_tcp_sack_nomatch() {
     let mut mem = TCP_SACK_NOMATCH.to_vec();
     let prog = assemble(TCP_SACK_ASM).unwrap();
     let vm = rbpf::EbpfVmRaw::new(Some(&prog)).unwrap();
-    assert_eq!(vm.prog_exec(mem.as_mut_slice()), 0x0);
+    assert_eq!(vm.prog_exec(mem.as_mut_slice()).unwrap(), 0x0);
 }

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません