Exemple #1
0
    def test_msat_preferred_variable(self):
        a, b, c = [Symbol(x) for x in "abc"]
        na, nb, nc = [Not(Symbol(x)) for x in "abc"]

        f = And(Implies(a, And(b, c)), Implies(na, And(nb, nc)))

        s1 = Solver("msat")
        s1.add_assertion(f)
        s1.set_preferred_var(a, True)
        self.assertTrue(s1.solve())
        self.assertTrue(s1.get_value(a).is_true())

        s2 = Solver("msat")
        s2.add_assertion(f)
        s2.set_preferred_var(a, False)
        self.assertTrue(s2.solve())
        self.assertTrue(s2.get_value(a).is_false())

        # Show that calling without polarity still works
        # This case is harder to test, because we only say
        # that the split will occur on that variable first.
        s1.set_preferred_var(a)
Exemple #2
0
    def test_msat_preferred_variable(self):
        a, b, c = [Symbol(x) for x in "abc"]
        na, nb, nc = [Not(Symbol(x)) for x in "abc"]

        f = And(Implies(a, And(b,c)),
                Implies(na, And(nb,nc)))

        s1 = Solver("msat")
        s1.add_assertion(f)
        s1.set_preferred_var(a, True)
        self.assertTrue(s1.solve())
        self.assertTrue(s1.get_value(a).is_true())

        s2 = Solver("msat")
        s2.add_assertion(f)
        s2.set_preferred_var(a, False)
        self.assertTrue(s2.solve())
        self.assertTrue(s2.get_value(a).is_false())

        # Show that calling without polarity still works
        # This case is harder to test, because we only say
        # that the split will occur on that variable first.
        s1.set_preferred_var(a)
Exemple #3
0
def solve_soduku_model(model):
    solver = Solver()
    solver.add_assertion(model.extractConstraints())

    if solver.solve():  # solution found
        solution = tabletools.generateEmptyTable(model.n)

        for y in range(0, model.n):  # retrive the values from the sloved model
            for x in range(0, model.n):
                solution[y][x] = solver.get_value(model.getSymbol(x, y))

        return solution

    else:
        return None  # couldn't solve model :(
Exemple #4
0
class Reluzy:

    def __init__(self, filename, violationfile, logger):
        self.logger = logger
        self.nnet2smt = Nnet2Smt(filename, violationfile)
        self.nnet2smt.convert(True)
        self.input_vars = self.nnet2smt.input_vars
        self.output_vars = self.nnet2smt.output_vars
        self.formulae = self.nnet2smt.formulae
        self.relus = self.nnet2smt.relus
        self.relus_level = self.nnet2smt.relus_level
        self.solver = Solver(name='yices')
        self.sat_checker = Solver(name='yices')
        self.init()
        
    def init(self):
        self.solver.add_assertion(And(self.formulae))
        self.sat_checker.add_assertion(And(self.formulae))
        for r1, r2 in self.relus:
            self.sat_checker.add_assertion(Equals(r1, Max(r2, Real(0))))
        #lemmas = self.refine_zero_lb(False)
        #self.solver.add_assertion(And(lemmas))
        #lemmas = self.refine_slope_lb(False)
        #self.solver.add_assertion(And(lemmas))

    def solve(self):
        while True:
            self.logger.info('Solving')
            res = self.solver.solve()
            if not res:
                print('unsat')
                break
            else:
                lemmas = self.refine()
                if not lemmas:
                    print('sat')
                    break
                else:
                    self.solver.add_assertion(And(lemmas))


    def check_sat(self):
        self.logger.info('Checking for Sat')
        self.sat_checker.push()
        for v in self.input_vars:
            self.sat_checker.add_assertion(Equals(v, self.solver.get_value(v)))
        res = self.sat_checker.solve()
        if res:
            for x in self.input_vars:
                print(v, self.sat_checker.get_value(x))
            return True
        else:
            self.sat_checker.pop()
            return False
            

    def refine(self):
        self.logger.info('Refining')
        lemmas = self.refine_zero_lb()
        if not lemmas:
            lemmas = self.refine_slope_lb()

        if not lemmas:
            lemmas = self.refine_zero_ub()

        if not lemmas:
            lemmas = self.refine_slope_ub()

        if not lemmas:
            for v in self.input_vars:
                print(v, self.solver.get_value(v))
        #elif self.check_sat():
        #    return []

        return lemmas

    def refine_zero_lb(self, check=True):
        lemmas = []
        zero = Real(0)
        for r1, _ in self.relus:
            l = GE(r1, zero)
            if check:
                tval = self.solver.get_value(l)
                if tval.is_false():
                    lemmas.append(l)
                    self.logger.debug('Adding %s' % l )
            else:
                lemmas.append(l)
        return lemmas

    def refine_zero_ub(self):
        lemmas = []
        zero = Real(0)
        for s in self.relus_level:
            for r1, r2 in s:
                l = Implies(LE(r2, zero), LE(r1, zero))
                tval = self.solver.get_value(l)
                if tval.is_false():
                    lemmas.append(l)
                    self.logger.debug('Adding %s' % l )
            if lemmas:
                break
        return lemmas
        
    def refine_slope_lb(self, check=True):
        lemmas = []
        for r1, r2 in self.relus:
            l = GE(r1, r2)
            if check:
                tval = self.solver.get_value(l)
                if tval.is_false():
                    lemmas.append(l)
                    self.logger.debug('Adding %s' % l )
            else:
                lemmas.append(l)
        return lemmas
       
    def refine_slope_ub(self):
        lemmas = []
        zero = Real(0)
        for s in self.relus_level:
            for r1, r2 in s:
                l = Implies(GE(r2, zero), LE(r1, r2))
                tval = self.solver.get_value(l)
                if tval.is_false():
                    lemmas.append(l)
                    self.logger.debug('Adding %s' % l )
            if lemmas:
                break
        return lemmas
Exemple #5
0
class PDR(object):
    def __init__(self, system):
        self.system = system
        self.frames = [system.init]
        self.solver = Solver()
        self.prime_map = dict([(v, next_var(v))
                               for v in self.system.variables])

    def check_property(self, prop):
        """Property Directed Reachability approach without optimizations."""
        print("Checking property %s..." % prop)

        while True:
            cube = self.get_bad_state(prop)
            if cube is not None:
                # Blocking phase of a bad state
                if self.recursive_block(cube):
                    print("--> Bug found at step %d" % (len(self.frames)))
                    break
                else:
                    print("   [PDR] Cube blocked '%s'" % str(cube))
            else:
                # Checking if the last two frames are equivalent i.e., are inductive
                if self.inductive():
                    print("--> The system is safe!")
                    break
                else:
                    print("   [PDR] Adding frame %d..." % (len(self.frames)))
                    self.frames.append(TRUE())

    def get_bad_state(self, prop):
        """Extracts a reachable state that intersects the negation
        of the property and the last current frame"""
        return self.solve(And(self.frames[-1], Not(prop)))

    def solve(self, formula):
        """Provides a satisfiable assignment to the state variables that are consistent with the input formula"""
        if self.solver.solve([formula]):
            return And([
                EqualsOrIff(v, self.solver.get_value(v))
                for v in self.system.variables
            ])
        return None

    def recursive_block(self, cube):
        """Blocks the cube at each frame, if possible.

        Returns True if the cube cannot be blocked.
        """
        for i in range(len(self.frames) - 1, 0, -1):
            cubeprime = cube.substitute(
                dict([(v, next_var(v)) for v in self.system.variables]))
            cubepre = self.solve(
                And(self.frames[i - 1], self.system.trans, Not(cube),
                    cubeprime))
            if cubepre is None:
                for j in range(1, i + 1):
                    self.frames[j] = And(self.frames[j], Not(cube))
                return False
            cube = cubepre
        return True

    def inductive(self):
        """Checks if last two frames are equivalent """
        if len(self.frames) > 1 and \
           self.solve(Not(EqualsOrIff(self.frames[-1], self.frames[-2]))) is None:
            return True
        return False

    def __del__(self):
        self.solver.exit()
Exemple #6
0
def analyze_rv32_interpreter(program: List[Instruction],
                             bbs: List[BasicBlock]):
    #print("analyzing rv32 interpreter ...")

    mk_dot(dot_cfg(bbs), filename="cfg.pdf")
    #for bb in program: print(bb)

    # start at MainStart @ 0x0056
    start_pc = 0x56
    # symbolic instruction: ADD rs2, rs1, rd
    funct7 = BitVecVal(0, 7)
    rs2 = Symbol("RV32I_ADD_rs2", BVType(5))
    rs1 = Symbol("RV32I_ADD_rs1", BVType(5))
    funct3 = BitVecVal(0b00, 3)  # ADD
    rd = Symbol("RV32I_ADD_rd", BVType(5))
    opcode = BitVecVal(0b0110011, 7)  # OP
    #RV32I_instr = Symbol("RV32IInstruction", BVType(32))
    RV32I_instr = cat(funct7, rs2, rs1, funct3, rd, opcode)
    print(f"Symbolically executing: {RV32I_instr}")

    # interpreter
    orig_state = MachineState().update(PC=BitVecVal(start_pc, 16))

    def place_instr(loc, instr, st) -> MachineState:
        # make sure PC fits into two registers
        assert loc & 0xffff == loc
        msb, lsb = BitVecVal(loc >> 8, 8), BitVecVal(loc & 0xff, 8)
        st = st.update(R=st.R.update(10, lsb).update(11, msb))
        instr_parts = [
            BVExtract(instr, *jj)
            for jj in ((jj * 8, jj * 8 + 7) for jj in range(4))
        ]
        if isinstance(loc, int):
            instr_locs = [loc + ii for ii in range(4)]
        else:
            assert False, "TODO: support symbolic address"
        mem = st.MEM
        for loc, val in zip(instr_locs, instr_parts):
            mem = mem.update(loc, val)
        return st.update(MEM=mem)

    orig_state = place_instr(loc=0, instr=RV32I_instr, st=orig_state)

    mf8_ex = SymExec()
    ex = SymbolicExecutionEngine(program=program,
                                 start_state=orig_state,
                                 semantics=mf8_ex)

    print()
    print()
    print("SYM EXEC")
    print("--------")
    done, end_state = ex.run(max_steps=2000)
    #ex.print_state()
    #ex.print_mem(ex.st)
    #ex.print_path()
    print(ex.taken)
    print(f"DONE? {done}")
    #print("PATHS:")
    for ii, (cond, st) in enumerate(end_state):
        print(str(ii) + ") " + cond.serialize())
        #ex.print_mem(st)

    solver = Solver(name="z3", logic=QF_AUFBV)

    # check for completeness
    conds = reduce(Or, (cond for cond, st in end_state))
    complete = not solver.is_sat(Not(conds))
    print(f"Complete? {complete}")

    # check result of every path:
    def to_mem_addrs(reg_index):
        return reversed([0xf100 + reg_index * 8 + jj for jj in range(4)])

    def relate_regs(mem, regs):
        def relate_loc(ii):
            mem_locs = [
                Select(mem, BitVecVal(addr, 16)) for addr in to_mem_addrs(ii)
            ]
            return Equals(cat(*mem_locs), Select(regs, BitVecVal(ii, 5)))

        return reduce(And, [relate_loc(ii) for ii in range(32)])

    def name_value(solver, name, val):
        sym = Symbol(name, val.get_type())
        solver.add_assertion(Equals(sym, val))

    def locs_to_str(name, array, locs):
        return "; ".join(f"{name}[{ii:04x}] = 0x{array[ii]:02x}"
                         for ii in sorted(list(set(locs))))

    for ii, (cond, end_st) in enumerate(end_state):
        # create clean slate solver
        solver = Solver(name="cvc4", logic=QF_AUFBV, generate_models=True)
        # symbolically execute the RISC-V add
        regs = Symbol('RV32I_REGS', ArrayType(BVType(5), BVType(32)))
        regs_n = sym_exec_rsicv_add(rs1=rs1, rs2=rs2, rd=rd, regs=regs)
        name_value(solver, "DBG_RV32I_REGS_N", regs_n)
        # add mem to regs relation
        mem_orig = orig_state.MEM.array()
        pre = And(And(cond, relate_regs(mem_orig, regs)),
                  Equals(Select(regs, BitVecVal(0, 5)), BitVecVal(0, 32)))
        mem_n = end_st.MEM.array()
        post = relate_regs(mem_n, regs_n)
        # DEBUG: add symbols for every memory write
        mem_data = end_st._mem._data
        mem_write_locs = [
            Symbol(f"DBG_MF8_MEM_WRITE_LOC_{ii}", BVType(16))
            for ii in range(len(mem_data))
        ]
        for sym, (expr, _) in zip(mem_write_locs, mem_data):
            solver.add_assertion(Equals(sym, expr))
        # now check for validity
        formula = Implies(pre, post)
        write_smtlib(Not(formula), f"path_{ii:02}.smt2")
        correct = solver.is_valid(formula)
        print(f"Correct? {correct}")
        if not correct:
            print("Path condition:")
            print(cond.serialize())
            print("Symbolic Mem:")
            ex.print_mem(end_st)
            print("Model:")
            rs1_val = solver.get_value(rs1).bv_unsigned_value()
            rs2_val = solver.get_value(rs2).bv_unsigned_value()
            rd_val = solver.get_value(rd).bv_unsigned_value()
            regs_val = ArrayValue(solver.get_value(regs))
            regs_n_val = ArrayValue(solver.get_value(regs_n))
            mem_val = ArrayValue(solver.get_value(mem_orig))
            mem_n_val = ArrayValue(solver.get_value(mem_n))
            reg_addrs = [rd_val, rs1_val, rs2_val]
            mem_write_locs_vals = [
                solver.get_value(ll).bv_unsigned_value()
                for ll in mem_write_locs
            ]
            mem_addrs = reduce(operator.add,
                               [list(to_mem_addrs(ii))
                                for ii in reg_addrs]) + mem_write_locs_vals
            print(f"R[{rd_val}] <- R[{rs1_val}] + R[{rs2_val}]")
            print(f"Pre:  {locs_to_str('R', regs_val, reg_addrs)}")
            print(f"      {locs_to_str('M',  mem_val, mem_addrs)}")
            print(f"Post: {locs_to_str('R', regs_n_val, reg_addrs)}")
            print(f"      {locs_to_str('M',  mem_n_val, mem_addrs)}")
            print(
                f"MEM write addresses: {[f'0x{loc:04x}' for loc in mem_write_locs_vals]}"
            )
            #print(regs_n_val)
            #print(mem_val)
            # TODO: check PC post-condition
            # TODO: add pre and post conditions for program memory equivalence
            # TODO: add pre and post conditions for data memory equivalence
            break

    return
Exemple #7
0
class PDR(object):
    def __init__(self, system):
        self.system = system
        self.frames = [system.init]
        self.solver = Solver()
        self.prime_map = dict([(v, next_var(v)) for v in self.system.variables])

    def check_property(self, prop):
        """Property Directed Reachability approach without optimizations."""
        print("Checking property %s..." % prop)

        while True:
            cube = self.get_bad_state(prop)
            if cube is not None:
                # Blocking phase of a bad state
                if self.recursive_block(cube):
                    print("--> Bug found at step %d" % (len(self.frames)))
                    break
                else:
                    print("   [PDR] Cube blocked '%s'" % str(cube))
            else:
                # Checking if the last two frames are equivalent i.e., are inductive
                if self.inductive():
                    print("--> The system is safe!")
                    break
                else:
                    print("   [PDR] Adding frame %d..." % (len(self.frames)))
                    self.frames.append(TRUE())

    def get_bad_state(self, prop):
        """Extracts a reachable state that intersects the negation
        of the property and the last current frame"""
        return self.solve(And(self.frames[-1], Not(prop)))

    def solve(self, formula):
        """Provides a satisfiable assignment to the state variables that are consistent with the input formula"""
        if self.solver.solve([formula]):
            return And([EqualsOrIff(v, self.solver.get_value(v)) for v in self.system.variables])
        return None

    def recursive_block(self, cube):
        """Blocks the cube at each frame, if possible.

        Returns True if the cube cannot be blocked.
        """
        for i in range(len(self.frames)-1, 0, -1):
            cubeprime = cube.substitute(dict([(v, next_var(v)) for v in self.system.variables]))
            cubepre = self.solve(And(self.frames[i-1], self.system.trans, Not(cube), cubeprime))
            if cubepre is None:
                for j in range(1, i+1):
                    self.frames[j] = And(self.frames[j], Not(cube))
                return False
            cube = cubepre
        return True

    def inductive(self):
        """Checks if last two frames are equivalent """
        if len(self.frames) > 1 and \
           self.solve(Not(EqualsOrIff(self.frames[-1], self.frames[-2]))) is None:
            return True
        return False