@@ -5,13 +5,12 @@ module EVM.SymExec where
5
5
6
6
import Control.Concurrent.Async (concurrently , mapConcurrently )
7
7
import Control.Concurrent.Spawn (parMapIO , pool )
8
- import Control.Concurrent.STM (TVar , readTVarIO , newTVarIO )
9
8
import Control.Monad (when , forM_ , forM )
10
9
import Control.Monad.IO.Unlift
11
10
import Control.Monad.Operational qualified as Operational
12
11
import Control.Monad.ST (RealWorld , stToIO , ST )
13
12
import Control.Monad.State.Strict (runStateT )
14
- import Data.Bifunctor (second , first )
13
+ import Data.Bifunctor (second )
15
14
import Data.ByteString (ByteString )
16
15
import Data.ByteString qualified as BS
17
16
import Data.Containers.ListUtils (nubOrd )
@@ -22,7 +21,7 @@ import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)
22
21
import Data.Map.Strict (Map )
23
22
import Data.Map.Strict qualified as Map
24
23
import Data.Map.Merge.Strict qualified as Map
25
- import Data.Set (Set , isSubsetOf )
24
+ import Data.Set (Set )
26
25
import Data.Set qualified as Set
27
26
import Data.Text (Text )
28
27
import Data.Text qualified as T
@@ -676,34 +675,33 @@ verify solvers opts preState maybepost = do
676
675
677
676
exprInter <- interpret (Fetch. oracle solvers opts. rpcInfo) opts. iterConf preState runExpr
678
677
when conf. dumpExprs $ liftIO $ T. writeFile " unsimplified.expr" (formatExpr exprInter)
679
- liftIO $ do
680
- when conf. debug $ putStrLn " Simplifying expression"
678
+ do
679
+ when conf. debug $ liftIO $ putStrLn " Simplifying expression"
681
680
let expr = if opts. simp then (Expr. simplify exprInter) else exprInter
682
- when conf. dumpExprs $ T. writeFile " simplified.expr" (formatExpr expr)
683
- when conf. dumpExprs $ T. writeFile " simplified-conc.expr" (formatExpr $ Expr. simplify $ mapExpr Expr. concKeccakOnePass expr)
681
+ when conf. dumpExprs $ liftIO $ T. writeFile " simplified.expr" (formatExpr expr)
682
+ when conf. dumpExprs $ liftIO $ T. writeFile " simplified-conc.expr" (formatExpr $ Expr. simplify $ mapExpr Expr. concKeccakOnePass expr)
684
683
let flattened = flattenExpr expr
685
- when conf. debug $ do
684
+ when conf. debug $ liftIO $ do
686
685
printPartialIssues flattened (" the call " <> call)
687
686
putStrLn $ " Exploration finished, " <> show (Expr. numBranches expr) <> " branch(es) to check in call " <> call
688
687
689
688
case maybepost of
690
689
Nothing -> pure (expr, [Qed ])
691
- Just post -> liftIO $ do
690
+ Just post -> do
692
691
let
693
692
-- Filter out any leaves from `flattened` that can be statically shown to be safe
694
693
tocheck = flip map flattened $ \ leaf -> (toPropsFinal leaf preState. constraints post, leaf)
695
- withQueries = filter canBeSat tocheck <&> first (SMT. assertProps conf)
696
- when conf. debug $
697
- putStrLn $ " Checking for reachability of " <> show (length withQueries)
698
- <> " potential property violation(s) in call " <> call
694
+ withQueries = filter canBeSat tocheck
695
+ when conf. debug $ liftIO $ putStrLn $ " Checking for reachability of " <> show (length withQueries) <> " potential property violation(s) in call " <> call
699
696
700
697
-- Dispatch the remaining branches to the solver to check for violations
701
- results <- flip mapConcurrently withQueries $ \ (query, leaf) -> do
702
- res <- checkSat solvers query
703
- when conf. debug $ putStrLn $ " SMT result: " <> show res
704
- pure (res, leaf)
705
- let cexs = filter (\ (res, _) -> not . isQed $ res) results
706
- when conf. debug $ putStrLn $ " Found " <> show (length cexs) <> " potential counterexample(s) in call " <> call
698
+ --
699
+ results <- withRunInIO $ \ env -> flip mapConcurrently withQueries $ \ (query, leaf) -> do
700
+ res <- env $ checkSatWithProps solvers query
701
+ when conf. debug $ putStrLn $ " SMT result: " <> show (fst res)
702
+ pure (fst res, leaf)
703
+ let cexs = filter (not . isQed . fst ) results
704
+ when conf. debug $ liftIO $ putStrLn $ " Found " <> show (length cexs) <> " potential counterexample(s) in call " <> call
707
705
pure $ if Prelude. null cexs then (expr, [Qed ]) else (expr, fmap toVRes cexs)
708
706
where
709
707
getCallPrefix :: Expr Buf -> String
@@ -715,7 +713,7 @@ verify solvers opts preState maybepost = do
715
713
canBeSat (a, _) = case a of
716
714
[PBool False ] -> False
717
715
_ -> True
718
- toVRes :: (SMTResult , Expr End ) -> VerifyResult
716
+ toVRes :: (SMTResult , Expr End ) -> VerifyResult
719
717
toVRes (res, leaf) = case res of
720
718
Cex model -> Cex (leaf, expandCex preState model)
721
719
Unknown reason -> Unknown (reason, leaf)
@@ -732,8 +730,6 @@ expandCex prestate c = c { store = Map.union c.store concretePreStore }
732
730
ConcreteStore _ -> True
733
731
_ -> False
734
732
735
- type UnsatCache = TVar [Set Prop ]
736
-
737
733
data EqIssues = EqIssues
738
734
{ res :: [(EquivResult , String )]
739
735
, partials :: [Expr End ]
@@ -835,43 +831,28 @@ equivalenceCheck' solvers branchesA branchesB create = do
835
831
when conf. dumpEndStates $ forM_ (zip differingEndStates [(1 :: Integer ).. ]) (\ (x, i) ->
836
832
liftIO $ T. writeFile (" prop-checked-" <> show i <> " .prop" ) (T. pack $ show x))
837
833
838
- knownUnsat <- liftIO $ newTVarIO []
839
834
procs <- liftIO getNumProcessors
840
- newDifferences <- checkAll differingEndStates knownUnsat procs
835
+ newDifferences <- checkAll differingEndStates procs
841
836
let additionalIssues = EqIssues newDifferences mempty
842
837
pure $ knownIssues <> additionalIssues
843
838
844
839
where
845
- -- we order the sets by size because this gives us more cache hits when
840
+ -- we order the sets by size because this gives us more UNSAT cache hits when
846
841
-- running our queries later on (since we rely on a subset check)
847
842
sortBySize :: [(Set a , b )] -> [(Set a , b )]
848
843
sortBySize = sortBy (\ (a, _) (b, _) -> if Set. size a > Set. size b then Prelude. LT else Prelude. GT )
849
844
850
- -- returns True if a is a subset of any of the sets in b
851
- subsetAny :: Set Prop -> [Set Prop ] -> Bool
852
- subsetAny a b = foldr (\ bp acc -> acc || isSubsetOf a bp) False b
853
-
854
- -- checks for satisfiability of all the props in the provided set. skips
855
- -- the solver if we can determine unsatisfiability from the cache already
856
- -- the last element of the returned tuple indicates whether the cache was
857
- -- used or not
858
- check :: App m => UnsatCache -> Set Prop -> m EquivResult
859
- check knownUnsat props = do
860
- ku <- liftIO $ readTVarIO knownUnsat
861
- if subsetAny props ku then pure Qed
862
- else fst <$> checkSatWithProps solvers (Set. toList props)
863
-
864
845
-- Allows us to run the queries in parallel. Note that this (seems to) run it
865
846
-- from left-to-right, and with a max of K threads. This is in contrast to
866
847
-- mapConcurrently which would spawn as many threads as there are jobs, and
867
848
-- run them in a random order. We ordered them correctly, though so that'd be bad
868
- checkAll :: (App m , MonadUnliftIO m ) => [(Set Prop , String )] -> UnsatCache -> Int -> m [(EquivResult , String )]
869
- checkAll input cache numproc = withRunInIO $ \ env -> do
849
+ checkAll :: (App m , MonadUnliftIO m ) => [(Set Prop , String )] -> Int -> m [(EquivResult , String )]
850
+ checkAll input numproc = withRunInIO $ \ env -> do
870
851
wrap <- pool numproc
871
852
parMapIO (runOne env wrap) input
872
853
where
873
854
runOne env wrap (props, meaning) = do
874
- res <- wrap (env $ check cache props)
855
+ res <- wrap (env $ fst <$> checkSatWithProps solvers ( Set. toList props) )
875
856
pure (res, meaning)
876
857
877
858
-- Takes two branches and returns a set of props that will need to be
@@ -996,10 +977,9 @@ both' f (x, y) = (f x, f y)
996
977
produceModels :: App m => SolverGroup -> Expr End -> m [(Expr End , SMTResult )]
997
978
produceModels solvers expr = do
998
979
let flattened = flattenExpr expr
999
- withQueries conf = fmap (\ e -> ((SMT. assertProps conf) . extractProps $ e, e)) flattened
1000
- conf <- readConfig
1001
- results <- liftIO $ (flip mapConcurrently) (withQueries conf) $ \ (query, leaf) -> do
1002
- res <- checkSat solvers query
980
+ withQueries = fmap (\ e -> (extractProps e, e)) flattened
981
+ results <- withRunInIO $ \ runInIO -> (flip mapConcurrently) withQueries $ \ (query, leaf) -> do
982
+ (res, _) <- runInIO $ checkSatWithProps solvers query
1003
983
pure (res, leaf)
1004
984
pure $ fmap swap $ filter (\ (res, _) -> not . isQed $ res) results
1005
985
0 commit comments