bin-runner #36
1 changed files with 113 additions and 0 deletions
|
|
@ -3339,3 +3339,116 @@ proptest! {
|
|||
prop_assert!(result.is_ok(), "actor must survive any operation sequence");
|
||||
}
|
||||
}
|
||||
|
||||
// ── Integer overflow in guest: wrapping arithmetic doesn't trap ─────────────
|
||||
|
||||
#[test]
|
||||
fn guest_integer_overflow_wraps_silently() {
|
||||
// WASM integers wrap on overflow (no trap). This guest adds i32::MAX + 1
|
||||
// and uses the result as a send offset. The wrapping result (0) should
|
||||
// produce a valid send.
|
||||
let wat = r#"
|
||||
(module
|
||||
(import "swactor" "send" (func $send (param i32 i32 i32)))
|
||||
(memory (export "memory") 1)
|
||||
(func (export "alloc") (param i32) (result i32) i32.const 256)
|
||||
(func (export "handle") (param $ptr i32) (param $len i32)
|
||||
;; i32::MAX + 1 wraps to i32::MIN (-2147483648)
|
||||
;; Use it as... nothing, just verify no trap
|
||||
i32.const 2147483647
|
||||
i32.const 1
|
||||
i32.add
|
||||
drop
|
||||
|
||||
;; Send normally
|
||||
(i32.store8 (i32.const 200) (i32.const 33))
|
||||
local.get $ptr
|
||||
i32.const 200
|
||||
i32.const 1
|
||||
call $send
|
||||
)
|
||||
)
|
||||
"#;
|
||||
let wasm = wat::parse_str(wat).unwrap();
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, wasm).build().unwrap();
|
||||
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), b"wrap")).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let received = inbox.try_recv().expect("wrapping overflow should not trap");
|
||||
assert_eq!(received.0, vec![33]);
|
||||
}
|
||||
|
||||
// ── Multiple messages in one tick to same WASM actor ────────────────────────
|
||||
|
||||
#[test]
|
||||
fn multiple_messages_in_one_tick_all_processed() {
|
||||
// Send 5 messages to a WASM actor before ticking. All should be
|
||||
// processed in the same tick (within the default budget of 64).
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
let actor = WasmActorBuilder::new(engine, guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
let addr = rt.spawn(actor).unwrap();
|
||||
|
||||
for i in 0u8..5 {
|
||||
rt.send_to(addr, framed_msg(inbox.addr(), &[i])).unwrap();
|
||||
}
|
||||
rt.tick();
|
||||
|
||||
let mut received = Vec::new();
|
||||
while let Some(msg) = inbox.try_recv() {
|
||||
received.push(msg.0[0]);
|
||||
}
|
||||
assert_eq!(received, vec![0, 1, 2, 3, 4]);
|
||||
}
|
||||
|
||||
// ── Swap actors: stop WASM, spawn new WASM at conceptually same role ────────
|
||||
|
||||
#[test]
|
||||
fn hot_swap_wasm_actor_works() {
|
||||
// Stop an echo actor, spawn a double actor in its place, verify the new
|
||||
// one works correctly. Tests clean handover of actor lifecycle.
|
||||
let engine = SharedEngine::new().unwrap();
|
||||
|
||||
// Phase 1: echo actor
|
||||
let echo = WasmActorBuilder::new(engine.clone(), guest_wasm("echo"))
|
||||
.build()
|
||||
.unwrap();
|
||||
let rt = Runtime::new(RuntimeConfig::default());
|
||||
let inbox = rt.new_inbox::<ByteMessage>().unwrap();
|
||||
|
||||
let echo_addr = rt.spawn(echo).unwrap();
|
||||
rt.send_to(echo_addr, framed_msg(inbox.addr(), b"echo-phase")).unwrap();
|
||||
rt.tick();
|
||||
let recv = inbox.try_recv().expect("echo should work");
|
||||
assert_eq!(recv.0, b"echo-phase");
|
||||
|
||||
// Stop echo
|
||||
rt.stop_actor(echo_addr).unwrap();
|
||||
rt.tick();
|
||||
rt.tick();
|
||||
|
||||
// Phase 2: double actor
|
||||
let double = WasmActorBuilder::new(engine, guest_wasm("double"))
|
||||
.build()
|
||||
.unwrap();
|
||||
let double_addr = rt.spawn(double).unwrap();
|
||||
|
||||
rt.send_to(double_addr, framed_msg(inbox.addr(), b"double-phase")).unwrap();
|
||||
rt.tick();
|
||||
|
||||
let first = inbox.try_recv().expect("double should send first");
|
||||
let second = inbox.try_recv().expect("double should send second");
|
||||
assert_eq!(first.0, b"double-phase");
|
||||
assert_eq!(second.0, b"double-phase");
|
||||
assert!(inbox.try_recv().is_none());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue