def Mux(in0, in1, sel, out): # if Modules.functional # INVAR: out' = Ite(sel = 0, in0, in1) # else # INVAR: ((sel = 0) -> (out = in0)) & ((sel = 1) -> (out = in1)) vars_ = [in0, in1, sel, out] comment = "Mux (in0, in1, sel, out) = (%s, %s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if sel.symbol_type() == BOOL: sel0 = Not(sel) sel1 = sel else: sel0 = EqualsOrIff(sel, BV(0, 1)) sel1 = EqualsOrIff(sel, BV(1, 1)) if Modules.functional: invar = And(EqualsOrIff(out, Ite(sel0, in0, in1))) else: invar = And(Implies(sel0, EqualsOrIff(in0, out)), Implies(sel1, EqualsOrIff(in1, out))) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def _get_param_assignments(self, model, time, parameters, monotonic=True): p_ass = [] fwd = False for p in parameters: # search the trace for any enabled faults ever_true = False for t in range(time + 1): p_time = model[TS.get_ptimed(p, 0)] if p.symbol_type() == BOOL: if p_time == TRUE(): ever_true = True break if ever_true: p_ass.append(p) elif not monotonic: p_ass.append(EqualsOrIff(p, FALSE())) p_ass = And(p_ass) self.region = simplify(Or(self.region, p_ass)) if self.models is None: self.models = [] self.models.append((model, time)) Logger.msg("+", 0, not (Logger.level(1))) self.cs_count += 1 Logger.log( "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1) return (p_ass, False)
def Uop(bvop, bop, in_, out): # INVAR: (<op> in) = out) vars_ = [in_, out] comment = "" #(bvop.__name__ + " (in, out) = (%s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) in_B = get_type(in_).is_bool_type() outB = get_type(out).is_bool_type() bools = (1 if in_B else 0) + (1 if outB else 0) if bop == None: if in_B: in_ = B2BV(in_) if outB: out = B2BV(out) invar = EqualsOrIff(bvop(in_), out) else: if bools == 2: invar = EqualsOrIff(bop(in_), out) elif bools == 0: invar = EqualsOrIff(bvop(in_), out) else: if not in_B: invar = EqualsOrIff(bop(BV2B(in_)), out) if not outB: invar = EqualsOrIff(bop(in_), BV2B(out)) ts = TS(comment) ts.vars, ts.invar = get_free_variables(invar), invar return ts
def Neq(in0, in1, out): # INVAR: (((in0 != in1) -> (out = #b1)) & ((in0 == in1) -> (out = #b0))) vars_ = [in0, in1, out] comment = "Eq (in0, in1, out) = (%s, %s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) # TODO: Create functional encoding if Modules.functional: if out.symbol_type() == BOOL: invar = EqualsOrIff(out, Not(EqualsOrIff(in0, in1))) else: invar = EqualsOrIff(out, BVNot(BVComp(in0, in1))) else: eq = EqualsOrIff(in0, in1) if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) invar = And(Implies(Not(eq), out1), Implies(eq, out0)) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def Zext(in_, out): # INVAR: (<op> in) = out) vars_ = [in_, out] comment = ("ZExt (in, out) = (%s, %s)") % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if (in_.symbol_type() == BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(in_, out) if (in_.symbol_type() != BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(BV2B(in_), out) if (in_.symbol_type() == BOOL) and (out.symbol_type() != BOOL): length = (out.symbol_type().width) - 1 if length == 0: invar = EqualsOrIff(in_, BV2B(out)) else: invar = EqualsOrIff(BVZExt(B2BV(in_), length), out) if (in_.symbol_type() != BOOL) and (out.symbol_type() != BOOL): length = (out.symbol_type().width) - (in_.symbol_type().width) if length == 0: invar = EqualsOrIff(in_, out) else: invar = EqualsOrIff(BVZExt(in_, length), out) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def simulate(self, prop, k): if self.config.strategy == VerificationStrategy.NU: self._init_at_time(self.hts.vars, 1) (t, model) = self.sim_no_unroll(self.hts, prop, k) else: self._init_at_time(self.hts.vars, k) if prop == TRUE(): self.config.incremental = False (t, model) = self.solve_safety_fwd(self.hts, Not(prop), k, False) else: (t, model) = self.solve_safety(self.hts, Not(prop), k) model = self._remap_model(self.hts.vars, model, t) if (t > -1) and (model is not None): Logger.log("Execution found", 1) trace = self.print_trace(self.hts, model, t, get_free_variables(prop), map_function=self.config.map_function) return (VerificationStatus.TRUE, trace) else: Logger.log("Deadlock wit k=%s" % k, 1) return (VerificationStatus.FALSE, None)
def check_init(): self._reset_assertions(self.solver) self._add_assertion(self.solver, self.at_time(And(init, Not(lemma)), 0), comment="Init check") res = self._solve(self.solver) prefix = None if self.config.prefix is not None: prefix = self.config.prefix + "-ind" if res: if Logger.level(2): Logger.log("Lemma \"%s\" failed for I -> L" % lemma, 2) (hr_trace, vcd_trace) = self.print_trace( hts, self._get_model(self.solver), 0, prefix=prefix, map_function=self.config.map_function) Logger.log("", 2) if hr_trace: Logger.log("Counterexample: \n%s" % (hr_trace), 2) else: Logger.log("", 2) return False else: Logger.log("Lemma \"%s\" holds for I -> L" % lemma, 2) return True
def solve_safety_inc_zz(self, hts, prop, k): self._reset_assertions(self.solver) if TS.has_next(prop): Logger.error( "Invariant checking with next variables only supports FWD strategy" ) init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() initt = self.at_time(And(init, invar), 0) Logger.log("Add init at_0", 2) self._add_assertion(self.solver, initt) propt = self.at_ptime(And(Not(prop), invar), -1) Logger.log("Add property pat_%d" % 0, 2) self._add_assertion(self.solver, propt) t = 0 while (t < k + 1): self._push(self.solver) even = (t % 2) == 0 th = int(t / 2) if even: eq = And([ EqualsOrIff(self.at_time(v, th), self.at_ptime(v, th - 1)) for v in hts.vars ]) else: eq = And([ EqualsOrIff(self.at_time(v, th + 1), self.at_ptime(v, th - 1)) for v in hts.vars ]) Logger.log("Add equivalence time %d" % t, 2) self._add_assertion(self.solver, eq) if self._solve(self.solver): Logger.log("Counterexample found with k=%s" % (t), 1) model = self._get_model(self.solver) return (t, model) else: Logger.log("No counterexample found with k=%s" % (t), 1) Logger.msg(".", 0, not (Logger.level(1))) self._pop(self.solver) if even: trans_t = self.unroll(trans, invar, th + 1, th) else: trans_t = self.unroll(trans, invar, th, th + 1) self._add_assertion(self.solver, trans_t) t += 1 return (t - 1, None)
def Orr(in_, out): # INVAR: (in = 0) -> (out = 0) & (in != 0) -> (out = 1) vars_ = [in_, out] comment = "Orr (in, out) = (%s, %s)" % (tuple( [x.symbol_name() for x in vars_])) Logger.log(comment, 3) if (in_.symbol_type() == BOOL) and (out.symbol_type() == BOOL): invar = EqualsOrIff(in_, out) else: if out.symbol_type() == BOOL: out0 = Not(out) out1 = out else: out0 = EqualsOrIff(out, BV(0, 1)) out1 = EqualsOrIff(out, BV(1, 1)) true_res = Implies( EqualsOrIff(in_, BV(0, in_.symbol_type().width)), out0) false_res = Implies( Not(EqualsOrIff(in_, BV(0, in_.symbol_type().width))), out1) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def _get_param_assignments(self, model, time, parameters, monotonic=True): p_ass = [] fwd = False for p in parameters: p_time = model[TS.get_ptimed(p, 0)] if p.symbol_type() == BOOL: if monotonic: if p_time == TRUE(): p_ass.append(p) else: p_ass.append(p if p_time == TRUE() else Not(p)) else: p_ass.append(EqualsOrIff(p, p_time)) p_ass = And(p_ass) self.region = simplify(Or(self.region, p_ass)) if self.models is None: self.models = [] self.models.append((model, time)) Logger.msg("+", 0, not (Logger.level(1))) self.cs_count += 1 Logger.log( "Found assignment \"%s\"" % (p_ass.serialize(threshold=100)), 1) return (p_ass, False)
def _pop(self, solver): Logger.log("Pop solver \"%s\"" % solver.name, 2) if not self.config.skip_solving: solver.solver.pop() solver.smt2vars = solver.smt2vars_inc.pop() self._write_smt2_log(solver, "(pop 1)")
def _push(self, solver): Logger.log("Push solver \"%s\"" % solver.name, 2) if not self.config.skip_solving: solver.solver.push() solver.smt2vars_inc.append(solver.smt2vars) self._write_smt2_log(solver, "(push 1)")
def translate(hts, config, formulae=None): Logger.log("\nWriting system to \"%s\"" % (config.translate), 0) printer = HTSPrintersFactory.printer_by_name(config.printer) props = [] if formulae is not None: props = [(f.serialize(threshold=100), f, None) for f in formulae if f is not None] with open(config.translate, "w") as f: f.write(printer.print_hts(hts, props))
def Wrap(in_, out): # INVAR: (in = out) vars_ = [in_,out] comment = ("Wrap (in, out) = (%s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) invar = EqualsOrIff(in_, out) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def run_passes(self): Logger.log("Running CoreIR passes...", 1) print_level = 3 if not Logger.level(print_level): saved_stdout = suppress_output() self.context.run_passes(PASSES) if not Logger.level(print_level): restore_output(saved_stdout)
def check_overappr(Ri, R): self._reset_assertions(solver_proof) self._add_assertion(solver_proof, And(Ri, Not(R))) if not self._solve(solver_proof): Logger.log("Proof found with k=%s"%(t), 1) return TRUE() Logger.log("Extending initial states (%s)"%int_c, 1) return Or(R, Ri)
def Slice(in_, out, low, high): # INVAR: (extract low high in) = out high -= 1 vars_ = [in_,out, low, high] comment = "Mux (in, out, low, high) = (%s, %s, %s, %s)"%(tuple([str(x) for x in vars_])) Logger.log(comment, 3) invar = EqualsOrIff(BVExtract(in_, low, high), out) ts = TS(comment) ts.vars, ts.invar = set([in_, out]), invar return ts
def run_problems(problems_config: ProblemsManager): if sys.version_info[0] < 3: if config.devel: Logger.warning( "This software is not tested for Python 2, we recommend to use Python 3 instead" ) else: Logger.error( "This software is not tested for Python 2, please use Python 3 instead. To avoid this error run in developer mode" ) reset_env() # Named tuple representing all the general configuration options # (things that don't change between problems) general_config = problems_config.general_config Logger.verbosity = general_config.verbosity Logger.time = general_config.time psol = ProblemSolver() psol.solve_problems(problems_config) global_status = 0 traces = [] if len(problems_config.problems) > 0: Logger.log("\n*** SUMMARY ***", 0) else: if not general_config.translate: Logger.log("No problems to solve", 0) return 0 formulae = [] for pbm in problems_config.problems: (status, trace) = print_problem_result(pbm, problems_config) if status != 0: global_status = status traces += trace formulae.append(pbm.properties) if len(traces) > 0: Logger.log("\n*** TRACES ***\n", 0) for trace in traces: Logger.log("[%d]:\t%s" % (traces.index(trace) + 1, trace), 0) if general_config.translate: translate(problems_config.hts, general_config, formulae) if global_status != 0: Logger.log("", 0) Logger.warning("Verifications with unexpected result") return global_status
def check_step(): self._reset_assertions(self.solver) self._add_assertion(self.solver, self.at_time(And(trans, lemma), 0)) self._add_assertion(self.solver, self.at_time(Not(lemma), 1)) if self._solve(self.solver): Logger.log("Lemma \"%s\" failed for L & T -> L'"%lemma, 2) return False Logger.log("Lemma \"%s\" holds for L & T -> L'"%lemma, 2) return True
def check_init(): self._reset_assertions(self.solver) self._add_assertion(self.solver, self.at_time(And(init, Not(lemma)), 0), comment="Init check") res = self._solve(self.solver) if res: Logger.log("Lemma \"%s\" failed for I -> L"%lemma, 2) return False Logger.log("Lemma \"%s\" holds for I -> L"%lemma, 2) return True
def solve(self, hts, prop, k, lemmas=None): if lemmas is not None: (hts, res) = self.add_lemmas(hts, prop, lemmas) if res: Logger.log("Lemmas imply the property", 1) Logger.log("", 0, not (Logger.level(1))) return (0, True) hts.reset_formulae() return self.solve_inc(hts, prop, k)
def run_problems(problems_file, config, problems=None): if sys.version_info[0] < 3: if config.devel: Logger.warning( "This software is not tested for Python 2, we recommend to use Python 3 instead" ) else: Logger.error( "This software is not tested for Python 2, please use Python 3 instead. To avoid this error run in developer mode" ) reset_env() Logger.verbosity = config.verbosity Logger.time = config.time psol = ProblemSolver() if problems is None: problems = Problems() problems.load_problems(problems_file) psol.solve_problems(problems, config) global_status = 0 traces = [] if len(problems.problems) > 0: Logger.log("\n*** SUMMARY ***", 0) else: if not config.translate: Logger.log("No problems to solve", 0) return 0 formulae = [] for pbm in problems.problems: (status, trace) = print_problem_result(pbm, config, len(traces) + 1) if status != 0: global_status = status traces += trace formulae.append(pbm.formula) if len(traces) > 0: Logger.log("\n*** TRACES ***\n", 0) for trace in traces: Logger.log("[%d]:\t%s" % (traces.index(trace) + 1, trace), 0) if config.translate: translate(problems.get_hts(), config, formulae) if global_status != 0: Logger.log("", 0) Logger.warning("Verifications with unexpected result") return global_status
def Andr(in_, out): # INVAR: (in = 2**width - 1) -> (out = 1) & (in != 2**width - 1) -> (out = 0) vars_ = [in_, out] comment = "Andr (in, out) = (%s, %s)"%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) width = in_.symbol_type().width eq_all_ones = EqualsOrIff(in_, BV(2**width - 1,width)) true_res = Implies(eq_all_ones, EqualsOrIff(out, BV(1,1))) false_res = Implies(Not(eq_all_ones), EqualsOrIff(out, BV(0,1))) invar = And(true_res, false_res) ts = TS(comment) ts.vars, ts.invar = set(vars_), invar return ts
def parse_file(self, strfile, config, flags=None): if flags is None: Logger.error("Top module not provided") topmodule = flags[0] absstrfile = os.path.abspath(strfile) directory = "/".join(absstrfile.split("/")[:-1]) filename = absstrfile.split("/")[-1] if self.single_file: files = [absstrfile] else: if self.files_from_dir: files = [ "%s/%s" % (directory, f) for f in os.listdir(directory) if self._get_extension(f) in self.extensions ] else: files = [ "%s/%s" % (directory, f) for f in list( set(self._collect_dependencies(directory, filename))) ] files.append(absstrfile) command = "%s -p \"%s\"" % (CMD, "; ".join(COMMANDS)) command = command.format(FILES=" ".join(files), \ TARGET=topmodule, \ PASSES="; ".join(PASSES), \ BTORFILE=TMPFILE) Logger.log("Command: %s" % command, 2) print_level = 3 if not Logger.level(print_level): saved_stdout = suppress_output() retval = os.system(command) if not Logger.level(print_level): restore_output(saved_stdout) if retval != 0: Logger.error("Error in Verilog conversion") parser = BTOR2Parser() ret = parser.parse_file(TMPFILE, config) if not Logger.level(1): os.remove(TMPFILE) return ret
def solve_safety_fwd(self, hts, prop, k, k_min): init = hts.single_init() trans = hts.single_trans() invar = hts.single_invar() t = k_min while (t < k+1): self._reset_assertions(self.solver) formula = And(init, invar) formula = self.at_time(formula, 0) Logger.log("Add init and invar", 2) self._add_assertion(self.solver, formula) trans_t = self.unroll(trans, invar, t) self._add_assertion(self.solver, trans_t) propt = self.at_time(Not(prop), t) Logger.log("Add property time %d"%t, 2) self._add_assertion(self.solver, propt) if self._solve(self.solver): Logger.log("Counterexample found with k=%s"%(t), 1) model = self._get_model(self.solver) return (t, model) else: Logger.log("No counterexample found with k=%s"%(t), 1) Logger.msg(".", 0, not(Logger.level(1))) t += 1 return (t-1, None)
def Const(out, value): invar = TRUE() if value is not None: if out.symbol_type() == BOOL: const = TRUE() if value == 1 else FALSE() else: const = BV(value, out.symbol_type().width) invar = EqualsOrIff(out, const) comment = "Const (out, val) = (" + out.symbol_name() + ", " + str(value) + ")" Logger.log(comment, 3) ts = TS(comment) ts.vars, ts.invar = set([out]), invar return ts
def check_step(): self._reset_assertions(self.solver) self._add_assertion(self.solver, self.at_time(And(trans, lemma), 0)) self._add_assertion(self.solver, self.at_time(Not(lemma), 1)) if self._solve(self.solver): if Logger.level(2): Logger.log("Lemma \"%s\" failed for L & T -> L'" % lemma, 2) if Logger.level(3): (hr_trace, vcd_trace) = self.print_trace( hts, self._get_model(self.solver), 1, prefix=prefix, map_function=self.config.map_function) if hr_trace or vcd_trace: vcd_msg = "" if vcd_trace: vcd_msg = " and in \"%s\"" % (vcd_trace) Logger.log( "Counterexample stored in \"%s\"%s" % (hr_trace, vcd_msg), 2) else: Logger.log("", 2) return False else: Logger.log("Lemma \"%s\" holds for L & T -> L'" % lemma, 2) return True
def solve_safety(self, hts, prop, k, k_min=0, lemmas=None, processes=1): if lemmas is not None: (hts, res) = self.add_lemmas(hts, prop, lemmas) if res: Logger.log("Lemmas imply the property", 1) Logger.log("", 0, not(Logger.level(1))) return (0, True) hts.reset_formulae() if self.config.incremental: return self.solve_safety_inc(hts, prop, k, k_min, processes) return self.solve_safety_ninc(hts, prop, k, k_min)
def BopBool(op, in0, in1, out): # INVAR: (in0 <op> in1) = out vars_ = [in0,in1,out] comment = (op.__name__ + " (in0, in1, out) = (%s, %s, %s)")%(tuple([x.symbol_name() for x in vars_])) Logger.log(comment, 3) if out.symbol_type() == BOOL: bout = out else: bout = EqualsOrIff(out, BV(1, 1)) invar = Iff(op(in0,in1), bout) ts = TS(comment) ts.vars, ts.invar = get_free_variables(invar), invar return ts
def translate(hts, config, formulae=None): # TODO: Fix this for the formulae which are not pysmt nodes at this point # accessing the problem copy of it which is still a string Logger.log("\nWriting system to \"%s\""%(config.translate), 0) printer = HTSPrintersFactory.printer_by_name(config.printer) props = [] if formulae is not None: for f in formulae: if f is None: continue assert isinstance(f, FNode), "Expecting parsed properties" props.append(f) with open(config.translate, "w") as f: f.write(printer.print_hts(hts, props))