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

Heapster array permission bug fixes #1659

Merged
merged 8 commits into from
May 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified heapster-saw/examples/arrays.bc
Binary file not shown.
12 changes: 12 additions & 0 deletions heapster-saw/examples/arrays.c
Original file line number Diff line number Diff line change
Expand Up @@ -122,3 +122,15 @@ uint64_t even_odd_sums_diff(const uint64_t *arr, size_t len) {
}
return sum;
}

uint64_t alloc_sum_array_test (void) {
uint64_t X[8];
X[0] = 0; X[1] = 1; X[2] = 2; X[3] = 3;
X[4] = 4; X[5] = 5; X[6] = 6; X[7] = 7;
/*
for (uint64_t i = 0; i < 16; ++i) {
X[i] = i;
}
*/
return sum_inc_ptr_64 (X, 8);
}
2 changes: 2 additions & 0 deletions heapster-saw/examples/arrays.saw
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,6 @@ heapster_typecheck_fun env "even_odd_sums_diff"
"(l:bv 64). arg0:array(W,0,<2*l,*8,fieldsh(int64<>)), arg1:eq(llvmword(2*l)) -o \
\ arg0:array(W,0,<2*l,*8,fieldsh(int64<>)), arg1:true, ret:int64<>";

heapster_typecheck_fun env "alloc_sum_array_test" "(). empty -o ret:int64<>";

heapster_export_coq env "arrays_gen.v";
Binary file modified heapster-saw/examples/rust_data.bc
Binary file not shown.
2 changes: 1 addition & 1 deletion heapster-saw/examples/rust_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ pub fn extract_from_result_infallible <'a> (r:&'a Result<Infallible,u64>) -> u64
/* Sum of two types; yes, this is like Result, but defined locally so we can
* make an impl block on it */
#[derive(Clone, Debug, PartialEq)]
#[repr(C)]
#[repr(C,u64)]
pub enum Sum<X,Y> {
Left (X),
Right (Y)
Expand Down
391 changes: 221 additions & 170 deletions heapster-saw/src/Verifier/SAW/Heapster/Implication.hs

Large diffs are not rendered by default.

122 changes: 91 additions & 31 deletions heapster-saw/src/Verifier/SAW/Heapster/Permissions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -2659,6 +2659,11 @@ mbLLVMArrayLen = mbMapCl $(mkClosed [| llvmArrayLen |])
mbLLVMArrayLenBytes :: (1 <= w, KnownNat w) => Mb ctx (LLVMArrayPerm w) -> Mb ctx (PermExpr (BVType w))
mbLLVMArrayLenBytes = mbMapCl $(mkClosed [| llvmArrayLengthBytes |])

-- | Get the range of offsets of an array permission in binding
mbLLVMArrayRange :: (1 <= w, KnownNat w) => Mb ctx (LLVMArrayPerm w) ->
Mb ctx (BVRange w)
mbLLVMArrayRange = mbMapCl $(mkClosed [| llvmArrayRange |])

-- | Get the stride of an array permission in binding
mbLLVMArrayStride :: Mb ctx (LLVMArrayPerm w) -> Bytes
mbLLVMArrayStride = mbLift . mbMapCl $(mkClosed [| llvmArrayStride |])
Expand Down Expand Up @@ -4957,6 +4962,15 @@ llvmArrayCellsToOffsets :: (1 <= w, KnownNat w) => LLVMArrayPerm w ->
llvmArrayCellsToOffsets ap (BVRange cell num_cells) =
BVRange (llvmArrayCellToOffset ap cell) (llvmArrayCellToOffset ap num_cells)

-- | Convert a range of absolute byte offsets to a range of cell numbers in an
-- array permission, if possible
llvmArrayAbsOffsetsToCells :: (1 <= w, KnownNat w) => LLVMArrayPerm w ->
BVRange w -> Maybe (BVRange w)
llvmArrayAbsOffsetsToCells ap rng
| Just cell <- matchLLVMArrayCell ap (bvRangeOffset rng) =
Just $ BVRange cell (bvDiv (bvRangeLength rng) (llvmArrayStride ap))
llvmArrayAbsOffsetsToCells _ _ = Nothing

-- | Return the clopen range @[0,len)@ of the cells of an array permission
llvmArrayCells :: (1 <= w, KnownNat w) => LLVMArrayPerm w -> BVRange w
llvmArrayCells ap = BVRange (bvInt 0) (llvmArrayLen ap)
Expand Down Expand Up @@ -5031,18 +5045,27 @@ permToLLVMArrayBorrow ap p =

_ -> Nothing

-- | Get the range of offsets spanned by a borrow relative to the start of an
-- array permission
llvmArrayBorrowRange :: (1 <= w, KnownNat w) =>
LLVMArrayPerm w -> LLVMArrayBorrow w -> BVRange w
llvmArrayBorrowRange ap borrow =
llvmArrayCellsToOffsets ap (llvmArrayBorrowCells borrow)

-- | Get the "absolute" range of offsets spanned by a borrow relative to the
-- pointer with this array permission
llvmArrayAbsBorrowRange :: (1 <= w, KnownNat w) =>
LLVMArrayPerm w -> LLVMArrayBorrow w -> BVRange w
LLVMArrayPerm w -> LLVMArrayBorrow w -> BVRange w
llvmArrayAbsBorrowRange ap borrow =
range { bvRangeOffset = bvAdd (llvmArrayOffset ap) (bvRangeOffset range) }
where
range = llvmArrayCellsToOffsets ap (llvmArrayBorrowCells borrow)

-- | Get the absolute offset at which an array borrow starts
llvmArrayBorrowAbsOffset :: (1 <= w, KnownNat w) => LLVMArrayPerm w ->
LLVMArrayBorrow w -> PermExpr (BVType w)
llvmArrayBorrowAbsOffset ap b = bvRangeOffset $ llvmArrayAbsBorrowRange ap b

-- | Add a borrow to an 'LLVMArrayPerm'
llvmArrayAddBorrow :: LLVMArrayBorrow w -> LLVMArrayPerm w -> LLVMArrayPerm w
llvmArrayAddBorrow b ap = ap { llvmArrayBorrows = b : llvmArrayBorrows ap }
Expand Down Expand Up @@ -5106,7 +5129,7 @@ llvmArrayBorrowsPermuteTo ap bs =
-- | Add a cell offset to an 'LLVMArrayBorrow', meaning we change the borrow to
-- be relative to an array with that many more cells added to the front
cellOffsetLLVMArrayBorrow :: (1 <= w, KnownNat w) => PermExpr (BVType w) ->
LLVMArrayBorrow w -> LLVMArrayBorrow w
LLVMArrayBorrow w -> LLVMArrayBorrow w
cellOffsetLLVMArrayBorrow off (FieldBorrow ix) =
FieldBorrow (bvAdd ix off)
cellOffsetLLVMArrayBorrow off (RangeBorrow rng) =
Expand All @@ -5119,6 +5142,8 @@ llvmArrayBorrowCells :: (KnownNat w, 1 <= w) => LLVMArrayBorrow w -> BVRange w
llvmArrayBorrowCells (FieldBorrow idx) = bvRangeOfIndex idx
llvmArrayBorrowCells (RangeBorrow r) = r

-- FIXME: delete? not used, and should be implementable via bvRangeDelete
{-
-- | Given a borrow @borrow@ and range (of borrowed indices) @rng@,
-- delete @rng@ from @borrow@, and return the borrows that describe
-- the remaining borrowed cells.
Expand All @@ -5139,27 +5164,42 @@ llvmArrayBorrowRangeDelete borrow rng =
, bvEq (bvRangeLength new_range) (bvInt 1) = Just $ FieldBorrow idx
| otherwise =
error "llvmArrayBorrowRangeDelete: found non unit new_range for FieldBorrow"
-}

-- | Return whether or not the borrows in @ap@ cover the range of cells [0, len). Specifically,
-- if the borrowed cells (as ranges) can be arranged in as a sequence of non-overlapping but contiguous
-- ranges (in the sense of @bvCouldEqual@) that extends at least as far as @len@ (in the sense of @bvLeq@)
llvmArrayIsBorrowed ::
(HasCallStack, 1 <= w, KnownNat w) =>
LLVMArrayPerm w ->
Bool
-- | Take in a range @rng@ and a list of ranges @rngs@ and try to find a
-- sequence of non-overlapping but contiguous ranges in @rngs@ that covers the
-- desired range @rng@
gatherCoveringRanges :: (1 <= w, KnownNat w) => BVRange w -> [BVRange w] ->
Maybe [BVRange w]
gatherCoveringRanges rng _ | bvIsZero (bvRangeLength rng) = Just []
gatherCoveringRanges rng rngs
| Just i <- findIndex (bvInRange (bvRangeOffset rng)) rngs
, rng' <- rngs!!i =
-- If rng' covers all of rng, then we are done
if bvRangeSubset rng rng' then Just [rng'] else
(rng' :) <$>
gatherCoveringRanges (bvRangeSuffix (bvRangeEnd rng') rng)
(deleteNth i rngs)
gatherCoveringRanges _ _ = Nothing

-- | Test if the borrows in @ap@ cover a given range of offsets. That is, test
-- if the ranges of the borrows in @ap@ can be arranged as a sequence of
-- non-overlapping but contiguous ranges that extends at least as far as @len@
-- (in the sense of @bvLeq@).
llvmArrayRangeIsBorrowed :: (HasCallStack, 1 <= w, KnownNat w) =>
LLVMArrayPerm w -> BVRange w -> Bool
llvmArrayRangeIsBorrowed ap rng =
isJust $ gatherCoveringRanges rng $
map (llvmArrayBorrowAbsOffsets ap) (llvmArrayBorrows ap)

-- | Test whether the borrows in @ap@ cover the range of cells @[0, len)@. That
-- is, test if the ranges of the borrows in @ap@ can be arranged as a sequence
-- of non-overlapping but contiguous ranges that extends at least as far as
-- @len@ (in the sense of @bvLeq@)
llvmArrayIsBorrowed :: (HasCallStack, 1 <= w, KnownNat w) => LLVMArrayPerm w ->
Bool
llvmArrayIsBorrowed ap =
go (bvInt 0) (llvmArrayBorrowCells <$> llvmArrayBorrows ap)
where
end = bvRangeEnd (llvmArrayCells ap)

go off borrows
| bvLeq end off
= True
| Just i <- findIndex (permForOff off) borrows
= go (bvAdd off (bvRangeLength (borrows!!i))) (deleteNth i borrows)
go _ _ = False

permForOff o b = bvCouldEqual o (bvRangeOffset b)
llvmArrayRangeIsBorrowed ap (llvmArrayAbsOffsets ap)

-- | Test if a byte offset @o@ statically aligns with a statically-known offset
-- into some array cell, i.e., whether
Expand Down Expand Up @@ -5328,6 +5368,7 @@ llvmMakeSubArray ap off len
, cell_rng <- BVRange cell len =
ap { llvmArrayOffset = off, llvmArrayLen = len,
llvmArrayBorrows =
map (cellOffsetLLVMArrayBorrow (bvNegate cell)) $
filter (not . all bvPropHolds .
llvmArrayBorrowsDisjoint (RangeBorrow cell_rng)) $
llvmArrayBorrows ap }
Expand Down Expand Up @@ -5367,23 +5408,42 @@ llvmPermContainsOffsetBool :: (1 <= w, KnownNat w) => PermExpr (BVType w) ->
llvmPermContainsOffsetBool off p =
maybe False snd $ llvmPermContainsOffset off p

-- | Test if an atomic LLVM permission contains (in the sense of 'bvPropHolds')
-- all offsets in a given range
llvmAtomicPermContainsRange :: (1 <= w, KnownNat w) => BVRange w ->
AtomicPerm (LLVMPointerType w) -> Bool
llvmAtomicPermContainsRange rng (Perm_LLVMArray ap)
-- | Build the propositions stating that an atomic LLVM permission contains all
-- offsets in a given range
llvmAtomicPermContainsRangeProps :: (1 <= w, KnownNat w) => BVRange w ->
AtomicPerm (LLVMPointerType w) ->
Maybe [BVProp w]
llvmAtomicPermContainsRangeProps rng (Perm_LLVMArray ap)
| Just ix1 <- matchLLVMArrayIndex ap (bvRangeOffset rng)
, Just ix2 <- matchLLVMArrayIndex ap (bvRangeEnd rng)
, props <- llvmArrayBorrowInArray ap (RangeBorrow $ BVRange
(llvmArrayIndexCell ix1)
(llvmArrayIndexCell ix2)) =
Just props
llvmAtomicPermContainsRangeProps rng (Perm_LLVMField fp) =
Just $ bvPropRangeSubset rng (llvmFieldRange fp)
llvmAtomicPermContainsRangeProps rng (Perm_LLVMBlock bp) =
Just $ bvPropRangeSubset rng (llvmBlockRange bp)
llvmAtomicPermContainsRangeProps _ _ = Nothing

-- | Test if an atomic LLVM permission contains (in the sense of 'bvPropHolds')
-- all offsets in a given range
llvmAtomicPermContainsRange :: (1 <= w, KnownNat w) => BVRange w ->
AtomicPerm (LLVMPointerType w) -> Bool
llvmAtomicPermContainsRange rng p
| Just props <- llvmAtomicPermContainsRangeProps rng p =
all bvPropHolds props
llvmAtomicPermContainsRange rng (Perm_LLVMField fp) =
bvRangeSubset rng (llvmFieldRange fp)
llvmAtomicPermContainsRange rng (Perm_LLVMBlock bp) =
bvRangeSubset rng (llvmBlockRange bp)
llvmAtomicPermContainsRange _ _ = False

-- | Test if an atomic LLVM permission could contain (in the sense of
-- 'bvPropCouldHold') all offsets in a given range
llvmAtomicPermCouldContainRange :: (1 <= w, KnownNat w) => BVRange w ->
AtomicPerm (LLVMPointerType w) -> Bool
llvmAtomicPermCouldContainRange rng p
| Just props <- llvmAtomicPermContainsRangeProps rng p =
all bvPropCouldHold props
llvmAtomicPermCouldContainRange _ _ = False

-- | Test if an atomic LLVM permission has a range that overlaps with (in the
-- sense of 'bvPropHolds') the offsets in a given range
llvmAtomicPermOverlapsRange :: (1 <= w, KnownNat w) => BVRange w ->
Expand Down Expand Up @@ -5437,7 +5497,7 @@ llvmArrayToBlocks _ = Nothing
llvmArrayBorrowOffsets :: (1 <= w, KnownNat w) => LLVMArrayPerm w ->
LLVMArrayBorrow w -> BVRange w
llvmArrayBorrowOffsets ap (FieldBorrow ix) =
bvRangeOfIndex $ llvmArrayCellToOffset ap ix
BVRange (llvmArrayCellToOffset ap ix) (bvInt $ toInteger $ llvmArrayStride ap)
llvmArrayBorrowOffsets ap (RangeBorrow r) = llvmArrayCellsToOffsets ap r

-- | Get the range of byte offsets represented by an array borrow relative to
Expand Down