-
Notifications
You must be signed in to change notification settings - Fork 42
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
Add more toggles for memory model-related options #783
Comments
In my ideal vision for this, we have a tree-based taxonomy of errors. Then users can specify sets of errors to check for by specifying boolean combinations of sets of errors as named by the taxonomy. For example, we might have a category of |
Ultimately, I'd like every proof obligation that is asserted in a Crucible program to have an associated identifier in this taxonomy, and assertions get filtered in the |
That sounds like a reasonable approach to me. I don't have a clear sense of all possible proof obligations in Crucible, so do you think it would make sense to only add a |
Yes, I think we can add meaningful categories later. As a first step, I'd probably just change the API for assertions to accept a category tag and make all use sites provide a "generic" or "trivial" tag. Later, we can go through and provide meaningful categories. |
I looked into fixing this recently, but I'm a bit stuck on how to implement a crucible/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs Lines 758 to 769 in 7942801
In the event a user disables the |
Yeah, Ideally we'd figure out how to generate an appropriate |
OK, there is already an |
Ah. I was aware of |
You're right, the semantics of LLVM Thinking about it some more, perhaps what we want to do is reinterpret the |
Just to make sure I understand correctly, you're proposing that in the new mode, we change the semantics of the crucible/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Partial.hs Lines 320 to 328 in 168f000
That is, rather than invoking |
Indeed, at about this level of the API is where I was thinking about changing things. |
Just a bit more flavor: in the current mode a |
I've tried a couple of approaches to plumb through type information, and I'm encountering difficulties with both approaches:
Approach (1) requires changing the logic of several functions that match on For this reason, I decided to implement approach (2), as it seems less invasive. I'm still not confident that my patch which implements this approach is correct, however. Here is a WIP patch: diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs
index afea8c0b..b55d84ff 100644
--- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs
+++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel.hs
@@ -559,7 +559,7 @@ doLoad ::
IO (RegValue sym tp)
doLoad sym mem ptr valType tpr alignment = do
unpackMemValue sym tpr =<<
- Partial.assertSafe sym =<<
+ Partial.assertSafe sym valType =<<
loadRaw sym mem ptr valType alignment
-- | Store a 'RegValue' in memory. Both the 'StorageType' and 'TypeRepr'
diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
index 7f9ec7d5..c1f96a01 100644
--- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
+++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
@@ -1247,7 +1247,7 @@ writeMemWithAllocationCheck is_allocated sym w gsym ptr tp alignment val mem = d
=<< traverse subFn (loadBitvector off 1 0 (ValueViewVar tp))
-- TODO! we're abusing assertSafe here a little
- v <- Partial.assertSafe sym partial_byte
+ v <- Partial.assertSafe sym tp partial_byte
case v of
LLVMValInt _ byte
| Just Refl <- testEquality (knownNat @8) (bvWidth byte) -> do
diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Partial.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Partial.hs
index 51ed3a10..a1869b6f 100644
--- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Partial.hs
+++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Partial.hs
@@ -320,14 +320,20 @@ totalLLVMVal sym = NoErr (truePred sym)
-- | Take a partial value and assert its safety
assertSafe :: (IsSymInterface sym)
=> sym
+ -> StorageType
-> PartLLVMVal sym
-> IO (LLVMVal sym)
-assertSafe sym (NoErr p v) =
+assertSafe sym tp (NoErr p v) =
do let rsn = AssertFailureSimError "Error during memory load" ""
+ unless (tp == Value.llvmValStorableType v) $
+ panic "RGS assertSafe"
+ [ "tp: " ++ show tp
+ , "llvmValStorableType v: " ++ show (Value.llvmValStorableType v)
+ ]
assert sym p rsn
return v
-assertSafe sym (Err p) = do
+assertSafe sym _ (Err p) = do
do let rsn = AssertFailureSimError "Error during memory load" ""
loc <- getCurrentProgramLoc sym
let err = SimError loc rsn
diff --git a/crucible-llvm/test/TestMemory.hs b/crucible-llvm/test/TestMemory.hs
index 73d7c049..2d029ed2 100644
--- a/crucible-llvm/test/TestMemory.hs
+++ b/crucible-llvm/test/TestMemory.hs
@@ -375,7 +375,7 @@ testPointerStore = testCase "pointer store" $ withMem LLVMD.BigEndian $ \sym mem
noAlignment
-- Assert that the read pointer is equal to the original pointer
- base_ptr1_back_safe <- LLVMMem.assertSafe sym base_ptr1_back
+ base_ptr1_back_safe <- LLVMMem.assertSafe sym pointer_storage_type base_ptr1_back
is_equal <- LLVMMem.testEqual sym base_ptr1_val base_ptr1_back_safe
case is_equal of
Nothing -> assertFailure "testEqual failed"
diff --git a/crucible-wasm/src/Lang/Crucible/Wasm/Memory.hs b/crucible-wasm/src/Lang/Crucible/Wasm/Memory.hs
index 3bf0202b..5c9e0d49 100644
--- a/crucible-wasm/src/Lang/Crucible/Wasm/Memory.hs
+++ b/crucible-wasm/src/Lang/Crucible/Wasm/Memory.hs
@@ -201,11 +201,12 @@ wasmStoreDouble sym off v mem =
wasmLoadInt :: (1 <= w, IsSymInterface sym) => sym -> SymBV sym 32 -> NatRepr w -> WasmMemImpl sym -> IO (SymBV sym w)
wasmLoadInt sym off w mem =
do let bs = Bytes (intValue w `div` 8)
+ tp = bitvectorType bs
assertInBounds sym off bs mem
p <- mkPtr sym off
let ?recordLLVMAnnotation = \_ _ -> return ()
- pval <- G.readMem sym knownNat Nothing p (bitvectorType bs) noAlignment (wasmMemHeap mem)
- Partial.assertSafe sym pval >>= \case
+ pval <- G.readMem sym knownNat Nothing p tp noAlignment (wasmMemHeap mem)
+ Partial.assertSafe sym tp pval >>= \case
LLVMValZero _ -> bvLit sym w (BV.zero w)
LLVMValInt _ v | Just Refl <- testEquality (bvWidth v) w -> pure v
_ -> panic "wasmLoadInt" ["type mismatch"]
@@ -222,7 +223,7 @@ wasmLoadFloat sym off mem =
p <- mkPtr sym off
let ?recordLLVMAnnotation = \_ _ -> return ()
pval <- G.readMem sym knownNat Nothing p floatType noAlignment (wasmMemHeap mem)
- Partial.assertSafe sym pval >>= \case
+ Partial.assertSafe sym floatType pval >>= \case
LLVMValZero _ -> iFloatLitRational sym SingleFloatRepr 0
LLVMValFloat SingleSize v -> pure v
_ -> panic "wasmLoadFloat" ["type mismatch"]
@@ -239,7 +240,7 @@ wasmLoadDouble sym off mem =
p <- mkPtr sym off
let ?recordLLVMAnnotation = \_ _ -> return ()
pval <- G.readMem sym knownNat Nothing p doubleType noAlignment (wasmMemHeap mem)
- Partial.assertSafe sym pval >>= \case
+ Partial.assertSafe sym doubleType pval >>= \case
LLVMValZero _ -> iFloatLitRational sym DoubleFloatRepr 0
LLVMValFloat DoubleSize v -> pure v
_ -> panic "wasmLoadDouble" ["type mismatch"] I would expect
|
This type mismatch ultimately arises from diff --git a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
index 7f9ec7d5..c1f96a01 100644
--- a/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
+++ b/crucible-llvm/src/Lang/Crucible/LLVM/MemModel/Generic.hs
@@ -1247,7 +1247,7 @@ writeMemWithAllocationCheck is_allocated sym w gsym ptr tp alignment val mem = d
=<< traverse subFn (loadBitvector off 1 0 (ValueViewVar tp))
-- TODO! we're abusing assertSafe here a little
- v <- Partial.assertSafe sym partial_byte
+ v <- Partial.assertSafe sym tp partial_byte
case v of
LLVMValInt _ byte
| Just Refl <- testEquality (knownNat @8) (bvWidth byte) -> do I'm sure I'm doing this wrong, but at the same time, I'm not sure what the correct way to compute the |
The |
OK, I've paged in what that code is doing. The type you pass into that particular |
It turns out that just adding the option to read from unwritten memory is a pretty formidable task on its own, even without the proposed taxonomy of errors layered on top of it. I've submitted a draft PR for the former at #794, which doesn't quite work yet, but is getting closer. |
In order to make the original program in #783 (comment) pass through Crux without failing, we'll need to avoid generating the following obligations:
The latter two work by attaching additional |
Thinking about this some more, maybe we don't need (for now, at least) specific toggles for all the various kinds of errors here (e.g. bad alignment vs unreadable region). Perhaps it suffices to have a single toggle for all classes of memory load errors. |
This renamed the `read-unwritten-memory` Crux option to `lax-loads-and-stores`, reflecting its new purpose of being a catch-all option for relaxing various validity checks related to loads and stores. This is meant for SV-COMP mode, which has a different view of fatal errors than Crucible does. This addresses some of the goals of #783. It does not address the goal of designing a generic taxonomy of errors.
Now that #808 has landed, the only remaining task is to implement a taxonomy of errors, as suggested in #783 (comment). Since the original goal of this ticket was to implement what is now known as |
SV-COMP has various benchmark programs that are expected to verify despite technically having memory model issues. For instance,
s3_clnt.blast.01.i.cil-1.c
is expected to verify successfully in theunreach-call
category, but Crux will currently reject it thusly:In order to make Crux handle these sorts of SV-COMP programs, we'll need to add a toggle to suppress this particular class of error. We already have various memory-model–related toggles, however. These include
lax-pointer-ordering
andlax-constant-equality
. Although we could just tack on more one-off toggles like these, it might make sense to consolidate all of these options somehow, similarly to howub-sanitizers
consolidates toggles related to undefined behavior.The text was updated successfully, but these errors were encountered: