def check_automaton_init(s: Solver, a: AutomatonDecl) -> None: utils.logger.always_print('checking automaton init:') prog = syntax.the_program t = s.get_translator(KEY_ONE) init_decl = a.the_init() assert init_decl is not None # checked by resolver init_phase = prog.scope.get_phase(init_decl.phase) assert init_phase is not None # checked by resolver with s: for init in prog.inits(): s.add(t.translate_expr(init.expr)) for inv in init_phase.invs(): with s: s.add(z3.Not(t.translate_expr(inv.expr))) if inv.tok is not None: msg = ' on line %d' % inv.tok.lineno else: msg = '' utils.logger.always_print(' implies phase invariant%s... ' % msg, end='') sys.stdout.flush() logic.check_unsat([ (inv.tok, 'phase invariant%s may not hold in initial state' % msg) ], s, [KEY_ONE])
def theorem(s: Solver) -> None: utils.logger.always_print('checking theorems:') prog = syntax.the_program for th in prog.theorems(): if th.twostate: keys = [KEY_OLD, KEY_NEW] else: keys = [KEY_ONE] t = s.get_translator(*keys) if th.name is not None: msg = ' ' + th.name elif th.tok is not None: msg = ' on line %d' % th.tok.lineno else: msg = '' utils.logger.always_print(' theorem%s... ' % msg, end='') sys.stdout.flush() with s: s.add(z3.Not(t.translate_expr(th.expr))) logic.check_unsat([(th.tok, 'theorem%s may not hold' % msg)], s, keys)
def check_automaton_edge_covering(s: Solver, a: AutomatonDecl) -> None: utils.logger.always_print('checking automaton edge covering:') prog = syntax.the_program t = s.get_translator(KEY_NEW, KEY_OLD) for phase in a.phases(): utils.logger.always_print(' checking phase %s:' % phase.name) with s: for inv in phase.invs(): s.add(t.translate_expr(inv.expr, old=True)) for trans in prog.transitions(): if any(delta.transition == trans.name and delta.precond is None for delta in phase.transitions()): utils.logger.always_print(' transition %s is covered trivially.' % trans.name) continue utils.logger.always_print(' checking transition %s is covered... ' % trans.name, end='') with s: s.add(t.translate_transition(trans)) s.add(z3.And(*(z3.Not(t.translate_precond_of_transition(delta.precond, trans)) for delta in phase.transitions() if trans.name == delta.transition))) logic.check_unsat([(phase.tok, 'transition %s is not covered by this phase' % (trans.name, )), (trans.tok, 'this transition misses transitions from phase %s' % (phase.name,))], s, [KEY_OLD, KEY_NEW])
def theorem(s: Solver) -> None: utils.logger.always_print('checking theorems:') prog = syntax.the_program for th in prog.theorems(): if th.num_states == 2: num_states = 2 elif th.num_states == 1: num_states = 1 else: num_states = 0 t = s.get_translator(num_states) if th.name is not None: msg = ' ' + th.name elif th.span is not None: msg = ' on line %d' % th.span[0].lineno else: msg = '' utils.logger.always_print(' theorem%s... ' % msg, end='') sys.stdout.flush() with s.new_frame(): s.add(t.translate_expr(Not(th.expr))) logic.check_unsat([(th.span, 'theorem%s does not hold' % msg)], s, num_states)
def check_automaton_inductiveness(s: Solver, a: AutomatonDecl) -> None: utils.logger.always_print('checking automaton inductiveness:') prog = syntax.the_program t = s.get_translator(KEY_NEW, KEY_OLD) for phase in a.phases(): utils.logger.always_print(' checking phase %s:' % phase.name) with s: for inv in phase.invs(): s.add(t.translate_expr(inv.expr, old=True)) for delta in phase.transitions(): trans = prog.scope.get_definition(delta.transition) assert trans is not None precond = delta.precond target = prog.scope.get_phase( delta.target) if delta.target is not None else phase assert target is not None trans_pretty = '(%s, %s)' % (trans.name, str(precond) if (precond is not None) else 'true') utils.logger.always_print(' checking transition: %s' % trans_pretty) with s: s.add(t.translate_transition(trans, precond=precond)) for inv in target.invs(): with s: s.add(z3.Not(t.translate_expr(inv.expr))) if inv.tok is not None: msg = ' on line %d' % inv.tok.lineno else: msg = '' utils.logger.always_print( ' preserves invariant%s... ' % msg, end='') sys.stdout.flush() logic.check_unsat([ (inv.tok, 'invariant%s may not be preserved by transition %s in phase %s' % (msg, trans_pretty, phase.name)), (delta.tok, 'this transition may not preserve invariant%s' % (msg, )) ], s, [KEY_OLD, KEY_NEW])
def trace(s: Solver) -> None: # sandbox(s) prog = syntax.the_program traces = list(prog.traces()) if traces: utils.logger.always_print('finding traces:') else: utils.logger.always_print('no traces found in file') return for trace in traces: res = bmc_trace(prog, trace, s, lambda s, n: logic.check_unsat([], s, n), log=True) if (res is not None) != trace.sat: def bool_to_sat(b: bool) -> str: return 'sat' if b else 'unsat' utils.print_error( trace.span, 'trace declared %s but was %s!' % (bool_to_sat(trace.sat), bool_to_sat(res is not None))) else: utils.logger.always_print( f'\nchecked {len(traces)} traces and found {utils.error_count} errors' )
def trace(s: Solver) -> None: prog = syntax.the_program if len(list(prog.traces())) > 0: utils.logger.always_print('finding traces:') for trace in prog.traces(): n_states = len(list(trace.transitions())) + 1 print('%s states' % (n_states,)) keys = ['state%2d' % i for i in range(n_states)] for k in keys: s.get_translator(k) # initialize all the keys before pushing a solver stack frame with s: lator = s.get_translator(keys[0]) if len(trace.components) > 0 and not isinstance(trace.components[0], syntax.AssertDecl): for init in prog.inits(): s.add(lator.translate_expr(init.expr)) i = 0 for c in trace.components: if isinstance(c, syntax.AssertDecl): if c.expr is None: if i != 0: utils.print_error_and_exit(c.tok, 'assert init is only allowed in the first state') for init in prog.inits(): s.add(s.get_translator(keys[i]).translate_expr(init.expr)) else: s.add(s.get_translator(keys[i]).translate_expr(c.expr)) else: te: syntax.TransitionExpr = c.transition if isinstance(te, syntax.AnyTransition): logic.assert_any_transition(s, str(i), keys[i + 1], keys[i], allow_stutter=True) else: l = [] for call in te.calls: tid = z3.Bool(logic.get_transition_indicator(str(i), call.target)) l.append(tid) s.add(tid == translate_transition_call(s, keys[i + 1], keys[i], call)) s.add(z3.Or(*l)) i += 1 res = logic.check_unsat([], s, keys) if (res == z3.sat) != trace.sat: utils.print_error(trace.tok, 'trace declared %s but was %s!' % ('sat' if trace.sat else 'unsat', res))
def trace(s: Solver) -> None: # sandbox(s) prog = syntax.the_program if len(list(prog.traces())) > 0: utils.logger.always_print('finding traces:') for trace in prog.traces(): res = bmc_trace(prog, trace, s, lambda s, keys: logic.check_unsat([], s, keys), log=True) if (res is not None) != trace.sat: utils.print_error( trace.tok, 'trace declared %s but was %s!' % ('sat' if trace.sat else 'unsat', res))