-
Notifications
You must be signed in to change notification settings - Fork 63
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
Prototype mir_verify
command
#1904
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of "plumbing-related" changes in this PR, which makes this a bit of a slog to review. I've made an effort to highlight what I think are the most interesting changes when compared to the existing LLVM/JVM backends.
-- | TypeShape is used to classify MIR `Ty`s and their corresponding | ||
-- CrucibleTypes into a few common cases. We don't use `Ty` directly because | ||
-- there are some `Ty`s that have identical structure (such as TyRef vs. | ||
-- TyRawPtr) or similar enough structure that we'd rather write only one case | ||
-- (such as `u8` vs `i8` vs `i32`, all primitives/BaseTypes). And we don't use | ||
-- TypeRepr directly because it's lacking information in some cases (notably | ||
-- `TyAdt`, which is always AnyRepr, concealing the actual field types of the | ||
-- struct). | ||
-- | ||
-- In each constructor, the first `M.Ty` is the overall MIR type (e.g., for | ||
-- ArrayShape, this is the TyArray type). The overall `TypeRepr tp` isn't | ||
-- stored directly, but can be computed with `shapeType`. | ||
data TypeShape (tp :: CrucibleType) where |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like I deleted a bunch of code here, but that's only because it's been moved to the new SAWScript.Crucible.MIR.TypeShape
module. I needed to use this code from saw-script
, not just crucible-mir-comp
, which motivated this move.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, this code now lives in SAWScript.Crucible.MIR.MethodSpecIR
, as I needed to use the various type family instances in saw-script
.
TopLevel MIRSpec | ||
~~~~ | ||
|
||
### Running a MIR-based verification |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This manual section is an interesting read, as it describes the conventions that SAW uses when looking up MIR identifiers.
-- | A pair of a simulation-time MIR value ('RegValue') and its corresponding | ||
-- type ('TypeShape'), where the @tp@ type parameter is closed over | ||
-- existentially. SAW's MIR backend passes around 'MIRVal's at simulation time. | ||
data MIRVal where | ||
MIRVal :: TypeShape tp -> RegValue Sym tp -> MIRVal |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a key data type that is used in many places in the MIR backend.
toMIRType :: | ||
Cryptol.TValue -> | ||
Either ToMIRTypeErr Mir.Ty |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This describes how to convert Cryptol types (TValue
s) to MIR types (Mir.Ty
s).
-- | Check if two 'Mir.Ty's are compatible in SAW. This is a slightly coarser | ||
-- notion of equality to reflect the fact that MIR's type system is richer than | ||
-- Cryptol's type system, and some types which would be distinct in MIR are in | ||
-- fact equal when converted to the equivalent Cryptol types. In particular: | ||
-- | ||
-- 1. A @u<N>@ type is always compatible with an @i<N>@ type. For instance, @u8@ | ||
-- is compatible with @i8@, and @u16@ is compatible with @i16@. Note that the | ||
-- bit sizes of both types must be the same. For instance, @u8@ is /not/ | ||
-- compatible with @i16@. | ||
-- | ||
-- 2. The @usize@/@isize@ types are always compatible with @u<N>@/@i<N>@, where | ||
-- @N@ is the number of bits corresponding to the 'Mir.SizeBits' type in | ||
-- "Mir.Intrinsics". (This is a bit unsavory, as the actual size of | ||
-- @usize@/@isize@ is platform-dependent, but this is the current approach.) | ||
-- | ||
-- 3. Compatibility applies recursively. For instance, @[ty_1; N]@ is compatible | ||
-- with @[ty_2; N]@ iff @ty_1@ and @ty_2@ are compatibile. Similarly, a tuple | ||
-- typle @(ty_1_a, ..., ty_n_a)@ is compatible with @(ty_1_b, ..., ty_n_b)@ | ||
-- iff @ty_1_a@ is compatible with @ty_1_b@, ..., and @ty_n_a@ is compatible | ||
-- with @ty_n_b@. | ||
-- | ||
-- See also @checkRegisterCompatibility@ in "SAWScript.Crucible.LLVM.Builtins" | ||
-- and @registerCompatible@ in "SAWScript.Crucible.JVM.Builtins", which fill a | ||
-- similar niche in the LLVM and JVM backends, respectively. | ||
checkCompatibleTys :: Mir.Ty -> Mir.Ty -> Bool | ||
checkCompatibleTys ty1 ty2 = tyView ty1 == tyView ty2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function (and everything that it is defined in terms of) is worth a look.
-- | Returns the Cryptol type of a MIR type, returning 'Nothing' if it is not | ||
-- easily expressible in Cryptol's type system or if it is not currently | ||
-- supported. | ||
cryptolTypeOfActual :: Mir.Ty -> Maybe Cryptol.Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This describes how to convert a MIR type (Mir.Ty
) to a Cryptol Type
.
-- | Given a function name @fnName@, attempt to look up its corresponding | ||
-- 'Mir.DefId'. Currently, the following types of function names are permittd: | ||
-- | ||
-- * @<crate_name>/<disambiguator>::<function_name>: A fully disambiguated name. | ||
-- | ||
-- * @<crate_name>::<function_name>: A name without a disambiguator. In this | ||
-- case, SAW will attempt to look up a disambiguator from the @crateDisambigs@ | ||
-- map. If none can be found, or if there are multiple disambiguators for the | ||
-- given @<crate_name>@, then this will fail. | ||
findDefId :: Map Text (NonEmpty Text) -> Text -> TopLevel Mir.DefId | ||
findDefId crateDisambigs fnName = do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function implements the MIR identifier lookup logic described in the SAW manual.
valueToSC :: | ||
Sym -> | ||
MS.ConditionMetadata -> | ||
OverrideFailureReason MIR -> | ||
Cryptol.TValue -> | ||
MIRVal -> | ||
OverrideMatcher MIR w Term |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This describes how to convert a MIRVal
to a SAWCore Term
.
5deb6b1
to
359a881
Compare
c01a82c
to
1e68229
Compare
1e68229
to
0e24394
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This broadly looks great! Thanks for pointing out places to focus more on. All of my comments are minor.
Also, Github won't let me put comments far away from your changes, so I'm putting one here:
On line 2359 in the manual the part that says "(or the corresponding JVM statements)" should say something like "(or the corresponding JVM or MIR statements)"
0e24394
to
634b884
Compare
This implements just enough scaffolding to support the basics of a `mir_verify` command and related scaffolding, which is one of the main goals of #1859. When I say "basic", I really do mean that: there are quite a few things that do not work currently. These include: * `mir_alloc`/`mir_points_to` do not work yet. * Overrides (unsafe or otherwise) do not work yet. * There is no way to declare variables with `struct` or `enum` types. * Likely other things. These limitations notwithstanding, it is now possible to write MIR specifications for very simple functions such as the ones in the `test_mir_verify_basic` integration test. I will be adding additional capabilities in subsequent patches. Most of the code in this patch is not terribly exciting, as lots of it is cargo-culted from the LLVM and JVM backends. Ideally, we would find a way to deduplicate a lot more of this code, but this will not be straightforward without substantial refactoring in SAW. See #379. In addition to the code itself, I have also expanded the SAW manual to mention the variety of new MIR-related commands added in this patch. Of particular interest is that `mir_verify` allows you to specify function identifiers in multiple ways, which is provided as a convenience to SAW users. See the manual for more details. Checks off several boxes in #1859.
634b884
to
8930c8a
Compare
This implements just enough scaffolding to support the basics of a
mir_verify
command and related scaffolding, which is one of the main goals of #1859. When I say "basic", I really do mean that: there are quite a few things that do not work currently. These include:mir_alloc
/mir_points_to
do not work yet.struct
orenum
types.These limitations notwithstanding, it is now possible to write MIR specifications for very simple functions such as the ones in the
test_mir_verify_basic
integration test. I will be adding additional capabilities in subsequent patches.Most of the code in this patch is not terribly exciting, as lots of it is cargo-culted from the LLVM and JVM backends. Ideally, we would find a way to deduplicate a lot more of this code, but this will not be straightforward without substantial refactoring in SAW. See #379.
In addition to the code itself, I have also expanded the SAW manual to mention the variety of new MIR-related commands added in this patch. Of particular interest is that
mir_verify
allows you to specify function identifiers in multiple ways, which is provided as a convenience to SAW users. See the manual for more details.Checks off several boxes in #1859.