diff --git a/prod/clean_arch/dita_v2/rust_backend.py b/prod/clean_arch/dita_v2/rust_backend.py index add817f..5ed721e 100644 --- a/prod/clean_arch/dita_v2/rust_backend.py +++ b/prod/clean_arch/dita_v2/rust_backend.py @@ -231,11 +231,18 @@ class _RustKernelLib: mode: str, verbosity: str, ) -> Dict[str, Any]: + # Keep local refs so CPython's ref-count doesn't free the bytes objects + # before the Rust FFI call completes. ctypes.c_char_p stores a raw pointer + # without incrementing the Python refcount; a temporary would be freed + # after c_char_p() returns, giving Rust a dangling pointer. + _pb = _to_rust_bytes(payload) + _mb = mode.encode("ascii") + _vb = verbosity.encode("ascii") raw = self.lib.dita_kernel_process_intent_json( handle, - ctypes.c_char_p(_to_rust_bytes(payload)), - ctypes.c_char_p(mode.encode("ascii")), - ctypes.c_char_p(verbosity.encode("ascii")), + ctypes.c_char_p(_pb), + ctypes.c_char_p(_mb), + ctypes.c_char_p(_vb), ) return json.loads(self._take_string(raw)) @@ -247,11 +254,14 @@ class _RustKernelLib: mode: str, verbosity: str, ) -> Dict[str, Any]: + _pb = _to_rust_bytes(payload) + _mb = mode.encode("ascii") + _vb = verbosity.encode("ascii") raw = self.lib.dita_kernel_on_venue_event_json( handle, - ctypes.c_char_p(_to_rust_bytes(payload)), - ctypes.c_char_p(mode.encode("ascii")), - ctypes.c_char_p(verbosity.encode("ascii")), + ctypes.c_char_p(_pb), + ctypes.c_char_p(_mb), + ctypes.c_char_p(_vb), ) return json.loads(self._take_string(raw)) @@ -263,11 +273,14 @@ class _RustKernelLib: mode: str, verbosity: str, ) -> Dict[str, Any]: + _pb = _to_rust_bytes(list(payload)) + _mb = mode.encode("ascii") + _vb = verbosity.encode("ascii") raw = self.lib.dita_kernel_reconcile_slots_json( handle, - ctypes.c_char_p(_to_rust_bytes(list(payload))), - ctypes.c_char_p(mode.encode("ascii")), - ctypes.c_char_p(verbosity.encode("ascii")), + ctypes.c_char_p(_pb), + ctypes.c_char_p(_mb), + ctypes.c_char_p(_vb), ) return json.loads(self._take_string(raw)) @@ -294,7 +307,8 @@ class _RustKernelLib: def on_account_event( self, handle: ctypes.c_void_p, event: Dict[str, Any] ) -> Dict[str, Any]: - raw = self.lib.dita_kernel_on_account_event_json(handle, ctypes.c_char_p(_to_rust_bytes(event))) + _eb = _to_rust_bytes(event) + raw = self.lib.dita_kernel_on_account_event_json(handle, ctypes.c_char_p(_eb)) if not raw: return {} return json.loads(self._take_string(raw)) @@ -761,7 +775,7 @@ class ExecutionKernel: self._last_settled_pnl[intent.slot_id] = 0.0 emitted_events = [] all_venue_transitions: List[KernelTransition] = [] - if intent.action in {KernelCommandType.ENTER, KernelCommandType.EXIT}: + if outcome.accepted and intent.action in {KernelCommandType.ENTER, KernelCommandType.EXIT}: emitted_events = self.venue.submit(intent) for event in emitted_events: evt_outcome = self.on_venue_event(event)