Verifier.hs 8.70 KiB
module Verifier where
import Language.Java.Syntax
import Language.Java.Pretty
import Z3.Monad
import System.IO.Unsafe
import Folds
import HelperFunctions
-- | Checks wether the negation is unsatisfiable
isTrue :: Exp -> Z3 Bool
isTrue e = isFalse (PreNot e)
-- | Checks wether the expression is unsatisfiable
isFalse :: Exp -> Z3 Bool
isFalse e =
do
ast <- foldExp expAssertAlgebra e
assert ast
result <- check
solverReset
case result of
Unsat -> return True
_ -> return False
-- | Unsafe version of isTrue
unsafeIsTrue :: Exp -> Bool
unsafeIsTrue = unsafePerformIO . evalZ3 . isTrue
-- | Unsafe version of isFalse
unsafeIsFalse :: Exp -> Bool
unsafeIsFalse = unsafePerformIO . evalZ3 . isFalse
stringToBv :: String -> Z3 AST
stringToBv [] = mkIntNum 0 >>= mkInt2bv 8
stringToBv (c:cs) = do
c' <- mkIntNum (fromEnum c) >>= mkInt2bv 8
cs' <- stringToBv cs
mkConcat c' cs'
-- | Defines the convertion from an expression to AST so that Z3 can assert satisfiability
-- This is used to fold expressions generated by the WLP transformer, so not all valid Java expressions need to be handled
expAssertAlgebra :: ExpAlgebra (Z3 AST)
expAssertAlgebra = (fLit, fClassLit, fThis, fThisClass, fInstanceCreation, fQualInstanceCreation, fArrayCreate, fArrayCreateInit, fFieldAccess, fMethodInv, fArrayAccess, fExpName, fPostIncrement, fPostDecrement, fPreIncrement, fPreDecrement, fPrePlus, fPreMinus, fPreBitCompl, fPreNot, fCast, fBinOp, fInstanceOf, fCond, fAssign, fLambda, fMethodRef) where
fLit lit = case lit of
Int n -> mkInteger n
Word n -> mkInteger n
Float d -> mkRealNum d
Double d -> mkRealNum d
Boolean b -> mkBool b
Char c -> do sort <- mkIntSort
mkInt (fromEnum c) sort
String s -> stringToBv s
Null -> do sort <- mkIntSort
mkInt 0 sort
fClassLit = undefined
fThis = undefined
fThisClass = undefined
fInstanceCreation = undefined
fQualInstanceCreation = undefined
fArrayCreate = undefined
fArrayCreateInit = undefined
fFieldAccess fieldAccess = case fieldAccess of
PrimaryFieldAccess e id -> case e of
InstanceCreation _ t args _ -> undefined
_ -> undefined
SuperFieldAccess id -> mkStringSymbol (prettyPrint (Name [id])) >>= mkIntVar
ClassFieldAccess (Name name) id -> mkStringSymbol (prettyPrint (Name (name ++ [id]))) >>= mkIntVar
fMethodInv invocation = case invocation of
MethodCall (Name [Ident "*length"]) [a, (Lit (Int n))] -> case a of
ArrayCreate t exps dim -> foldExp expAssertAlgebra (if fromEnum n < length exps then (exps !! fromEnum n) else Lit (Int 0))
ArrayCreateInit t dim arrayInit -> mkInteger 0
_ -> error "length of non-array"
_ -> error (prettyPrint invocation)
fArrayAccess arrayIndex = case arrayIndex of
ArrayIndex (ArrayCreate t _ _) _ -> foldExp expAssertAlgebra (getInitValue t)
ArrayIndex (ArrayCreateInit t _ _) _ -> foldExp expAssertAlgebra (getInitValue t)
ArrayIndex e _ -> foldExp expAssertAlgebra e
fExpName name = do
symbol <- mkStringSymbol (prettyPrint name)
mkIntVar symbol
fPostIncrement = undefined
fPostDecrement = undefined
fPreIncrement = undefined
fPreDecrement = undefined
fPrePlus e = e
fPreMinus e = do
ast <- e
zero <- mkInteger 0
mkSub [zero, ast]
fPreBitCompl = undefined
fPreNot e = e >>= mkNot
fCast = undefined
fBinOp e1 op e2 = case op of
Mult -> do
ast1 <- e1
ast2 <- e2
mkMul [ast1, ast2]
Div -> do
ast1 <- e1
ast2 <- e2
mkDiv ast1 ast2
Rem -> do
ast1 <- e1
ast2 <- e2
mkRem ast1 ast2
Add -> do
ast1 <- e1
ast2 <- e2
mkAdd [ast1, ast2]
Sub -> do
ast1 <- e1
ast2 <- e2
mkSub [ast1, ast2]
LShift -> do
ast1 <- e1
ast2 <- e2
mkBvshl ast1 ast2
RShift -> do
ast1 <- e1
ast2 <- e2
mkBvashr ast1 ast2
RRShift -> do
ast1 <- e1
ast2 <- e2
mkBvlshr ast1 ast2
LThan -> do
ast1 <- e1
ast2 <- e2
mkLt ast1 ast2
GThan -> do
ast1 <- e1
ast2 <- e2
mkGt ast1 ast2
LThanE -> do
ast1 <- e1
ast2 <- e2
mkLe ast1 ast2
GThanE -> do
ast1 <- e1
ast2 <- e2
mkGe ast1 ast2
Equal -> do
ast1 <- e1
ast2 <- e2
mkEq ast1 ast2
NotEq -> do
ast1 <- e1
ast2 <- e2
eq <- mkEq ast1 ast2
mkNot eq
And-> do
ast1 <- e1
ast2 <- e2
mkAnd [ast1, ast2]
Or -> do
ast1 <- e1
ast2 <- e2
mkOr [ast1, ast2]
Xor -> do
ast1 <- e1
ast2 <- e2
mkXor ast1 ast2
CAnd -> do
ast1 <- e1
ast2 <- e2
mkAnd [ast1, ast2]
COr -> do
ast1 <- e1
ast2 <- e2
mkOr [ast1, ast2]
fInstanceOf = undefined
fCond g e1 e2 = do
astg <- (g >>= mkNot)
assert astg
result <- check
solverReset
case result of
Sat -> e2
Unsat -> e1
_ -> error "can't evaluate if-condition"
fAssign = undefined
fLambda = undefined
fMethodRef = undefined