GaloisInc / saw-script

The SAW scripting language.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add `mir_ref_of`/`mir_ref_mut_of` functions for allocating references directly from values

RyanGlScott opened this issue · comments

Currently, in order to allocate a MIR reference that points to a value v, one must do something like this:

ref <- mir_alloc ty;
mir_points_to ref v;

This is a bit verbose, considering that whenever you allocate a reference, you pretty much always want it to point to something. But more than that, it's easy to mess up. Given this Rust code:

pub struct S {
    pub x: u32,
    pub y: u32,
}

pub fn get_x(s: &S) -> u32 {
    s.x
}

Consider this SAW spec example, which assumes that we can point to particular fields of a struct using mir_field_ref (see #1983):

let s_adt = mir_find_adt "example::S" [];

let get_x_42_spec = do {
  s <- mir_alloc (mir_adt s_adt);
  mir_points_to (mir_field_ref s) (mir_term {{ 42 : [32] }});

  mir_execute_func [s];
}

With the way that the crucible-mir memory model works, this would be an error! The entirety of the s reference must be initialized with a contiguous before one can offset into particular fields using mir_field_ref. That is, you'd need to write this spec like so:

let get_x_spec = do {
  s <- mir_alloc (mir_adt s_adt);
  s_val <- mir_fresh_expanded_value "s_val" (mir_adt s_adt);
  mir_points_to s s_val;
  mir_points_to (mir_field_ref s) (mir_term {{ 42 : [32] }});

  mir_execute_func [s];
}

I can foresee this being a common point of confusion. Offering mir_ref_of would make this mistake less likely, since then users would instead write this:

let get_x_spec = do {
  s_val <- mir_fresh_expanded_value "s_val" (mir_adt s_adt);
  s <- mir_ref_of s_val;
  mir_points_to (mir_field_ref s) (mir_term {{ 42 : [32] }});

  mir_execute_func [s];
}

This is a much more natural way to approach things, especially since there is a nice correspondence between mir_ref_of/mir_ref_mut_of and the &/&mut operators in Rust. We might even discourage the use of mir_alloc/mir_alloc_mut in favor of mir_ref_of/mir_ref_mut_of.

Note that if we changed the crucible-mir memory model to support partially initializing more things (see GaloisInc/crucible#1109), then this problem wouldn't be quite as severe, as then you could write mir_points_to (mir_field_ref s) (mir_term {{ 42 : [32] }}) without first needing to initialize the entire struct. Even so, having mir_ref_of would be a nice convenience.