Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mir_slice_value and mir_slice_range_value #1948

Merged
merged 2 commits into from
Nov 6, 2023
Merged

mir_slice_value and mir_slice_range_value #1948

merged 2 commits into from
Nov 6, 2023

Conversation

RyanGlScott
Copy link
Contributor

@RyanGlScott RyanGlScott commented Sep 22, 2023

This adds mir_slice_value and mir_slice_range_value functions to the MIR backend, which allow writing specifications involving slice arguments. Currently, only slices to array references are supported, although we may expand the scope of these commands in the future.

Some interesting parts of the implementation:

  1. The TypeShape for slices is ever-so-slightly different from the TypeShape for tuples (TupleShape), so I added a new SliceShape TypeShape to tell them apart.

  2. There is a MirSetupSliceRaw constructor that is only used for crucible-mir-comp purposes at the moment. In the future, we may want to expose a SAWScript command that uses this to allow users to directly construct a slice from a pointer and a length.

  3. mir_alloc now explicitly disallows allocating slice references, so passing mir_slice or mir_str as an argument will throw an error.

This checks off one box in #1859.

--
-- To make it easier to recurse on the 'TypeShape's for the slice's
-- reference and length types, we provide the 'sliceShapeParts' function.
SliceShape :: M.Ty
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note the new addition of SliceShape, which is distinct from TupleShape.

Comment on lines +126 to +154
-- | A slice-related MIR 'SetupValue'.
data MirSetupSlice
= MirSetupSliceRaw (MS.SetupValue MIR) (MS.SetupValue MIR)
-- ^ A \"raw\" slice constructed directly from a pointer and a length.
-- Currently, this is only used by @crucible-mir-comp@. SAWScript offers no
-- way to use this, although we may consider doing so in the future.
| MirSetupSlice (MS.SetupValue MIR)
-- ^ A slice of a reference to a contiguous sequence 'SetupValue'.
-- Currently, this only supports references to arrays.
| MirSetupSliceRange (MS.SetupValue MIR) Int Int
-- ^ A slice of a reference to a contiguous sequence 'SetupValue', where the
-- slice only covers the range specified by the given start and end values
-- (the first and second 'Int', respectively). Currently, this only
-- supports references to arrays, and it only supports concrete ranges.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An important new data type that classifies all of the different ways one can construct slice values in SAW/crucible-mir-comp.

Comment on lines +147 to +255
MirSetupSliceRaw{} ->
panic "typeOfSetupValue" ["MirSetupSliceRaw not yet implemented"]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MirSetupSliceRaw is only used in crucible-mir-comp at the moment, so I didn't bother implemented support for it in SAW.

Comment on lines 262 to 385
MirSetupSlice arrRef -> do
SetupSliceFromArray _elemTpr sliceShp refVal len <-
resolveSetupSliceFromArray bak arrRef
lenVal <- usizeBvLit sym len
pure $ MIRVal sliceShp (Ctx.Empty Ctx.:> RV refVal Ctx.:> RV lenVal)
MirSetupSliceRange arrRef start end -> do
unless (start <= end) $
fail $ "slice index starts at " ++ show start
++ " but ends at " ++ show end
SetupSliceFromArray elemTpr sliceShp refVal0 len <-
resolveSetupSliceFromArray bak arrRef
unless (end < len) $
fail $ "range end index " ++ show end
++ " out of range for slice of length " ++ show len
startBV <- usizeBvLit sym start
refVal1 <- Mir.mirRef_offsetIO bak iTypes elemTpr refVal0 startBV
lenVal <- usizeBvLit sym $ end - start
pure $ MIRVal sliceShp (Ctx.Empty Ctx.:> RV refVal1 Ctx.:> RV lenVal)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is where the magic happens, such as interfacing with the crucible-mir memory model and checking the start/end values of slice ranges.

@@ -2648,6 +2650,77 @@ construct compound values:
* `mir_tuple_value : [MIRValue] -> MIRValue` construct a tuple with the given
list of values as elements.

### MIR slices
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Documentation

@RyanGlScott
Copy link
Contributor Author

RyanGlScott commented Sep 25, 2023

Thinking about this some more, there are a couple of unresolved questions in this PR:

  1. What happens if a user writes mir_alloc (mir_slice ty)? I'm not sure what the semantics of this should be. I suppose we could allocate a slice with a symbolic length, but that goes against the usual SAW philosophy of using fixed-length sequence types whenever possible. Perhaps mir_alloc (mir_slice ty) should just throw an explicit error? Or maybe we should offer an alternative mir_alloc_slice <ty> <len> command for this purpose?
  2. This PR doesn't provide users any way to create &str slices. Indeed, I'm not sure what user interface we'd want to provide for str. I suppose we could allow users to create str references from values of type [u8; N], but this would require users to be very aware of UTF-8 particulars (e.g., a slice of the string "💖" would have to be created from the array [240, 159, 146, 150]). Not to mention that I'm not sure if we'd want to allow things like mir_elem str 1, since Rust generally forbids indexing into strings...

@RyanGlScott
Copy link
Contributor Author

Thinking about this some more:

  1. We disallow mir_alloc (mir_slice ty), since it is unclear what its semantics should be. I also don't think we need to add a special mir_alloc_slice command, as I don't think it would provide much value.
  2. I'm going to punt on the question of string slices for now, as that is a can of worms that I don't want to open just yet. Let's make mir_alloc mir_str an error, just like with mir_alloc (mir_slice ty).

@RyanGlScott
Copy link
Contributor Author

I've implemented the ideas in #1948 (comment), so this is now ready for review.

@RyanGlScott
Copy link
Contributor Author

I've realized that mir_slice_value arr_ref always produces a slice with the same mutability as the underlying arr_ref. A consequence of this is that there is no way to obtain an immutable slice of a mutable array, even though such a thing is possible in Rust. I imagine that we will want to be able to do this, so I think we will need a _mut counterpart to mir_slice_value (and mir_slice_range_value), with the stipulation that you cannot call mir_slice_mut_value on an immutable array.

@RyanGlScott RyanGlScott marked this pull request as draft October 10, 2023 21:04
@spernsteiner
Copy link
Contributor

In general, it might be nice to have a way to cast &mut T to &T in SAWscript. Then you could cast before calling mir_slice_value if needed.

@RyanGlScott
Copy link
Contributor Author

Ah, I like that idea better. A casting function would also be handy if you wanted to take an immutable slice of a static mut array value. The alternative would be to add something like mir_static_immut_ref_of_mut, which would be kind of ridiculous.

@RyanGlScott
Copy link
Contributor Author

I've opened #1954 to track this idea. This idea can be implemented separately and applies to more things than just slices, so I don't think we need to hold up this PR while we wait for that.

@RyanGlScott RyanGlScott marked this pull request as ready for review October 11, 2023 14:16
Copy link
Contributor

@spernsteiner spernsteiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks generally good, except for some confusion around half-open vs inclusive ranges in mir_slice_range_value. It should use half-open for consistency with Rust, where arr[start..end] is much more common than the inclusive version arr[start..=end].

I'm not entirely clear on why we need a separate SliceShape when it's a strict subset of StructShape, but it doesn't seem like it was much trouble to introduce this distinction.

doc/manual/manual.md Outdated Show resolved Hide resolved
doc/manual/manual.md Outdated Show resolved Hide resolved
doc/manual/manual.md Outdated Show resolved Hide resolved
doc/manual/manual.md Outdated Show resolved Hide resolved
doc/manual/manual.md Outdated Show resolved Hide resolved
intTests/test_mir_verify_slices/test.saw Outdated Show resolved Hide resolved
intTests/test_mir_verify_slices/test.saw Show resolved Hide resolved
src/SAWScript/Crucible/MIR/ResolveSetupValue.hs Outdated Show resolved Hide resolved
src/SAWScript/Interpreter.hs Outdated Show resolved Hide resolved
This adds `mir_slice_value` and `mir_slice_range_value` functions to the MIR
backend, which allow writing specifications involving slice arguments.
Currently, only slices to array references are supported, although we may
expand the scope of these commands in the future.

Some interesting parts of the implementation:

1. The `TypeShape` for slices is _ever_-so-slightly different from the
   `TypeShape` for tuples (`TupleShape`), so I added a new `SliceShape`
   `TypeShape` to tell them apart.

2. There is a `MirSetupSliceRaw` constructor that is _only_ used for
   `crucible-mir-comp` purposes at the moment. In the future, we may want to
   expose a SAWScript command that uses this to allow users to directly
   construct a slice from a pointer and a length.

3. `mir_alloc` now explicitly disallows allocating slice references, so
   passing `mir_slice` or `mir_str` as an argument will throw an error.

This checks off one box in #1859.
Copy link
Contributor

@spernsteiner spernsteiner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If all the half-open range stuff is fixed, then I think this is good to merge.

@RyanGlScott RyanGlScott added the PR: ready to merge Magic flag for pull requests to ask Mergify to merge given an approval and a successful CI run label Nov 6, 2023
@mergify mergify bot merged commit 67ef60c into master Nov 6, 2023
39 checks passed
@mergify mergify bot deleted the T1859-mir-slices branch November 6, 2023 17:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
PR: ready to merge Magic flag for pull requests to ask Mergify to merge given an approval and a successful CI run
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants