diff --git a/crates/console/prometeu-vm/tests/syscall_multi_return.rs b/crates/console/prometeu-vm/tests/syscall_multi_return.rs new file mode 100644 index 00000000..a2200b07 --- /dev/null +++ b/crates/console/prometeu-vm/tests/syscall_multi_return.rs @@ -0,0 +1,55 @@ +//! Deterministic tests for multi-return syscalls with the slot-based ABI. +use prometeu_bytecode::isa::core::CoreOpCode as OpCode; +use prometeu_bytecode::{FunctionMeta, Value}; +use prometeu_vm::{HostContext, HostReturn, NativeInterface, VirtualMachine}; +use prometeu_hal::vm_fault::VmFault; + +fn enc_op(op: OpCode) -> [u8; 2] { (op as u16).to_le_bytes() } + +#[test] +fn vm_syscall_multi_return_stack_contents() { + // Use a real multi-return syscall id with ret_slots = 4: PadGetUp (0x2200) + // ROM: SYSCALL 0x2200; HALT + let mut rom = Vec::new(); + rom.extend_from_slice(&enc_op(OpCode::Syscall)); + rom.extend_from_slice(&0x2200u32.to_le_bytes()); + rom.extend_from_slice(&enc_op(OpCode::Halt)); + + struct TestNative; + impl NativeInterface for TestNative { + fn syscall( + &mut self, + id: u32, + _args: &[Value], + ret: &mut HostReturn, + _ctx: &mut HostContext, + ) -> Result<(), VmFault> { + assert_eq!(id, 0x2200); + // Push exactly 4 results in a known order. + ret.push_int(11); + ret.push_int(22); + ret.push_bool(true); + ret.push_bounded(7)?; + Ok(()) + } + } + + let mut vm = VirtualMachine::new(rom.clone(), vec![]); + vm.program.functions = std::sync::Arc::from(vec![FunctionMeta { + code_offset: 0, + code_len: rom.len() as u32, + ..Default::default() + }]); + + let mut native = TestNative; + let mut ctx = HostContext::new(None); + vm.prepare_call("0"); + let _ = vm.run_budget(100, &mut native, &mut ctx).expect("VM run failed"); + + // Verify stack order: last pushed is on top + assert_eq!(vm.pop().unwrap(), Value::Bounded(7)); + assert_eq!(vm.pop().unwrap(), Value::Boolean(true)); + assert_eq!(vm.pop().unwrap(), Value::Int64(22)); + assert_eq!(vm.pop().unwrap(), Value::Int64(11)); + assert!(vm.operand_stack.is_empty()); +} diff --git a/crates/console/prometeu-vm/tests/verifier_golden.rs b/crates/console/prometeu-vm/tests/verifier_golden.rs index 766e88f8..351e52a4 100644 --- a/crates/console/prometeu-vm/tests/verifier_golden.rs +++ b/crates/console/prometeu-vm/tests/verifier_golden.rs @@ -269,6 +269,35 @@ fn golden_ok_syscall_args_and_returns() { assert!(res_b[0] >= 1); } +#[test] +fn golden_ok_syscall_multi_returns() { + // Syscall with 0 args and 4 returns: PadGetUp (0x2200) + // Program: SYSCALL 0x2200; RET (ret_slots = 4) + let mut code = Vec::new(); + code.extend_from_slice(&enc_op(OpCode::Syscall)); + code.extend_from_slice(&0x2200u32.to_le_bytes()); // PadGetUp: 0 args, 4 returns + code.extend_from_slice(&enc_op(OpCode::Ret)); + + let functions = func(FunctionMeta { code_offset: 0, code_len: code.len() as u32, return_slots: 4, ..Default::default() }); + let res = Verifier::verify(&code, &functions).unwrap(); + // Max stack height should reach at least 4 due to the syscall's return values + assert!(res[0] >= 4); +} + +#[test] +fn golden_err_syscall_multi_returns_mismatch() { + // Same syscall (PadGetUp: returns 4), but function declares only 3 return slots. + // Program: SYSCALL 0x2200; RET (ret_slots = 3) → verifier must reject due to BadRetStackHeight. + let mut code = Vec::new(); + code.extend_from_slice(&enc_op(OpCode::Syscall)); + code.extend_from_slice(&0x2200u32.to_le_bytes()); + code.extend_from_slice(&enc_op(OpCode::Ret)); + + let functions = func(FunctionMeta { code_offset: 0, code_len: code.len() as u32, return_slots: 3, ..Default::default() }); + let res = Verifier::verify(&code, &functions); + assert_eq!(res, Err(VerifierError::BadRetStackHeight { pc: 6, height: 4, expected: 3 })); +} + #[test] fn golden_err_invalid_func_id() { // Encode a Call with invalid function id (beyond functions.len()) diff --git a/files/TODOs.md b/files/TODOs.md index f2960f5c..e69de29b 100644 --- a/files/TODOs.md +++ b/files/TODOs.md @@ -1,45 +0,0 @@ -# PR-5.6 — Syscall Multi-Return Tests - -### Briefing - -We must ensure multi-return syscalls behave correctly with the slot-based ABI. - -### Target - -* Add deterministic tests covering multi-return behavior. - -### Work items - -* Create or adapt at least one syscall with `ret_slots > 1`. -* Add tests: - - * Verify correct stack results after syscall. - * Verify incorrect caller expectations fail verification. - -### Acceptance checklist - -* [ ] Multi-return syscalls behave correctly. -* [ ] Verifier catches mismatches. -* [ ] `cargo test` passes. - -### Tests - -* New multi-return syscall tests. - -### Junie instructions - -**You MAY:** - -* Add deterministic tests. -* Use existing syscalls or create a simple test-only syscall. - -**You MUST NOT:** - -* Modify syscall semantics to satisfy tests. -* Add nondeterministic behavior. - -**If unclear:** - -* Ask before introducing new test syscalls. - -