Skip to content

Commit

Permalink
vm interp: improved tests (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ece authored Dec 3, 2024
1 parent cdf3980 commit e85d314
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 21 deletions.
5 changes: 4 additions & 1 deletion scripts/run_test_vectors.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ else
fi

find dump/test-vectors/instr/fixtures -type f -name '*.fix' -exec ./target/release/test_exec_instr {} + > $LOG_PATH/test_exec_instr.log 2>&1
find dump/test-vectors/txn/fixtures/precompile -type f -name '*.fix' -exec ./target/release/test_exec_txn {} + > $LOG_PATH/test_exec_precompile.log 2>&1
# secp256r1 currently not working, agave has bugs
# find dump/test-vectors/txn/fixtures/precompile -type f -name '*.fix' -exec ./target/release/test_exec_txn {} + > $LOG_PATH/test_exec_precompile.log 2>&1
find dump/test-vectors/txn/fixtures/precompile/ed25519 -type f -name '*.fix' -exec ./target/release/test_exec_txn {} + > $LOG_PATH/test_exec_precompile.log 2>&1
find dump/test-vectors/txn/fixtures/precompile/secp256k1 -type f -name '*.fix' -exec ./target/release/test_exec_txn {} + > $LOG_PATH/test_exec_precompile.log 2>&1
find dump/test-vectors/txn/fixtures/programs -type f -name '*.fix' -exec ./target/release/test_exec_txn {} + > $LOG_PATH/test_exec_txn.log 2>&1
find dump/test-vectors/cpi/fixtures -type f -name '*.fix' -exec ./target/release/test_exec_cpi {} + > $LOG_PATH/test_exec_cpi.log 2>&1
find dump/test-vectors/syscall/fixtures -type f -name '*.fix' -exec ./target/release/test_exec_vm_syscall {} + > $LOG_PATH/test_exec_vm_syscall.log 2>&1
Expand Down
8 changes: 6 additions & 2 deletions src/utils/vm/err_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ pub fn get_fd_vm_err_code(ebpf_err: &EbpfError) -> i32 {
EbpfError::CallDepthExceeded => 11, /* FD_VM_ERR_SIGSTACK */
EbpfError::InvalidInstruction => 12, /* FD_VM_ERR_SIGILL */
EbpfError::AccessViolation(_, _, _, _) => 13, /* FD_VM_ERR_SIGSEGV */
EbpfError::StackAccessViolation(_, _, _, _) => 13, /* FD_VM_ERR_SIGSEGV */
/* FD_VM_ERR_SIGBUS (14) and FD_VM_ERR_SIGRDONLY (15) not used */
EbpfError::ExceededMaxInstructions => 16, /* FD_VM_ERR_SIGCOST*/
EbpfError::DivideByZero => 17, /* FD_VM_ERR_SIGFPE */
EbpfError::DivideByZero => 18, /* FD_VM_ERR_SIGFPE */
/* EbpfError::DivideOverflow isn't possible in SBPFv1 bytecode,
so we don't have a mapping. */
_ => -1,
err => {
eprintln!("unknown error: {:?}", err);
-1
}
}
}

Expand Down
52 changes: 34 additions & 18 deletions src/vm_interp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,19 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec
.register_function(key, name, SyscallStub::vm)
.unwrap();
}
let program_runtime_environment_v1 =
BuiltinProgram::new_loader(unstubbed_runtime.get_config().clone(), stubbed_syscall_reg);

let sbpf_version: SBPFVersion = SBPFVersion::V1;
//TODO: support SBPF version
let sbpf_version = SBPFVersion::V1;
let config = &Config {
aligned_memory_mapping: true,
enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1,
enable_stack_frame_gaps: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
enable_instruction_tracing: true,
..Config::default()
};

let program_runtime_environment_v1 =
BuiltinProgram::new_loader(config.clone(), stubbed_syscall_reg);
let loader = std::sync::Arc::new(program_runtime_environment_v1);

// Setup TestContextObject
Expand All @@ -135,14 +144,6 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec
let mut stack = mempool.get_stack(STACK_SIZE);
let mut heap = AlignedMemory::<HOST_ALIGN>::from(&vec![0; vm_ctx.heap_max as usize]);

/* TODO: should we just use loader.get_config()? */
let config = &Config {
aligned_memory_mapping: true,
enabled_sbpf_versions: SBPFVersion::V1..=SBPFVersion::V1,
enable_stack_frame_gaps: !feature_set.is_active(&bpf_account_data_direct_mapping::id()),
..Config::default()
};

let mut regions = vec![
MemoryRegion::new_readonly(rodata.as_slice(), ebpf::MM_PROGRAM_START),
MemoryRegion::new_writable_gapped(
Expand Down Expand Up @@ -200,14 +201,14 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec

if executable.verify::<RequisiteVerifier>().is_err() {
return Some(SyscallEffects {
error: -1,
error: -2,
..Default::default()
});
}

if executable.jit_compile().is_err() {
return Some(SyscallEffects {
error: -1,
error: -3,
..Default::default()
});
}
Expand All @@ -226,6 +227,14 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec
StableResult::Ok(n) => StableResult::Ok(n),
};

// When a program fails, the register in trace_log are not properly
// captured (they represent the state at the end of the previous ix).
// For simplicity, we ignore them.
let out_registers = match result {
StableResult::Err(_) => &[0; 12],
StableResult::Ok(_) => vm.context_object_pointer.trace_log.last()?,
};

if let StableResult::Err(err) = result.borrow() {
if let EbpfError::ExceededMaxInstructions = err {
/* CU error is difficult to properly compare as there may have been
Expand All @@ -246,10 +255,17 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec
StableResult::Ok(_) => 0,
StableResult::Err(ref ebpf_err) => err_map::get_fd_vm_err_code(ebpf_err).into(),
},
r0: match result {
StableResult::Ok(n) => n,
StableResult::Err(_) => 0,
},
r0: out_registers[0],
r1: out_registers[1],
r2: out_registers[2],
r3: out_registers[3],
r4: out_registers[4],
r5: out_registers[5],
r6: out_registers[6],
r7: out_registers[7],
r8: out_registers[8],
r9: out_registers[9],
r10: out_registers[10],
cu_avail: vm.context_object_pointer.get_remaining(),
frame_count: vm.call_depth,
heap: heap.as_slice().into(),
Expand All @@ -264,7 +280,7 @@ pub fn execute_vm_interp(syscall_context: SyscallContext) -> Option<SyscallEffec
},
StableResult::Err(_) => vm.registers[11],
},
..Default::default() // FIXME: implement rodata
..Default::default()
})
}

Expand Down
11 changes: 11 additions & 0 deletions src/vm_syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,17 @@ pub fn execute_vm_syscall(input: SyscallContext) -> Option<SyscallEffects> {
// Register 0 doesn't seem to contain the result, maybe we're missing some code from agave.
// Regardless, the result is available in vm.program_result, so we can return it from there.
r0,
// Registers are only for vm_interp
r1: 0,
r2: 0,
r3: 0,
r4: 0,
r5: 0,
r6: 0,
r7: 0,
r8: 0,
r9: 0,
r10: 0,
cu_avail: vm.context_object_pointer.get_remaining(),
heap: heap.as_slice().into(),
stack: stack.as_slice().into(),
Expand Down

0 comments on commit e85d314

Please sign in to comment.