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 Prover Redux #1617

Merged
merged 30 commits into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
9cb7e4d
WIP checkin, basic cases of array prover rewrite working.
abakst Mar 9, 2022
46debc3
Add unit tests for implication prover
abakst Mar 11, 2022
60c7438
WIP checkin - array implication prover
abakst Mar 11, 2022
51649d3
Fix bug in skeletonArray range gathering
abakst Mar 11, 2022
fa5a209
Reorg test main
abakst Mar 11, 2022
63377f7
Add some symbolic tests
abakst Mar 12, 2022
2bcc587
Add some tests over fields
abakst Mar 12, 2022
bd3f363
goo begone
abakst Mar 12, 2022
c87ac9d
Some clean up of array reimplementation
abakst Mar 14, 2022
bd0f660
clean up array prover impl
abakst Mar 16, 2022
9f23f02
more testing
abakst Mar 16, 2022
8fc06f9
Revert changed examples
abakst Mar 16, 2022
fa39897
Add comment to last successful case of proveVarLLVMArrayH
abakst Mar 16, 2022
8f6edcf
Revert _CoqProject changes
abakst Mar 16, 2022
e9a1a2a
Revert arrays.saw changes
abakst Mar 16, 2022
bf5945e
WIP checkin, bug fix
abakst Mar 21, 2022
657282e
Finish cleanup
abakst Mar 21, 2022
fa2cdeb
Refactor proveSomeBlockM
abakst Mar 23, 2022
fe46a41
Refactor gatherRangesForArray
abakst Mar 23, 2022
72825cf
Better docs on SImpl_LLVMArrayBorrowed.
abakst Mar 23, 2022
d54a799
Fix errors in refactor
abakst Mar 24, 2022
6217b34
Eliminate array-shaped blocks in `proveVarLLVMArrayH`.
abakst Mar 24, 2022
3876eda
Check totally-borrowed side condition of SImpl_LLVMArrayBorrowed in `…
abakst Mar 24, 2022
232e92a
Make llvmAtomicPermCouldOverlapRange docs more precise
abakst Mar 24, 2022
7ded6f3
Missing haddocks
abakst Mar 24, 2022
a415019
Remove commented-out code
abakst Mar 24, 2022
590265a
Remove unused function.
abakst Mar 24, 2022
1f9375f
Don't throw away rhs borrows.
abakst Mar 24, 2022
2e4c48c
Don't depend on ordering when checking an array is completely borrowed
abakst Mar 25, 2022
7e6b6a8
Merge branch 'master' into array-prover
Mar 28, 2022
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
22 changes: 22 additions & 0 deletions heapster-saw/heapster-saw.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,25 @@ library
Verifier.SAW.Heapster.Widening
GHC-options: -Wall
default-language: Haskell2010

test-suite prover_tests
type: exitcode-stdio-1.0
hs-source-dirs: proverTests

ghc-options: -Wall -threaded
default-language: Haskell2010

main-is: Main.hs

build-depends: base
, directory
, filemanip
, filepath
, process
, tasty
, tasty-hunit
, tasty-expected-failure
, heapster-saw
, hobbits ^>= 1.4
, crucible
, crucible-llvm
239 changes: 239 additions & 0 deletions heapster-saw/proverTests/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE IncoherentInstances #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Main where

import Data.Binding.Hobbits
import Data.Binding.Hobbits.NameMap(singleton)
import Test.Tasty
import Verifier.SAW.Heapster.Permissions
import Lang.Crucible.LLVM.Bytes
import Lang.Crucible.LLVM.MemModel (LLVMPointerType)
import Verifier.SAW.Heapster.Implication (proveVarImpl, checkVarImpl)
import Test.Tasty.HUnit
import Lang.Crucible.Types (BVType)
import GHC.TypeLits

infix 5 ===>
infixl 8 \\
infixl 8 \\\
infixl 8 \\\\

(===>) :: (ToConj p1, ToConj p2) => p1 -> p2 -> Bool
xs ===> ys = conj xs `checkImpl` conj ys

(\\) :: LLVMArrayPerm w -> [LLVMArrayBorrow w] -> LLVMArrayPerm w
(\\) a bs = a { llvmArrayBorrows = llvmArrayBorrows a ++ bs }

(\\\) :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => LLVMArrayPerm 64 -> (a1, a2) -> LLVMArrayPerm 64
(\\\) a (i, l) = a \\ [RangeBorrow (BVRange (toIdx i) (toIdx l))]

(\\\\) :: (ArrayIndexExpr a) => LLVMArrayPerm 64 -> a -> LLVMArrayPerm 64
(\\\\) a i = a \\ [FieldBorrow (toIdx i)]

class t ~ LLVMPointerType 64 => ToAtomic a t | a -> t where
atomic :: a -> AtomicPerm t

instance t ~ LLVMPointerType 64 => ToAtomic (AtomicPerm t) t where
atomic = id

instance t ~ LLVMPointerType 64 => ToAtomic (LLVMArrayPerm 64) t where
atomic = Perm_LLVMArray

class ToConj a where
conj :: a -> ValuePerm (LLVMPointerType 64)

instance (ToAtomic p t, t ~ LLVMPointerType 64) => ToConj p where
conj x = ValPerm_Conj1 (atomic x)

instance (ToAtomic p t, t ~ LLVMPointerType 64) => ToConj [p] where
conj = ValPerm_Conj . fmap atomic

instance (t ~ LLVMPointerType 64) => ToConj [AtomicPerm t] where
conj = ValPerm_Conj

class ArrayIndexExpr a where
toIdx :: a -> PermExpr (BVType 64)

instance ArrayIndexExpr (PermExpr (BVType 64)) where
toIdx = id

instance Integral i => ArrayIndexExpr i where
toIdx i = bvInt (toInteger i)

instance t ~ BVType 64 => ArrayIndexExpr (Name t) where
toIdx x = PExpr_Var x

passes :: Bool -> Assertion
passes = assertBool "should succeed"

fails :: Bool -> Assertion
fails = assertBool "should fail" . not

withName :: (Name (BVType 64) -> Bool) -> Bool
withName k = mbLift (nu k)

checkImpl :: ValuePerm (LLVMPointerType 64) -> ValuePerm (LLVMPointerType 64) -> Bool
checkImpl lhs rhs = mbLift (nu $ \x -> checkVarImpl (pset x) (proveVarImpl x perm_rhs))
where
perm_lhs = lhs
perm_rhs = emptyMb rhs
pset x = PermSet { _varPermMap = singleton x perm_lhs, _distPerms = DistPermsNil }

memblockPerm :: (ArrayIndexExpr a1, ArrayIndexExpr a2) =>
a1 -> a2 -> PermExpr (LLVMShapeType 64) -> LLVMBlockPerm 64
memblockPerm off len shape = LLVMBlockPerm
{ llvmBlockRW = PExpr_Write
, llvmBlockLifetime = PExpr_Always
, llvmBlockOffset = toIdx off
, llvmBlockLen = toIdx len
, llvmBlockShape = shape
}

intValuePerm :: (KnownNat sz, 1 <= sz) => ValuePerm (LLVMPointerType sz)
intValuePerm = ValPerm_Exists $ nu $ \x -> ValPerm_Eq (PExpr_LLVMWord (PExpr_Var x))

fieldShape :: (KnownNat sz, 1 <= sz) => ValuePerm (LLVMPointerType sz) -> PermExpr (LLVMShapeType 64)
fieldShape p = PExpr_FieldShape (LLVMFieldShape p)

fieldPerm :: ArrayIndexExpr a => a -> ValuePerm (LLVMPointerType w) -> LLVMFieldPerm 64 w
fieldPerm off contents = LLVMFieldPerm
{ llvmFieldRW = PExpr_Write
, llvmFieldLifetime = PExpr_Always
, llvmFieldOffset = toIdx off
, llvmFieldContents = contents
}

field :: (KnownNat sz, 1 <= sz, ArrayIndexExpr a) =>
a -> ValuePerm (LLVMPointerType sz) -> AtomicPerm (LLVMPointerType 64)
field off contents = Perm_LLVMField (fieldPerm off contents)

memblock_int64field :: (ArrayIndexExpr a) => a -> AtomicPerm (LLVMPointerType 64)
memblock_int64field off = Perm_LLVMBlock $ memblockPerm off 8 (fieldShape (intValuePerm @64))

memblock_int64array :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => a1 -> a2 -> AtomicPerm (LLVMPointerType 64)
memblock_int64array off len = Perm_LLVMBlock $ memblockPerm off (bvMult 8 (toIdx len)) (arrayShape len 8 (fieldShape (intValuePerm @64)))

int64field :: ArrayIndexExpr a => a -> AtomicPerm (LLVMPointerType 64)
int64field off = field off (intValuePerm :: ValuePerm (LLVMPointerType 64))

int64array :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => a1 -> a2 -> AtomicPerm (LLVMPointerType 64)
int64array off len = Perm_LLVMArray (int64ArrayPerm off len)

int32array :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => a1 -> a2 -> AtomicPerm (LLVMPointerType 64)
int32array off len = Perm_LLVMArray (int32ArrayPerm off len)

int64ArrayPerm :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => a1 -> a2 -> LLVMArrayPerm 64
int64ArrayPerm off len = arrayPerm (toIdx off) (toIdx len) 8 (fieldShape (intValuePerm @ 64))

int32ArrayPerm :: (ArrayIndexExpr a1, ArrayIndexExpr a2) => a1 -> a2 -> LLVMArrayPerm 64
int32ArrayPerm off len = arrayPerm (toIdx off) (toIdx len) 4 (fieldShape (intValuePerm @ 32))

arrayPerm ::
PermExpr (BVType w) ->
PermExpr (BVType w) ->
Bytes ->
PermExpr (LLVMShapeType w) ->
LLVMArrayPerm w
arrayPerm off len stride shape = LLVMArrayPerm
{ llvmArrayRW = PExpr_Write
, llvmArrayLifetime = PExpr_Always
, llvmArrayOffset = off
, llvmArrayLen = len
, llvmArrayStride = stride
, llvmArrayCellShape = shape
, llvmArrayBorrows = []
}

arrayShape :: (ArrayIndexExpr a) => a -> Bytes -> PermExpr (LLVMShapeType 64) -> PermExpr (LLVMShapeType 64)
arrayShape len = PExpr_ArrayShape (toIdx len)

arrayTests :: TestTree
arrayTests =
testGroup "arrayTests"
[ testCase "too small" $ fails $ int64array 0 3 ===> int64array 0 6
, testCase "bigger" $ passes $ int64array 0 6 ===> int64array 0 3

, testGroup "sum of two arrays"
[ testCase "exact" $ passes $ [ int64array 0 3, int64array 24 3 ] ===> int64array 0 6
, testCase "larger" $ passes $ [ int64array 0 3, int64array 24 3 ] ===> int64array 0 5
, testCase "not enough" $ fails $ [ int64array 0 3, int64array 24 3 ] ===> int64array 0 7
]

, testGroup "sum of fields"
[ testCase "some fields" $ passes $
[ int64field 0, int64field 8, int64field 16 ] ===> int64array 0 3
, testCase "some extra fields" $ passes $
[ int64field 0, int64field 8, int64field 16 ] ===> int64array 8 2
, testCase "insufficient fields (1)" $ fails $
[ int64field 0, int64field 8, int64field 16 ] ===> int64array 8 3
, testCase "insufficient fields (2)" $ fails $
[ int64field 0, int64field 8, int64field 16 ] ===> int64array 0 4
]

, testGroup "mix of permission types"
[ testCase "memblocks 1:1" $ passes $
memblock_int64field 0 ===> int64array 0 1
, testCase "memblocks insufficient" $ fails $
[ memblock_int64field 0, memblock_int64field 8 ] ===> int64array 0 3
, testCase "memblocks array 1:1" $ passes $
memblock_int64array 0 3 ===> int64array 0 3
, testCase "memblocks array 2:1" $ passes $
[ memblock_int64array 8 3, memblock_int64array 32 4 ] ===> int64array 8 7
]

, testGroup "symbolic"
[ testCase "borrowed concrete field" $ fails $
withName $ \l ->
int64ArrayPerm 0 l \\\\ 0 ===> int64array 0 l
, testCase "borrowed concrete field" $ passes $
withName $ \l ->
[atomic (int64ArrayPerm 0 l \\\\ 0), int64field 0] ===> int64array 0 l
, testCase "borrowed symbolic field" $ passes $
withName $ \l -> withName $ \i ->
[atomic (int64ArrayPerm 0 l \\\\ i), int64field (bvMult 8 (toIdx i))] ===> int64array 0 l
, testCase "symbolic length append" $ passes $
withName $ \l ->
[int64ArrayPerm 0 l, int64ArrayPerm (bvMult 8 (toIdx l)) l] ===> int64array 0 (bvMult 2 (toIdx l))
]

, testGroup "borrows on rhs"
[ testCase "matched borrows" $ passes $
int64ArrayPerm 0 3 \\\ (1,2) ===> int64ArrayPerm 0 3 \\\ (1,2)

, testCase "sum of matched borrows" $ passes $
[ int64ArrayPerm 0 3 \\\ (1,2) , int64ArrayPerm 24 3 ]
===> int64ArrayPerm 0 6 \\\ (1,2)

, testCase "borrowed lhs/rhs offset" $ passes $
[ int64ArrayPerm 24 3,
int64ArrayPerm 48 2 ] ===> int64ArrayPerm 24 5 \\\ (3, 2)

, testCase "rhs borrow intersects two lhs borrows " $ fails $
int64ArrayPerm 0 10 \\\ (1, 3) \\\ (7,3) ===> int64ArrayPerm 0 10 \\\ (2,6)

, testCase "rhs borrow intersects two lhs borrows " $ passes $
[ int64ArrayPerm 0 5 \\\ (1, 3) \\\ (7,3)
, int64ArrayPerm 8 3
, int64ArrayPerm 56 3
] ===> int64ArrayPerm 0 5 \\\ (2,6)

, testCase "too much lhs borrowed" $ fails $ int64ArrayPerm 0 10 \\\ (5,2) ===> int64ArrayPerm 0 10 \\\ (5,1)

, testCase "sum of borrows" $ passes $
[ int64ArrayPerm 0 3 \\\ (1,2) , int64ArrayPerm 24 4 \\\ (1,2) ]
===> int64ArrayPerm 0 7 \\\ (1,2) \\\ (3,3)
]
]

main :: IO ()
main = defaultMain arrayTests
Loading