-
Notifications
You must be signed in to change notification settings - Fork 50
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
copilot-theorem
: Crash when two externs share the same name
#536
Comments
copilot-theorem
: Bug when two externs share the same namecopilot-theorem
: Cannot run spec where two externs share the same name
copilot-theorem
: Cannot run spec where two externs share the same namecopilot-theorem
: Crash when two externs share the same name
Interestingly, if I add a trigger or observer to the program, such as in this modified example: module Main where
import Control.Monad (forM_)
import qualified Prelude as P
import Copilot.Theorem.What4
import Language.Copilot
spec :: Spec
spec = do
-- An example using external streams.
let a1 = extern "a" Nothing
prop "Example 7" (forAll (a1 || not a1))
-- An example using external streams.
let a2 :: Stream Int32
a2 = extern "a" Nothing
p1 = a2 > 10
p2 = a2 <= 10
prop "Example 8" (forAll (p1 || p2))
trigger "trig" (a1 || p1) []
return ()
main :: IO ()
main = do
spec' <- reify spec
-- Use Z3 to prove the properties.
results <- prove Z3 spec'
-- Print the results.
forM_ results $ \(propName, propRes) -> do
putStr $ propName <> ": "
case propRes of
Valid -> putStrLn "valid"
Invalid -> putStrLn "invalid"
Unknown -> putStrLn "unknown" Then Copilot will reject this specification with a proper error message instead of panicking:
If I comment out the copilot/copilot-language/src/Copilot/Language/Analyze.hs Lines 268 to 284 in 068c06d
Notice that this collects all of the externs mentioned in the triggers or observers, but not the externs mentioned in the properties. As such, if a specification consists solely of properties (as in your original example), then this function will incorrectly conclude that the specification has no externs. The following patch suffices to make the analysis consider externs in properties as well: diff --git a/copilot-language/src/Copilot/Language/Analyze.hs b/copilot-language/src/Copilot/Language/Analyze.hs
index 9d326395..9acd203d 100644
--- a/copilot-language/src/Copilot/Language/Analyze.hs
+++ b/copilot-language/src/Copilot/Language/Analyze.hs
@@ -268,10 +268,13 @@ analyzeExts ExternEnv { externVarEnv = vars
-- | Obtain all the externs in a specification.
specExts :: IORef Env -> Spec' a -> IO ExternEnv
specExts refStreams spec = do
- env <- foldM triggerExts
+ env0 <- foldM triggerExts
(ExternEnv [] [] [] [])
(triggers $ runSpec spec)
- foldM observerExts env (observers $ runSpec spec)
+ env1 <- foldM observerExts
+ env0
+ (observers $ runSpec spec)
+ foldM propertyExts env1 (properties $ runSpec spec)
where
observerExts :: ExternEnv -> Observer -> IO ExternEnv
@@ -283,6 +286,9 @@ specExts refStreams spec = do
foldM (\env'' (Arg arg_) -> collectExts refStreams arg_ env'')
env' args
+ propertyExts :: ExternEnv -> Property -> IO ExternEnv
+ propertyExts env (Property _ stream) = collectExts refStreams stream env
+
-- | Obtain all the externs in a stream.
collectExts :: C.Typed a => IORef Env -> Stream a -> ExternEnv -> IO ExternEnv
collectExts refStreams stream_ env_ = do We may also want to extend the analysis to include |
That does patch affect anything else (for example, the C code generator)? |
I don't believe this change should affect anything besides the validity checks that Copilot performs during a call to |
I think you are right. It's called during analysis, but I don't see it being called in anything that produces a result that propagates into the Copilot Core representation. |
Description Copilot crashes when two externs share the same name but have different types and are used with Type
Additional context None. Requester
Method to check presence of bug Running the following specification, which uses two externs with the same name but different types: module Main where
import Control.Monad (forM_)
import qualified Prelude as P
import Copilot.Theorem.What4
import Language.Copilot
spec :: Spec
spec = do
-- An example using external streams.
let a = extern "a" Nothing
prop "Example 7" (forAll (a || not a))
-- An example using external streams.
let a :: Stream Int32
a = extern "a" Nothing
p1 = a > 10
p2 = a <= 10
prop "Example 8" (forAll (p1 || p2))
return ()
main :: IO ()
main = do
spec' <- reify spec
-- Use Z3 to prove the properties.
results <- prove Z3 spec'
-- Print the results.
forM_ results $ \(propName, propRes) -> do
putStr $ propName <> ": "
case propRes of
Valid -> putStrLn "valid"
Invalid -> putStrLn "invalid"
Unknown -> putStrLn "unknown" results in a crash with the following error message:
when it should instead report the error in a graceful way. Expected result Copilot detects the problem and stops with a user-friendly error message. Desired result Copilot detects the problem and stops with a user-friendly error message. Proposed solution Modify the analyzer in Further notes None. |
Change Manager: Confirmed that the issue exists. |
I just ran an example where a locally defined extern was being used with multiple types, and I was met with an unexpected error message. Here's the module:
Here's what I was met with:
If I change the second extern definition to
a = extern "b" Nothing
, then the error message goes away.This kind of error also does not manifest if both externs have the same type.
The text was updated successfully, but these errors were encountered: