Skip to content

copilot-theorem: Support translating struct updates to what4 #524

Closed

Description

@RyanGlScott

Copilot 3.20 added support for struct updates via the new UpdateField operation. At the moment, there is no support on the copilot-theorem side for translating UpdateField operations into equivalent what4 expressions. For example, this means that the following Copilot specification will fail when executed:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Main (main) where

import Data.Foldable (for_)
import Data.Functor (void)
import Data.Word (Word32)

import qualified Copilot.Theorem.What4 as CT
import Language.Copilot

data S = S
  { unS :: Field "unS" Word32
  }

instance Struct S where
  typeName _ = "s"
  toValues s = [Value typeOf (unS s)]

instance Typed S where
  typeOf = Struct (S (Field 0))

spec :: Spec
spec = do
  let externS :: Stream S
      externS = extern "extern_s" Nothing

      example :: Stream Word32
      example = (externS ## unS =: 42) # unS

  void $ prop "example" (forAll $ example == example)

main :: IO ()
main = do
  spec' <- reify spec

  -- Use Z3 to prove the properties.
  results <- CT.prove CT.Z3 spec'

  -- Print the results.
  for_ results $ \(nm, res) -> do
    putStr $ nm <> ": "
    case res of
      CT.Valid -> putStrLn "valid"
      CT.Invalid -> putStrLn "invalid"
      CT.Unknown -> putStrLn "unknown"
$ runghc UpdateField.hs 
UpdateField.hs: src/Copilot/Theorem/What4/Translate.hs:(707,40)-(802,2): Non-exhaustive patterns in case

This limitation currently blocks copilot-verifier support for struct updates, as copilot-verifier makes us of copilot-theorem's what4 translation capabilities.

I have a prototype implementation in this branch which could be used as a starting point for a patch.

Activity

  1. ivanperez-keera commented on Aug 21, 2024

    @ivanperez-keera
    Member

    Description

    Copilot currently supports modifying values from streams of structs, but not reasoning about them using copilot-theorem.

    Type

    • Bug: exception produced when executing valid specification.

    Additional context

    Requester

    • Ryan Scott (Galois)

    Method to check presence of bug

    Running the following specification that tries to assert a trivial equality:

    {-# LANGUAGE DataKinds #-}
    {-# LANGUAGE NoImplicitPrelude #-}
    module Main (main) where
    
    import Data.Foldable (for_)
    import Data.Functor (void)
    import Data.Word (Word32)
    
    import qualified Copilot.Theorem.What4 as CT
    import Language.Copilot
    
    data S = S
      { unS :: Field "unS" Word32
      }
    
    instance Struct S where
      typeName _ = "s"
      toValues s = [Value typeOf (unS s)]
    
    instance Typed S where
      typeOf = Struct (S (Field 0))
    
    spec :: Spec
    spec = do
      let externS :: Stream S
          externS = extern "extern_s" Nothing
    
          example :: Stream Word32
          example = (externS ## unS =: 42) # unS
    
      void $ prop "example" (forAll $ example == example)
    
    main :: IO ()
    main = do
      spec' <- reify spec
    
      -- Use Z3 to prove the properties.
      results <- CT.prove CT.Z3 spec'
    
      -- Print the results.
      for_ results $ \(nm, res) -> do
        putStr $ nm <> ": "
        case res of
          CT.Valid -> putStrLn "valid"
          CT.Invalid -> putStrLn "invalid"
          CT.Unknown -> putStrLn "unknown"

    produces an error message:

    $ runghc UpdateField.hs 
    UpdateField.hs: src/Copilot/Theorem/What4/Translate.hs:(707,40)-(802,2): Non-exhaustive patterns in case
    

    when it should instead execute correctly and print valid, invalid, or unknown.

    Expected result

    Copilot allows using struct updates in copilot-theorem and to reason about them.

    Desired result

    Copilot allows using struct updates in copilot-theorem and to reason about them.

    Proposed solution

    Translate struct updates to what4.

    Include an example that demonstrates the support for struct updates in copilot-theorem.

    Include a test that checks that struct updates are supported in copilot-theorem.

    Further notes

    None.

  2. added
    CR:Type:BugAdmin only: Change request pertaining to error detected
    CR:Status:InitiatedAdmin only: Change request that has been initiated
    on Aug 21, 2024
  3. ivanperez-keera commented on Aug 21, 2024

    @ivanperez-keera
    Member

    Change Manager: Confirmed that the issue exists.

  4. added
    CR:Status:ConfirmedAdmin only: Change request that has been acknowledged by the change manager
    and removed
    CR:Status:InitiatedAdmin only: Change request that has been initiated
    on Aug 21, 2024
  5. ivanperez-keera commented on Aug 21, 2024

    @ivanperez-keera
    Member

    Technical Lead: Confirmed that the issue should be addressed.

  6. added
    CR:Status:AcceptedAdmin only: Change request accepted by technical lead
    and removed
    CR:Status:ConfirmedAdmin only: Change request that has been acknowledged by the change manager
    on Aug 21, 2024
  7. ivanperez-keera commented on Aug 21, 2024

    @ivanperez-keera
    Member

    Technical Lead: Issue scheduled for fixing in Copilot 4.

    Fix assigned to: @RyanGlScott .

  8. added
    CR:Status:ScheduledAdmin only: Change requested scheduled
    and removed
    CR:Status:AcceptedAdmin only: Change request accepted by technical lead
    on Aug 21, 2024
  9. added this to the Copilot 4 milestone on Aug 21, 2024
  10. 4 remaining items

  11. RyanGlScott commented on Aug 21, 2024

    @RyanGlScott
    CollaboratorAuthor

    Implementor: Solution implemented, review requested.

  12. added
    CR:Status:VerificationAdmin only: Change request that is currently being verified
    and removed
    CR:Status:ImplementationAdmin only: Change request that is currently being implemented
    on Aug 30, 2024
  13. ivanperez-keera commented on Aug 30, 2024

    @ivanperez-keera
    Member

    Change Manager: Verified that:

    • Solution is implemented:
      • The code proposed compiles and passes all tests. Details:
        Build log: https://app.travis-ci.com/github/Copilot-Language/copilot/builds/272114388

      • The solution proposed produces the expected result. Details:
        The following Dockerfile installs copilot and runs a spec that uses copilot-theorem to prove that a stream with an update is equal to itself, in which case it prints the message "valid", followed by "Success":

        --- Dockerfile
        FROM ubuntu:focal
        
        ENV DEBIAN_FRONTEND=noninteractive
        RUN apt-get update
        
        RUN apt-get install --yes libz-dev
        RUN apt-get install --yes git
        
        RUN apt-get install --yes wget
        RUN mkdir -p $HOME/.ghcup/bin
        RUN wget https://downloads.haskell.org/~ghcup/0.1.19.2/x86_64-linux-ghcup-0.1.19.2 -O $HOME/.ghcup/bin/ghcup
        
        RUN chmod a+x $HOME/.ghcup/bin/ghcup
        ENV PATH=$PATH:/root/.ghcup/bin/
        ENV PATH=$PATH:/root/.cabal/bin/
        RUN apt-get install --yes curl
        RUN apt-get install --yes gcc g++ make libgmp3-dev
        RUN apt-get install --yes pkg-config
        RUN apt-get install --yes z3
        
        SHELL ["/bin/bash", "-c"]
        
        RUN ghcup install ghc 9.4
        RUN ghcup install cabal 3.2
        RUN ghcup set ghc 9.4.8
        RUN cabal update
        
        ADD UpdateField.hs /tmp/UpdateField.hs
        
        CMD git clone $REPO \
            && cd $NAME \
            && git checkout $COMMIT \
            && cabal v1-sandbox init \
            && cabal v1-install alex happy \
            && cabal v1-install copilot**/ \
            && cabal v1-exec -- runhaskell /tmp/UpdateField.hs \
            && echo Success
        
        --- UpdateField.hs
        {-# LANGUAGE DataKinds #-}
        {-# LANGUAGE NoImplicitPrelude #-}
        module Main (main) where
        
        import Data.Foldable (for_)
        import Data.Functor (void)
        import Data.Word (Word32)
        
        import qualified Copilot.Theorem.What4 as CT
        import Language.Copilot
        
        data S = S
          { unS :: Field "unS" Word32
          }
        
        instance Struct S where
          typeName _ = "s"
          toValues s = [Value typeOf (unS s)]
        
        instance Typed S where
          typeOf = Struct (S (Field 0))
        
        spec :: Spec
        spec = do
          let externS :: Stream S
              externS = extern "extern_s" Nothing
        
              example :: Stream Word32
              example = (externS ## unS =: 42) # unS
        
          void $ prop "example" (forAll $ example == example)
        
        main :: IO ()
        main = do
          spec' <- reify spec
        
          -- Use Z3 to prove the properties.
          results <- CT.prove CT.Z3 spec'
        
          -- Print the results.
          for_ results $ \(nm, res) -> do
            putStr $ nm <> ": "
            case res of
              CT.Valid -> putStrLn "valid"
              CT.Invalid -> putStrLn "invalid"
              CT.Unknown -> putStrLn "unknown"

        Command (substitute variables based on new path after merge):

        $ docker run -e "REPO=https://github.com/GaloisInc/copilot-1" -e "NAME=copilot-1" -e "COMMIT=bf0f4548f07484d8a262eba1784036ff17e5e3aa" -it copilot-verify-524
        
    • Implementation is documented. Details:
      New functions are documented.
    • Change history is clear.
    • Commit messages are clear.
    • Changelogs are updated.
    • Examples are updated. Details:
      Updated example demonstrates reasoning with struct updates.
    • Required version bumps are evaluated. Details:
      Bump not needed (bug fix).
  14. ivanperez-keera commented on Aug 30, 2024

    @ivanperez-keera
    Member

    Change Manager: Implementation ready to be merged.

  15. added a commit that references this issue on Aug 30, 2024
    0f5055e
  16. added
    CR:Status:ClosedAdmin only: Change request that has been completed
    and removed
    CR:Status:VerificationAdmin only: Change request that is currently being verified
    on Sep 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

CR:Status:ClosedAdmin only: Change request that has been completedCR:Type:BugAdmin only: Change request pertaining to error detected

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions