pub struct InstanceHandle {
pub base: InstanceBase,
pub template: TemplateKey,
/* private fields */
}Expand description
The concrete type this plan’s header design decision makes SimHandle
point at (Task 8 adds the SimHandle conversion). layout/arena are
private raw pointers; they stay valid for the life of this handle
(never merely for the life of the StateEngine that minted them — see
below) for two independent reasons (review fix, Task 7 r1 — the
original comment here conflated them and was wrong about arena):
arenapoints at theArenastruct itself, inside the heap allocationarena_ownerbelow (an ownedRc<Arena>clone) keeps alive. That alone is not sufficient for soundness, though:Arena’s own backing storage isUnsafeCell-wrapped and every mutating accessor takes&self, specifically so that no code in this module ever needs to form a fresh&mut Arenaafter this pointer is minted — under Rust’s Stacked/Tree Borrows aliasing model, forming a&mut Arenaat all (regardless of whether it is used to write) invalidates every previously-derived raw pointer’s borrow-stack tag onArena’s own field memory. Seestate::arena’s module doc comment for the full argument and thecargo +nightly mirifailure this fixes.layoutpoints into the heap allocation aBox<StateLayout>owns inside theTemplateRegistryheap allocationtemplates_ownerbelow (an ownedRc<TemplateRegistry>clone) keeps alive, at the specificBox<StateLayout>slot for this handle’stemplate— seeTemplateRegistry’s doc comment — so it stays valid even if that registry’s backingVecreallocates from a laterregistercall.
Review fix (Task 7 r2): arena_owner/templates_owner are this
handle’s own Rc clones, taken at the moment [StateEngine:: allocate_instance] mints the handle — not merely raw pointers derived
from the minting StateEngine’s Rc<Arena>/Rc<TemplateRegistry> with
no owned stake in them. allocate_instance’s signature
(&mut self -> Option<Box<InstanceHandle>>) returns a fully owned value
with no borrow-checked connection back to self — a helper function that
builds a StateEngine, calls allocate_instance, and returns just the
handle is completely ordinary code, and previously, once that
StateEngine (and therefore its Rcs) dropped, arena/layout above
would dangle: cargo +nightly miri test -p vj-sim instance:: reported
“Undefined Behavior: constructing invalid value of type
&state::arena::Arena: encountered a dangling reference (use-after-free)”
at exactly that read site before this fix. Cloning an Rc bumps its
strong count, so as long as any InstanceHandle referencing a given
Arena/TemplateRegistry is alive, that allocation’s refcount cannot
reach zero — independent of whether the StateEngine that minted the
handle is itself still alive. See
dropping_the_state_engine_after_allocating_an_instance_leaves_the_handle_valid
below for the Miri-checked regression test.
Task 10 (ST-027): base/template stay pub (CODEGEN needs base to
mint a SimHandle at instantiation time, per this plan’s header design
decision), but this type never hands a caller a raw pointer it could add
base/a SlotOffset to itself — layout/arena are private, and the only
way to actually reach a signal’s storage through this handle is the
accessor fns (accessor_impl::sv_get_scalar/sv_set_scalar/_wide) or
arena()/layout()’s own pub(crate)-scoped, already-safe accessors,
never a pub fn returning *mut/*const for external base+offset
arithmetic. See super::SlotOffset’s own doc comment for the
superseded-design context this resolves.
Fields§
§base: InstanceBase§template: TemplateKeyImplementations§
Source§impl InstanceHandle
impl InstanceHandle
Sourcepub fn into_sim_handle(self: Box<Self>) -> SimHandle
pub fn into_sim_handle(self: Box<Self>) -> SimHandle
Box::into_raw leak — the handle’s lifetime is the simulation run’s,
matching how sim_init/sim_final bracket it per ARCHITECTURE §5.
Sourcepub unsafe fn from_sim_handle<'a>(h: SimHandle) -> &'a InstanceHandle
pub unsafe fn from_sim_handle<'a>(h: SimHandle) -> &'a InstanceHandle
§Safety
h must be a SimHandle previously produced by Self::into_sim_handle
on an InstanceHandle that has not since been passed to a reclaiming
function (no such function exists this wave — every handle this crate
mints lives for the simulation run’s duration, per ARCHITECTURE §5, so
this precondition is trivially satisfied by every caller in this
wave), and no other thread is concurrently reclaiming/freeing it.