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

MacOS: fails to recognize installed Z3 solver #1488

Closed
mouse07410 opened this issue Jan 4, 2023 · 22 comments
Closed

MacOS: fails to recognize installed Z3 solver #1488

mouse07410 opened this issue Jan 4, 2023 · 22 comments

Comments

@mouse07410
Copy link

mouse07410 commented Jan 4, 2023

MacOS Monterey 12.6.2, Xcode-14.2, GHC-9.2.5, Cabal-3.8.1.0, current Cryptol built form sources.

Apparent error: Missing response from solver.

$ type z3
z3 is /opt/local/bin/z3
$ z3 --version
Z3 version 4.8.17 - 64 bit
$ ./cry test
Running tests
tests:
  constraint-guards:
    constant.icry: [Failed]
0a1
> ld: warning: -undefined dynamic_lookup may not work with chained fixups
2,18c3
< Loading module Cryptol
< Loading module Main
< [warning] at constant.cry:1:11--1:16
<     Unused name: n
< [warning] at constant.cry:14:10--14:15
<     Unused name: n
< [warning] at constant.cry:28:1--28:10:
<   Could not prove that the constraint guards used in defining Main::idTypeNum were exhaustive.
< property isZero_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
< property isFin_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
< property idTypeNum_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
---
> cryptol: user error (Missing response from solver)

# If output is OK:
cp /Users/ur20980/src/cryptol/output/tests/constraint-guards/constant.icry.stdout \
     /Users/ur20980/src/cryptol/tests/constraint-guards/constant.icry.stdout


    inits.icry: [Failed]
2,8c2
< Loading module Cryptol
< Loading module Main
< Showing a specific instance of polymorphic result:
<   * Using 'Integer' for type of sequence member
< Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
---
> cryptol: user error (Missing response from solver)

# If output is OK:
cp /Users/ur20980/src/cryptol/output/tests/constraint-guards/inits.icry.stdout \
     /Users/ur20980/src/cryptol/tests/constraint-guards/inits.icry.stdout


    insert.icry: [Failed]
2,6c2
< Loading module Cryptol
< Loading module Main
< Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
---
> cryptol: user error (Missing response from solver)
.  .  .
@RyanGlScott
Copy link
Contributor

Some additional information that would be helpful for debugging this:

  1. What is the output of uname -a? (This will let us know what your architecture is.)
  2. What is the output of z3 --version?
  3. How did you install Z3?
  4. Can you successfully run z3 on a small example? For instance, if you download this file and run z3 mult_dist.smt2, does it return unsat?

@mouse07410
Copy link
Author

mouse07410 commented Jan 4, 2023

z3 was installed via Macports - which shouldn't matter. This is an Intel platform. A counter-question: how does Cryptol invoke and communicate with Z3?

$ uname -a
Darwin 549725-mitll 21.6.0 Darwin Kernel Version 21.6.0: Sun Nov  6 23:31:16 PST 2022; root:xnu-8020.240.14~1/RELEASE_X86_64 x86_64
$ z3 --version
Z3 version 4.8.17 - 64 bit
$ z3 ../mult_dist.smt2 
unsat
$ 

@RyanGlScott
Copy link
Contributor

Interesting. I can't reproduce this with Z3 4.8.17 on Linux, so perhaps there really is something macOS-specific about this issue. I won't have access to a Mac machine to debug this myself for a couple of weeks, however.

In the meantime, one thing that you could to do to help debug this further is to run a test case with higher debug settings. Namely, can you apply this patch:

diff --git a/tests/constraint-guards/constant.icry b/tests/constraint-guards/constant.icry
index b7557b19..8323aa1d 100644
--- a/tests/constraint-guards/constant.icry
+++ b/tests/constraint-guards/constant.icry
@@ -1,3 +1,4 @@
+:set tcDebug=2
 :l constant.cry
 
 :check
\ No newline at end of file

And then run the constant.icry test case using the following?

$ ./cry test tests/constraint-guards/constant.icry

Doing so should print out the sequence of commands send to and received from Z3, which might help reveal what the issue is.

@mouse07410
Copy link
Author

$ ./cry test tests/constraint-guards/constant.icry
Running tests
tests:
  constraint-guards:
    constant.icry: [Failed]
2,18c2
< Loading module Cryptol
< Loading module Main
< [warning] at constant.cry:1:11--1:16
<     Unused name: n
< [warning] at constant.cry:14:10--14:15
<     Unused name: n
< [warning] at constant.cry:28:1--28:10:
<   Could not prove that the constraint guards used in defining Main::idTypeNum were exhaustive.
< property isZero_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
< property isFin_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
< property idTypeNum_correct Using exhaustive testing.
< Testing... Passed 1 tests.
< Q.E.D.
---
> cryptol: user error (Missing response from solver)

# If output is OK:
cp /Users/ur20980/src/cryptol/output/tests/constraint-guards/constant.icry.stdout \
     /Users/ur20980/src/cryptol/tests/constraint-guards/constant.icry.stdout



         Test Cases  Total      
 Passed  0           0          
 Failed  1           1          
 Total   1           1          
$ 
$ cat tests/constraint-guards/constant.icry
:set tcDebug=2
:l constant.cry

:check
\ No newline at end of file

Apparently, we need something different to print out the communications with Z3.

@RyanGlScott
Copy link
Contributor

Huh, that is very strange. Does the same thing happen on the Cryptol REPL? That is, if you run:

$ cabal run exe:cryptol

And then type in the following at the REPL:

Cryptol> :set tcDebug=2
Cryptol> 0b1

For me, that produces lots of output starting with:

[send->] (set-option :print-success true )
[<-recv] success
[send->] (set-option :produce-models true )
[<-recv] success
[send->] (set-option :global-decls false )
[<-recv] success
[send->] (declare-datatypes () ((InfNat (mk-infnat (value Int ) (isFin Bool ) (isErr Bool ) ) ) ) )
[<-recv] success
...

@mouse07410
Copy link
Author

mouse07410 commented Jan 11, 2023

$ cabal run exe:cryptol
Up to date
┏━╸┏━┓╻ ╻┏━┓╺┳╸┏━┓╻  
┃  ┣┳┛┗┳┛┣━┛ ┃ ┃ ┃┃  
┗━╸╹┗╸ ╹ ╹   ╹ ┗━┛┗━╸
version 2.13.0.99 (953673b, modified)
https://cryptol.net  :? for help

Loading module Cryptol
cryptol: user error (Missing response from solver)

Can you get me a patch that makes printing out SMT communications a default? So that I could recompile Cryptol, try to run it, and get the output?

BTW:

$ port installed z3
The following ports are currently installed:
  z3 @4.8.17_0+lto+polly+polly_late+polly_vector+threads (active)
$ type z3
z3 is /opt/local/bin/z3
$

@RyanGlScott
Copy link
Contributor

Ah, that's helpful to know: the failure is happening during the initial SMT solver setup, rather than when running any Cryptol code.

Can you get me a patch that makes printing out SMT communications a default? So that I could recompile Cryptol, try to run it, and get the output?

Good idea. Try this patch:

diff --git a/src/Cryptol/TypeCheck/Solver/SMT.hs b/src/Cryptol/TypeCheck/Solver/SMT.hs
index 8da61e34..e80b9433 100644
--- a/src/Cryptol/TypeCheck/Solver/SMT.hs
+++ b/src/Cryptol/TypeCheck/Solver/SMT.hs
@@ -77,10 +77,8 @@ setupSolver s cfg = do
 -- | Start a fresh solver instance
 startSolver :: IO () -> SolverConfig -> IO Solver
 startSolver onExit sCfg =
-   do logger <- if (solverVerbose sCfg) > 0 then SMT.newLogger 0
-
-                                     else return quietLogger
-      let smtDbg = if (solverVerbose sCfg) > 1 then Just logger else Nothing
+   do logger <- SMT.newLogger 0
+      let smtDbg = Just logger
       solver <- SMT.newSolverNotify
                     (solverPath sCfg) (solverArgs sCfg) smtDbg (Just (const onExit))
       let sol = Solver solver logger

After applying this patch, I get solver output right after starting Cryptol:

$ cabal run exe:cryptol
Up to date
┏━╸┏━┓╻ ╻┏━┓╺┳╸┏━┓╻  
┃  ┣┳┛┗┳┛┣━┛ ┃ ┃ ┃┃  
┗━╸╹┗╸ ╹ ╹   ╹ ┗━┛┗━╸
version 2.13.0.99 (bf17c70, modified)
https://cryptol.net  :? for help                                                                                                 

[send->] (set-option :print-success true )
[<-recv] success
[send->] (set-option :produce-models true )
[<-recv] success
[send->] (set-option :global-decls false )
[<-recv] success
[send->] (declare-datatypes () ((InfNat (mk-infnat (value Int ) (isFin Bool ) (isErr Bool ) ) ) ) )
[<-recv] success
...

@mouse07410
Copy link
Author

mouse07410 commented Jan 12, 2023

$ cabal run exe:cryptol
Build profile: -w ghc-9.2.5 -O1
In order, the following will be built (use -v for more details):
 - cryptol-2.13.0.99 (lib) (file src/GitRev.hs changed)
 - cryptol-2.13.0.99 (exe:cryptol) (dependency rebuilt)
Preprocessing library for cryptol-2.13.0.99..
Building library for cryptol-2.13.0.99..
[119 of 121] Compiling GitRev           ( src/GitRev.hs, /Users/ur20980/src/cryptol/dist-newstyle/build/x86_64-osx/ghc-9.2.5/cryptol-2.13.0.99/opt/build/GitRev.o, /Users/ur20980/src/cryptol/dist-newstyle/build/x86_64-osx/ghc-9.2.5/cryptol-2.13.0.99/opt/build/GitRev.dyn_o )
ld: warning: -undefined dynamic_lookup may not work with chained fixups
Preprocessing executable 'cryptol' for cryptol-2.13.0.99..
Building executable 'cryptol' for cryptol-2.13.0.99..
Linking /Users/ur20980/src/cryptol/dist-newstyle/build/x86_64-osx/ghc-9.2.5/cryptol-2.13.0.99/x/cryptol/opt/build/cryptol/cryptol ...
┏━╸┏━┓╻ ╻┏━┓╺┳╸┏━┓╻  
┃  ┣┳┛┗┳┛┣━┛ ┃ ┃ ┃┃  
┗━╸╹┗╸ ╹ ╹   ╹ ┗━┛┗━╸
version 2.13.0.99 (953673b, modified)
https://cryptol.net  :? for help

[send->] (set-option :print-success true )
[<-recv] success
[send->] (set-option :produce-models true )
[<-recv] success
[send->] (set-option :global-decls false )
[<-recv] success
[send->] (declare-datatypes () ((InfNat (mk-infnat (value Int ) (isFin Bool ) (isErr Bool ) ) ) ) )
[<-recv] success
[send->] (declare-datatypes () ((MaybeBool (mk-mb (prop Bool ) (isErrorProp Bool ) ) ) ) )
[<-recv] success
[send->] (define-fun cryBool ((x Bool ) ) MaybeBool (mk-mb x false ) )
[<-recv] success
[send->] (define-fun cryErrProp () MaybeBool (mk-mb false true ) )
[<-recv] success
[send->] (define-fun cryInf () InfNat (mk-infnat 0 false false ) )
[<-recv] success
[send->] (define-fun cryNat ((x Int ) ) InfNat (mk-infnat x true false ) )
[<-recv] success
[send->] (define-fun cryErr () InfNat (mk-infnat 0 false true ) )
[<-recv] success
[send->] (define-fun cryEq ((x InfNat ) (y InfNat ) ) MaybeBool (ite (or (isErr x ) (isErr y ) ) cryErrProp (cryBool (ite (isFin x ) (ite (isFin y ) (= (value x ) (value y ) ) false ) (not (isFin y ) ) ) ) ) )
[<-recv] success
[send->] (define-fun cryNeq ((x InfNat ) (y InfNat ) ) MaybeBool (ite (or (isErr x ) (isErr y ) ) cryErrProp (cryBool (ite (isFin x ) (ite (isFin y ) (not (= (value x ) (value y ) ) ) true ) (isFin y ) ) ) ) )
[<-recv] success
[send->] (define-fun cryFin ((x InfNat ) ) MaybeBool (ite (isErr x ) cryErrProp (cryBool (isFin x ) ) ) )
[<-recv] success
[send->] (define-fun cryGeq ((x InfNat ) (y InfNat ) ) MaybeBool (ite (or (isErr x ) (isErr y ) ) cryErrProp (cryBool (ite (isFin x ) (ite (isFin y ) (>= (value x ) (value y ) ) false ) true ) ) ) )
[<-recv] success
[send->] (define-fun cryAnd ((x MaybeBool ) (y MaybeBool ) ) MaybeBool (ite (or (isErrorProp x ) (isErrorProp y ) ) cryErrProp (cryBool (and (prop x ) (prop y ) ) ) ) )
[<-recv] success
[send->] (define-fun cryTrue () MaybeBool (cryBool true ) )
[<-recv] success
[send->] (define-fun cryVar ((x InfNat ) ) Bool (and (not (isErr x ) ) (>= (value x ) 0 ) ) )
[<-recv] success
[send->] (define-fun cryAssume ((x MaybeBool ) ) Bool (ite (isErrorProp x ) true (prop x ) ) )
[<-recv] success
[send->] (declare-fun cryUnknown () Bool )
[<-recv] success
[send->] (define-fun cryProve ((x MaybeBool ) ) Bool (ite (isErrorProp x ) cryUnknown (not (prop x ) ) ) )
[<-recv] success
[send->] (define-fun cryAdd ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) ) cryErr (ite (isFin x ) (ite (isFin y ) (cryNat (+ (value x ) (value y ) ) ) cryInf ) cryInf ) ) )
[<-recv] success
[send->] (define-fun crySub ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) (not (isFin y ) ) ) cryErr (ite (isFin x ) (ite (>= (value x ) (value y ) ) (cryNat (- (value x ) (value y ) ) ) cryErr ) cryInf ) ) )
[<-recv] success
[send->] (define-fun cryMul ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) ) cryErr (ite (isFin x ) (ite (isFin y ) (cryNat (* (value x ) (value y ) ) ) (ite (= (value x ) 0 ) (cryNat 0 ) cryInf ) ) (ite (and (isFin y ) (= (value y ) 0 ) ) (cryNat 0 ) cryInf ) ) ) )
[<-recv] success
[send->] (define-fun cryDiv ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) (not (isFin x ) ) ) cryErr (ite (isFin y ) (ite (= (value y ) 0 ) cryErr (cryNat (div (value x ) (value y ) ) ) ) (cryNat 0 ) ) ) )
[<-recv] success
[send->] (define-fun cryMod ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) (not (isFin x ) ) ) cryErr (ite (isFin y ) (ite (= (value y ) 0 ) cryErr (cryNat (mod (value x ) (value y ) ) ) ) x ) ) )
[<-recv] success
[send->] (define-fun cryMin ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) ) cryErr (ite (isFin x ) (ite (isFin y ) (ite (<= (value x ) (value y ) ) x y ) x ) y ) ) )
[<-recv] success
[send->] (define-fun cryMax ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) ) cryErr (ite (isFin x ) (ite (isFin y ) (ite (<= (value x ) (value y ) ) y x ) y ) x ) ) )
[<-recv] success
[send->] (declare-fun cryWidthUnknown (Int ) Int )
[<-recv] success
[send->] (define-fun k_2_to_64 () Int 18446744073709551616 )
[<-recv] success
[send->] (define-fun k_2_to_65 () Int 36893488147419103232 )
[<-recv] success
[send->] (assert (forall ((x Int ) ) (or (> (cryWidthUnknown x ) 64 ) (< x k_2_to_64 ) ) ) )
[<-recv] success
[send->] (assert (forall ((x Int ) ) (or (> x (cryWidthUnknown x ) ) (< x k_2_to_64 ) ) ) )
[<-recv] success
[send->] (assert (forall ((x Int ) ) (or (>= 65 (cryWidthUnknown x ) ) (>= x k_2_to_65 ) ) ) )
[<-recv] success
[send->] (assert (forall ((x Int ) (y Int ) ) (=> (>= x y ) (>= (cryWidthUnknown x ) (cryWidthUnknown y ) ) ) ) )
[<-recv] success
[send->] (define-fun cryWidthTable ((x Int ) ) Int (ite (< x 1 ) 0 (ite (< x 2 ) 1 (ite (< x 4 ) 2 (ite (< x 8 ) 3 (ite (< x 16 ) 4 (ite (< x 32 ) 5 (ite (< x 64 ) 6 (ite (< x 128 ) 7 (ite (< x 256 ) 8 (ite (< x 512 ) 9 (ite (< x 1024 ) 10 (ite (< x 2048 ) 11 (ite (< x 4096 ) 12 (ite (< x 8192 ) 13 (ite (< x 16384 ) 14 (ite (< x 32768 ) 15 (ite (< x 65536 ) 16 (ite (< x 131072 ) 17 (ite (< x 262144 ) 18 (ite (< x 524288 ) 19 (ite (< x 1048576 ) 20 (ite (< x 2097152 ) 21 (ite (< x 4194304 ) 22 (ite (< x 8388608 ) 23 (ite (< x 16777216 ) 24 (ite (< x 33554432 ) 25 (ite (< x 67108864 ) 26 (ite (< x 134217728 ) 27 (ite (< x 268435456 ) 28 (ite (< x 536870912 ) 29 (ite (< x 1073741824 ) 30 (ite (< x 2147483648 ) 31 (ite (< x 4294967296 ) 32 (ite (< x 8589934592 ) 33 (ite (< x 17179869184 ) 34 (ite (< x 34359738368 ) 35 (ite (< x 68719476736 ) 36 (ite (< x 137438953472 ) 37 (ite (< x 274877906944 ) 38 (ite (< x 549755813888 ) 39 (ite (< x 1099511627776 ) 40 (ite (< x 2199023255552 ) 41 (ite (< x 4398046511104 ) 42 (ite (< x 8796093022208 ) 43 (ite (< x 17592186044416 ) 44 (ite (< x 35184372088832 ) 45 (ite (< x 70368744177664 ) 46 (ite (< x 140737488355328 ) 47 (ite (< x 281474976710656 ) 48 (ite (< x 562949953421312 ) 49 (ite (< x 1125899906842624 ) 50 (ite (< x 2251799813685248 ) 51 (ite (< x 4503599627370496 ) 52 (ite (< x 9007199254740992 ) 53 (ite (< x 18014398509481984 ) 54 (ite (< x 36028797018963968 ) 55 (ite (< x 72057594037927936 ) 56 (ite (< x 144115188075855872 ) 57 (ite (< x 288230376151711744 ) 58 (ite (< x 576460752303423488 ) 59 (ite (< x 1152921504606846976 ) 60 (ite (< x 2305843009213693952 ) 61 (ite (< x 4611686018427387904 ) 62 (ite (< x 9223372036854775808 ) 63 (ite (< x 18446744073709551616 ) 64 (cryWidthUnknown x ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) )
[<-recv] success
[send->] (define-fun cryWidth ((x InfNat ) ) InfNat (ite (isErr x ) cryErr (ite (isFin x ) (cryNat (cryWidthTable (value x ) ) ) cryInf ) ) )
[<-recv] success
[send->] (declare-fun cryExpUnknown (Int Int ) Int )
[<-recv] success
[send->] (assert (forall ((x Int ) (y Int ) ) (=> (and (> y 0 ) (> x 0 ) ) (>= (cryExpUnknown x y ) x ) ) ) )
[<-recv] success
[send->] (define-fun cryExpTable ((x Int ) (y Int ) ) Int (ite (= y 0 ) 1 (ite (= y 1 ) x (ite (= x 0 ) 0 (cryExpUnknown x y ) ) ) ) )
[<-recv] success
[send->] (define-fun cryExp ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) ) cryErr (ite (isFin x ) (ite (isFin y ) (cryNat (cryExpTable (value x ) (value y ) ) ) (ite (< (value x ) 2 ) x cryInf ) ) (ite (isFin y ) (ite (= (value y ) 0 ) (cryNat 1 ) cryInf ) cryInf ) ) ) )
[<-recv] success
[send->] (define-fun cryCeilDiv ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) (not (isFin y ) ) ) cryErr (ite (= (value y ) 0 ) cryErr (ite (not (isFin x ) ) cryInf (cryNat (- (div (- (value x ) ) (value y ) ) ) ) ) ) ) )
[<-recv] success
[send->] (define-fun cryCeilMod ((x InfNat ) (y InfNat ) ) InfNat (ite (or (isErr x ) (isErr y ) (not (isFin y ) ) ) cryErr (ite (= (value y ) 0 ) cryErr (ite (not (isFin x ) ) (cryNat 0 ) (cryNat (mod (- (value x ) ) (value y ) ) ) ) ) ) )
[<-recv] success
[send->] (define-fun cryLenFromThenTo ((x InfNat ) (y InfNat ) (z InfNat ) ) InfNat (ite (or (isErr x ) (not (isFin x ) ) (isErr y ) (not (isFin y ) ) (isErr z ) (not (isFin z ) ) (= (value x ) (value y ) ) ) cryErr (cryNat (ite (> (value x ) (value y ) ) (ite (> (value z ) (value x ) ) 0 (+ (div (- (value x ) (value z ) ) (- (value x ) (value y ) ) ) 1 ) ) (ite (< (value z ) (value x ) ) 0 (+ (div (- (value z ) (value x ) ) (- (value y ) (value x ) ) ) 1 ) ) ) ) ) )
[<-recv] success
Loading module Cryptol
PROVE IMP
  VARIABLES
    [send->] (push 1 )
cryptol: user error (Missing response from solver)
$ 

@mouse07410
Copy link
Author

I'd like to see a different kind of debug messages, at a much lower level:

  • how SMT process (executable) is started
  • tracking that it did not exit/quit at or after the Loading module Cryptol message
  • exact IPC message (push 1) that went to that (presumably still running) SMT process, and how it was sent

The current verbose output tells me that when Cryptol "thinks" it "sent" something to the SMT process, something somehow ([<-recv] appears to come back from (presumably) that process, so Cryptol is happy. While we need to figure whether

  • (push 1) is a legitimate message
  • Z3 received it
  • Z3 responded
  • Cryptol received the response and processed it correctly

@RyanGlScott
Copy link
Contributor

Thanks! Interestingly, the Missing response from solver occurs right after (push 1 ). I wonder if this can be reproduced outside of a Cryptol context. As an experiment, can you make a file called test.smt2 with the following contents:

(set-option :print-success true )
(set-option :produce-models true )
(set-option :global-decls false )
(push 1 )

And run it through z3 like so?

$ z3 -smt2 test.smt2

For me, that produces:

success
success
success
success

It's possible that this may not be enough to trigger your issue, however. The way that Cryptol actually invokes Z3 is through an interactive process, like so:

$ z3 -smt2 -in

And then it redirects the commands to the Z3 process via standard input. For instance, I can run the sequence of commands in test.smt2 like so:

$ ~/Software/z3-4.8.17/bin/z3 -smt2 -in
(set-option :print-success true )
success
(set-option :produce-models true )
success
(set-option :global-decls false )
success
(push 1 )
success

Where I typed each command, hit Enter, and then received success for a response as output. Can you try this as well?

@RyanGlScott
Copy link
Contributor

I did not see your comment at #1488 (comment) until after submitting #1488 (comment), but to answer your questions:

  • how SMT process (executable) is started

Cryptol is managing its Z3 subprocess through the simple-smt library. The relevant function is newSolverNotify. This function is invoked here in Cryptol:

solver <- SMT.newSolverNotify
(solverPath sCfg) (solverArgs sCfg) smtDbg (Just (const onExit))

And we are using the default values of solverPath and solverArgs taken from here:

-- | A default configuration for using Z3, where
-- the solver prelude is expected to be found
-- in the given search path.
defaultSolverConfig :: [FilePath] -> SolverConfig
defaultSolverConfig searchPath =
SolverConfig
{ solverPath = "z3"
, solverArgs = [ "-smt2", "-in" ]
, solverVerbose = 0
, solverPreludePath = searchPath
}

So the subprocess is being invoked as z3 -smt2 -in.

  • tracking that it did not exit/quit at or after the Loading module Cryptol message

It is quitting after that message. This is because the PROVE IMP/VARIABLES messages come from here:

-- | Returns goals that were not proved
proveImp :: Solver -> [Prop] -> [Goal] -> IO [Goal]
proveImp sol ps gs0 =
debugBlock sol "PROVE IMP" $
do let gs1 = concatMap flatGoal gs0
(gs,rest) = partition (isNumeric . goal) gs1
numAsmp = filter isNumeric (concatMap pSplitAnd ps)
vs = Set.toList (fvs (numAsmp, map goal gs))
tvs <- debugBlock sol "VARIABLES" $
do SMT.push (solver sol)
Map.fromList <$> zipWithM (declareVar sol) [ 0 .. ] vs
debugBlock sol "ASSUMPTIONS" $
mapM_ (assume sol tvs) numAsmp
gs' <- mapM (prove sol tvs) gs
SMT.pop (solver sol)
return (catMaybes gs' ++ rest)

And the Loading module Cryptol message comes from here:

-- | Load dependencies, typecheck, and add to the eval environment.
doLoadModule ::
Bool {- ^ evaluate declarations in the module -} ->
Bool {- ^ quiet mode: true suppresses the "loading module" message -} ->
ImportSource ->
ModulePath ->
Fingerprint ->
P.Module PName ->
ModuleM T.Module
doLoadModule eval quiet isrc path fp pm0 =
loading isrc $
do let pm = addPrelude pm0
loadDeps pm
unless quiet $ withLogger logPutStrLn
("Loading module " ++ pretty (P.thing (P.mName pm)))

doLoadModule happens as the very first thing in a Cryptol session, and it is responsible for loading the prelude called Cryptol.cry (hence the Loading module Cryptol message). The proveImp function is called when checking Cryptol type signatures, which happens for the signatures in Cryptol.cry, which occurs after loading the module.

  • exact IPC message (push 1) that went to that (presumably still running) SMT process, and how it was sent

Setting :tcDebug=2 causes the simple-smt library to print exactly these messages. The [send->]/[<-recv] bits are just tags that simple-smt adds, which you can see here.

The (push 1) command in particular is sent right after the VARIABLES message, as seen here:

tvs <- debugBlock sol "VARIABLES" $
do SMT.push (solver sol)

@weaversa
Copy link
Collaborator

weaversa commented Jan 12, 2023

If you want to see the commands flowing to and from z3, you can use tee.

First, rename z3 to _z3, then create a bash script named z3:

tee -a ~/z3.log | _z3 -smt2 -in | tee -a ~/z3.log

Then you can tail -f ~/z3.log the log file while you interact with Cryptol.

@mouse07410
Copy link
Author

Funny - here's what I got:

$ z3 -smt2 test2.smt 
success
success
success
Segmentation fault: 11
$ 

and crash report:

Termination Reason:    Namespace SIGNAL, Code 11 Segmentation fault: 11
Terminating Process:   exc handler [58074]

VM Region Info: 0 is not in any region.  Bytes before following region: 4382007296
      REGION TYPE                    START - END         [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                      105302000-10689a000    [ 21.6M] r-x/r-x SM=COW  .../local/bin/z3

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   z3                            	       0x106198c80 smt::theory_seq::theory_seq(smt::context&) + 192
1   z3                            	       0x105f55e39 smt::setup::setup_seq_str(static_features const&) + 265
2   z3                            	       0x105f516a0 smt::setup::setup_unknown() + 384
3   z3                            	       0x105ef95e5 smt::context::setup_context(bool) + 149
4   z3                            	       0x105ef570d smt::context::push() + 61
5   z3                            	       0x105a78908 solver_na2as::push() + 40
6   z3                            	       0x105a9984d cmd_context::push() + 2205
7   z3                            	       0x105ac6268 smt2::parser::operator()() + 4312
8   z3                            	       0x10672f693 read_smtlib2_commands(char const*) + 563
9   z3                            	       0x10672cfa3 main + 2115
10  dyld                          	       0x10c83352e start + 462

Submitted a bug report at Macports: https://trac.macports.org/ticket/66676#ticket

Working on getting a working Z3 from other sources.

@weaversa
Copy link
Collaborator

For me, on macos, z3 builds out-of-the-box after pulling the source from github and running make. Fingers crossed you have a similar experience.

@mouse07410
Copy link
Author

Building and installing Z3 v4.11.2 from sources, majority of the tests pass:
cry-tests.txt

         Test Cases    Total        
 Passed  299           299          
 Failed  7             7            
 Total   306           306 

@RyanGlScott
Copy link
Contributor

Thanks! As far as the 7 test case failures are concerned:

  • 1 test (constant.icry) is failing because of GHC printing out a linker warning due to GHC#22429. I claim that this is a bug on GHC's end, not Cryptol's.

  • 3 of the tests (cplx.icry, poly.icry, and rational_properties.icry) are failing because you do not have CVC4 installed.

  • 3 of the tests (ffi-reload.icry, ffi-runtime-errors.icry, and test-ffi.icry) are failing because your C compiler cannot find the GMP library, e.g.,

    > ld: library not found for -lgmp
    > clang: error: linker command failed with exit code 1 (use -v to see invocation)
    > make: *** [ffi-runtime-errors.dylib] Error 1
    

    These test cases require GMP, so it isn't surprising that they fail if clang -lgmp doesn't work.

@RyanGlScott
Copy link
Contributor

It sounds like installing Z3 from a source besides MacPorts has resolved the issue, so I'll go ahead and close this. If you encounter other issues, please do not hesitate to open a separate issue. Thanks for your patience and help in debugging this, @mouse07410!

@mouse07410
Copy link
Author

These test cases require GMP, so it isn't surprising that they fail if clang -lgmp doesn't work.

This is interesting - clang -lgmp does not work, but clang -L/opt/local/lib -lgmp does.

So, how do I tell Cryptol to look for the "extras" (C headers and libraries) in /opt/local/include and /opt/local/lib correspondingly?

Or do you want me to open a new issue for this?

@RyanGlScott
Copy link
Contributor

Feel free to file a new issue if you believe there is another Cryptol issue lurking here. That being said, I don't think the issue is necessarily on Cryptol's side. The FFI-related tests first build a foreign library using this Makefile, which uses the CC macro to determine your C compiler. In this case, that's clang, and clang isn't searching /opt/local/lib for libraries for some reason.

I think you can resolve the issue by extending clang's library search path (e.g., export LIBRARY_PATH=/opt/local/lib:$LIBRARY_PATH). You'd probably need to do something similar for the location of GMP's header files (e.g., export C_INCLUDE_PATH=<path-to-gmp-headers>:$C_INCLUDE_PATH) as well.

@mouse07410
Copy link
Author

clang isn't searching /opt/local/lib for libraries for some reason.

The reason being - it's not a system location (like /lib, /usr/lib, and on Mac perhaps some /Library/whatever/...).

That means these locations must be explicitly given to clang (and/or to gcc, same thing in this respect), usually by by

  • adding something like -I/opt/local/include to CFLAGS env var and -L/opt/local/lib to LDFLAGS env var, and
  • making sure that clang invocation in the Makefile includes these, like clang $CFLAGS <whatever> to compile and clang $LDFLAGS $LDLIBS -o whatever <whatever> for the linker stage.

How can I do it with Cryptol, where the build details are "under the hood"? I think it needs a way to intake these.

@RyanGlScott
Copy link
Contributor

I think extending C_INCLUDE_PATH/LIBRARY_PATH like I describe in #1488 (comment) is the idiomatic way to accomplish this without having to change every invocation of clang.

@mouse07410
Copy link
Author

I think extending C_INCLUDE_PATH/LIBRARY_PATH like I describe in #1488 (comment) is the idiomatic way to accomplish this without having to change every invocation of clang.

You are correct, thank you!

CPATH or C_INCLUDE_PATH for C, CPLUS_INCLUDE_PATH for C++, and LIBRARY_PATH for linker. That fixed FFI tests, and after I installed cvc4 SMT solver (in addition to Z3 solver), all tests passed:

         Test Cases    Total        
 Passed  306           306          
 Failed  0             0            
 Total   306           306 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants