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

Refactoring to support control sync rework #387

Merged
merged 27 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b5cf203
add missing JSON serialization for ChoiceTree
danmatichuk May 14, 2024
7e8dc31
add utility functions for PairGraphM
danmatichuk May 14, 2024
d7243dd
retain divergence information for sync nodes
danmatichuk May 14, 2024
2412b87
add 'filter' function to RevMap
danmatichuk Mar 20, 2024
ac18ddd
wrap PairGraph worklist elements in WorkItem datatype
danmatichuk Mar 20, 2024
483b7df
add SingleNodeEntry datatype to represent explicitly single-sided nodes
danmatichuk Apr 4, 2024
4b8532e
add map to SetF
danmatichuk Apr 5, 2024
1c072ad
add WithBin datatype to PatchPair for annotating data with original o…
danmatichuk Apr 5, 2024
7ea5e60
WIP
danmatichuk May 14, 2024
c95d70f
cherry-pick changes from dm/diverge-fix2
danmatichuk May 15, 2024
fe6c108
distinguish entry vs. exit sync points so they can be
danmatichuk May 17, 2024
54f81a5
Merge branch 'master' into dm/control_sync_wip2
danmatichuk May 17, 2024
c883edf
add simple logging to PairGraph operations
danmatichuk May 31, 2024
d4b30e1
add ProcessSplit as top-level work queue action
danmatichuk May 31, 2024
9269e67
clean up logging
danmatichuk May 31, 2024
61bd5ff
add execPG to Monad.PairGraph
danmatichuk Jun 5, 2024
b0b35f9
support stubs returning to sync points
danmatichuk Jun 5, 2024
367dfdf
update challenge 10 script
danmatichuk Jun 5, 2024
8aaf24b
update tests
danmatichuk Jun 7, 2024
48186bc
update desync-zerostep tests
danmatichuk Jun 7, 2024
3bd4ac5
ensure that merge work items aren't lost from the queue
danmatichuk Jun 7, 2024
6ff9dd7
only output "Finish Choosing" once when picking sync point
danmatichuk Jun 7, 2024
b7132d7
handle orphaned returns by implicitly adding equivalence condition
danmatichuk Jun 7, 2024
93bfc71
mark desync-orphan as expected conditional verification
danmatichuk Jun 8, 2024
95229ae
add a 20 minute per-test timeout
danmatichuk Jun 10, 2024
e13b7e4
don't use .expect file for self-equivalence test
danmatichuk Jun 11, 2024
fbf0624
proper handling for special case where stub returns exactly to a sync…
danmatichuk Jun 11, 2024
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
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ jobs:
- name: Test
if: runner.os == 'Linux'
run: |
cabal test pkg:pate
cabal test pkg:pate --test-options="-t 1200s"

- name: Docs
run: cabal haddock pkg:pate
17 changes: 17 additions & 0 deletions src/Data/Parameterized/PairF.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ module Data.Parameterized.PairF
) where

import Data.Kind (Type)
import Data.Parameterized.Classes

data PairF tp1 tp2 k = PairF (tp1 k) (tp2 k)

Expand All @@ -26,6 +27,22 @@ type instance TupleF '(a,b,c,d) = PairF a (PairF b (PairF c d))
pattern TupleF2 :: a k -> b k -> TupleF '(a,b) k
pattern TupleF2 a b = PairF a b

instance (TestEquality a, TestEquality b) => TestEquality (PairF a b) where
testEquality (PairF a1 b1) (PairF a2 b2) =
case (testEquality a1 a2, testEquality b1 b2) of
(Just Refl, Just Refl) -> Just Refl
_ -> Nothing

instance (OrdF a, OrdF b) => OrdF (PairF a b) where
compareF (PairF a1 b1) (PairF a2 b2) =
lexCompareF a1 a2 $ compareF b1 b2

instance (Eq (a tp), Eq (b tp)) => Eq ((PairF a b) tp) where
(PairF a1 b1) == (PairF a2 b2) = a1 == a2 && b1 == b2

instance (Ord (a tp), Ord (b tp)) => Ord ((PairF a b) tp) where
compare (PairF a1 b1) (PairF a2 b2) = compare a1 a2 <> compare b1 b2

{-# COMPLETE TupleF2 #-}

pattern TupleF3 :: a k -> b k -> c k -> TupleF '(a,b,c) k
Expand Down
30 changes: 27 additions & 3 deletions src/Data/Parameterized/SetF.hs
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,14 @@ module Data.Parameterized.SetF
, union
, unions
, null
, toSet
, fromSet
, map
, ppSetF
) where

import Prelude hiding (filter, null)
import Prelude hiding (filter, null, map)
import qualified Data.List as List
import Data.Parameterized.Classes
import qualified Data.Foldable as Foldable

Expand All @@ -55,6 +59,7 @@ import Prettyprinter ( (<+>) )

import Data.Set (Set)
import qualified Data.Set as S
import Unsafe.Coerce (unsafeCoerce)

newtype AsOrd f tp where
AsOrd :: { unAsOrd :: f tp } -> AsOrd f tp
Expand Down Expand Up @@ -91,13 +96,13 @@ insert e (SetF es) = SetF (S.insert (AsOrd e) es)
toList ::
SetF f tp ->
[f tp]
toList (SetF es) = map unAsOrd $ S.toList es
toList (SetF es) = List.map unAsOrd $ S.toList es

fromList ::
OrdF f =>
[f tp] ->
SetF f tp
fromList es = SetF $ S.fromList (map AsOrd es)
fromList es = SetF $ S.fromList (List.map AsOrd es)

member ::
OrdF f =>
Expand Down Expand Up @@ -130,6 +135,25 @@ null ::
SetF f tp -> Bool
null (SetF es) = S.null es

-- | Convert a 'SetF' to a 'Set', under the assumption
-- that the 'OrdF' and 'Ord' instances are consistent.
-- This uses coercion rather than re-building the set,
-- which is sound given the above assumption.
toSet ::
(OrdF f, Ord (f tp)) => SetF f tp -> Set (f tp)
toSet (SetF s) = unsafeCoerce s

-- | Convert a 'Set' to a 'SetF', under the assumption
-- that the 'OrdF' and 'Ord' instances are consistent.
-- This uses coercion rather than re-building the set,
-- which is sound given the above assumption.
fromSet :: (OrdF f, Ord (f tp)) => Set (f tp) -> SetF f tp
fromSet s = SetF (unsafeCoerce s)

map ::
(OrdF g) => (f tp -> g tp) -> SetF f tp -> SetF g tp
map f (SetF s) = SetF (S.map (\(AsOrd v) -> AsOrd (f v)) s)

ppSetF ::
(f tp -> PP.Doc a) ->
SetF f tp ->
Expand Down
12 changes: 11 additions & 1 deletion src/Data/RevMap.hs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-|
Module : Data.RevMap
Copyright : (c) Galois, Inc 2023
Expand All @@ -19,9 +21,10 @@ module Data.RevMap
, alter
, insertWith
, findFirst
, filter
) where

import Prelude hiding (lookup)
import Prelude hiding (lookup, filter)

import qualified Data.Set as Set
import Data.Set (Set)
Expand Down Expand Up @@ -76,6 +79,13 @@ delete a m@(RevMap a_to_b b_to_a) = case Map.lookup a a_to_b of
Just b -> reverseAdjust b (Set.delete a) (RevMap (Map.delete a a_to_b) b_to_a)
Nothing -> m

filter :: forall a b. (a -> b -> Bool) -> RevMap a b -> RevMap a b
filter f (RevMap a_to_b b_to_a) =
RevMap (Map.filterWithKey f a_to_b) (Map.mapMaybeWithKey g b_to_a)
where
g :: b -> Set a -> Maybe (Set a)
g b as = let as' = Set.filter (\a -> f a b) as
in if Set.null as' then Nothing else Just as'

alter :: (Ord a, Ord b) => (Maybe b -> Maybe b) -> a -> RevMap a b -> RevMap a b
alter f a m@(RevMap a_to_b b_to_as) = case Map.lookup a a_to_b of
Expand Down
22 changes: 18 additions & 4 deletions src/Pate/Binary.hs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ module Pate.Binary
, Patched
, WhichBinaryRepr(..)
, OtherBinary
, binCases
, flipRepr
, short)
, short
, otherInvolutive
)
where

import Data.Parameterized.WithRepr
Expand All @@ -50,16 +53,27 @@ data WhichBinaryRepr (bin :: WhichBinary) where
OriginalRepr :: WhichBinaryRepr 'Original
PatchedRepr :: WhichBinaryRepr 'Patched

type family OtherBinary (bin :: WhichBinary) :: WhichBinary
type family OtherBinary (bin :: WhichBinary) :: WhichBinary where
OtherBinary Original = Patched
OtherBinary Patched = Original

type instance OtherBinary Original = Patched
type instance OtherBinary Patched = Original
otherInvolutive :: WhichBinaryRepr bin -> (OtherBinary (OtherBinary bin) :~: bin)
otherInvolutive bin = case binCases bin (flipRepr bin) of
Left Refl -> Refl
Right Refl -> Refl

flipRepr :: WhichBinaryRepr bin -> WhichBinaryRepr (OtherBinary bin)
flipRepr = \case
OriginalRepr -> PatchedRepr
PatchedRepr -> OriginalRepr

binCases :: WhichBinaryRepr bin1 -> WhichBinaryRepr bin2 -> Either (bin1 :~: bin2) ('(bin1, bin2) :~: '(OtherBinary bin2, OtherBinary bin1))
binCases bin1 bin2 = case (bin1, bin2) of
(OriginalRepr, OriginalRepr) -> Left Refl
(OriginalRepr, PatchedRepr) -> Right Refl
(PatchedRepr, PatchedRepr) -> Left Refl
(PatchedRepr, OriginalRepr) -> Right Refl

short :: WhichBinaryRepr bin -> String
short OriginalRepr = "O"
short PatchedRepr = "P"
Expand Down
5 changes: 3 additions & 2 deletions src/Pate/Equivalence/Error.hs
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,11 @@ data InnerEquivalenceError arch
| UninterpretedInstruction
| FailedToResolveAddress (MM.MemWord (MM.ArchAddrWidth arch))
| forall tp. FailedToGroundExpr (SomeExpr tp)
| OrphanedSingletonAnalysis (PB.FunPair arch)
| OrphanedSinglesidedAnalysis (PB.FunPair arch)
| RequiresInvalidPointerOps
| PairGraphError PairGraphErr
| forall e. X.Exception e => UnhandledException e
| IncompatibleSingletonNodes (PB.ConcreteBlock arch PBi.Original) (PB.ConcreteBlock arch PBi.Patched)
| SolverError X.SomeException

errShortName :: MS.SymArchConstraints arch => InnerEquivalenceError arch -> String
Expand Down Expand Up @@ -230,7 +231,7 @@ isRecoverable' e = case e of
BlockHasNoExit{} -> True
OrphanedFunctionReturns{} -> True
CallReturnsToFunctionEntry{} -> True
OrphanedSingletonAnalysis{} -> True
OrphanedSinglesidedAnalysis{} -> True
UnsatisfiableEquivalenceCondition{} -> True
_ -> False

Expand Down
2 changes: 2 additions & 0 deletions src/Pate/Monad/Environment.hs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ data NodePriorityK =
| PriorityDeferredPropagation
| PriorityDomainRefresh
| PriorityHandleReturn
| PriorityHandleMerge
| PriorityMiscCleanup
| PriorityDeferred
deriving (Eq, Ord)
Expand All @@ -153,6 +154,7 @@ printPriorityKind (NodePriority pk _ _ ) = case pk of
PriorityDeferredPropagation -> "Propagating Deferred Conditions"
PriorityDomainRefresh -> "Re-checking Equivalence Domains"
PriorityHandleReturn -> "Handling Function Return"
PriorityHandleMerge -> "Handling Control Flow Merge"
PriorityMiscCleanup -> "Proof Cleanup"
PriorityDeferred -> "Handling Deferred Decisions"

Expand Down
83 changes: 71 additions & 12 deletions src/Pate/Monad/PairGraph.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,17 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE PolyKinds #-}

-- EquivM operations on a PairGraph
module Pate.Monad.PairGraph
( withPG
, evalPG
, withPG_
, liftPG
, catchPG
Expand All @@ -23,6 +30,9 @@ module Pate.Monad.PairGraph
, considerDesyncEvent
, addLazyAction
, queuePendingNodes
, runPG
, execPG
, liftPartEqM_
) where

import Control.Monad.State.Strict
Expand Down Expand Up @@ -52,44 +62,93 @@ import qualified Pate.Equivalence.Condition as PEC
import qualified Data.Macaw.CFG as MM
import qualified Data.Map as Map
import qualified Pate.Equivalence.Error as PEE
import GHC.Stack (HasCallStack)
import qualified Prettyprinter as PP


instance IsTraceNode (k :: l) "pg_trace" where
type TraceNodeType k "pg_trace" = [String]
prettyNode () msgs = PP.vsep (map PP.viaShow msgs)
nodeTags = mkTags @k @"pg_trace" [Custom "debug"]

emitPGTrace :: [String] -> EquivM sym arch ()
emitPGTrace [] = return ()
emitPGTrace l = emitTrace @"pg_trace" l

withPG ::
HasCallStack =>
PairGraph sym arch ->
StateT (PairGraph sym arch) (EquivM_ sym arch) a ->
EquivM sym arch (a, PairGraph sym arch)
withPG pg f = runStateT f pg

evalPG ::
HasCallStack =>
PairGraph sym arch ->
PairGraphM sym arch a ->
EquivM sym arch a
evalPG pg f = fst <$> (withPG pg $ liftPG f)

execPG :: HasCallStack => PairGraph sym arch -> PairGraphM sym arch a -> EquivM_ sym arch (PairGraph sym arch)
execPG pg f = snd <$> runPG pg f

withPG_ ::
HasCallStack =>
PairGraph sym arch ->
StateT (PairGraph sym arch) (EquivM_ sym arch) a ->
EquivM sym arch (PairGraph sym arch)
withPG_ pg f = execStateT f pg

liftPG :: PairGraphM sym arch a -> StateT (PairGraph sym arch) (EquivM_ sym arch) a
liftPG :: HasCallStack => PairGraphM sym arch a -> StateT (PairGraph sym arch) (EquivM_ sym arch) a
liftPG f = do
pg <- get
case runPairGraphM pg f of
Left err -> lift $ throwHere $ PEE.PairGraphError err
Right (a,pg') -> do
put pg'
return a
env <- lift $ ask
withValidEnv env $
case runPairGraphMLog pg f of
(l, Left err) -> do
lift $ emitPGTrace l
lift $ throwHere $ PEE.PairGraphError err
(l, Right (a,pg')) -> do
lift $ emitPGTrace l
put pg'
return a

catchPG :: PairGraphM sym arch a -> StateT (PairGraph sym arch) (EquivM_ sym arch) (Maybe a)
runPG :: HasCallStack => PairGraph sym arch -> PairGraphM sym arch a -> EquivM_ sym arch (a, PairGraph sym arch)
runPG pg f = withValid $ case runPairGraphMLog pg f of
(l, Left err) -> do
emitPGTrace l
throwHere $ PEE.PairGraphError err
(l, Right a) -> do
emitPGTrace l
return a

catchPG :: HasCallStack => PairGraphM sym arch a -> StateT (PairGraph sym arch) (EquivM_ sym arch) (Maybe a)
catchPG f = do
pg <- get
case runPairGraphM pg f of
Left{} -> return Nothing
Right (a,pg') -> do
put pg'
return $ Just a
env <- lift $ ask
withValidEnv env $
case runPairGraphMLog pg f of
(l, Left{}) -> (lift $ emitPGTrace l) >> return Nothing
(l, Right (a,pg')) -> do
lift $ emitPGTrace l
put pg'
return $ Just a

liftEqM_ ::
HasCallStack =>
(PairGraph sym arch -> EquivM_ sym arch (PairGraph sym arch)) ->
StateT (PairGraph sym arch) (EquivM_ sym arch) ()
liftEqM_ f = liftEqM $ \pg -> ((),) <$> (f pg)

liftPartEqM_ ::
(PairGraph sym arch -> EquivM_ sym arch (Maybe (PairGraph sym arch))) ->
StateT (PairGraph sym arch) (EquivM_ sym arch) Bool
liftPartEqM_ f = liftEqM $ \pg -> f pg >>= \case
Just pg' -> return (True, pg')
Nothing -> return (False, pg)

liftEqM ::
HasCallStack =>
(PairGraph sym arch -> EquivM_ sym arch (a, PairGraph sym arch)) ->
StateT (PairGraph sym arch) (EquivM_ sym arch) a
liftEqM f = do
Expand Down
Loading
Loading