Exemple #1
0
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])
Exemple #2
0
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)
Exemple #3
0
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)
Exemple #4
0
def bmc_trace(prog: syntax.Program,
              trace: syntax.TraceDecl,
              s: Solver,
              sat_checker: Callable[[Solver, List[str]],
                                    Optional[logic.Trace]],
              log: bool = False) -> Optional[logic.Trace]:
    n_states = len(list(trace.transitions())) + 1
    if log:
        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

        return sat_checker(s, keys)
def bmc_trace(prog: syntax.Program,
              trace: syntax.TraceDecl,
              s: Solver,
              sat_checker: Callable[[Solver, int], Optional[logic.Trace]],
              log: bool = False) -> Optional[logic.Trace]:
    n_states = len(list(trace.transitions())) + 1
    if log:
        print('%s states' % (n_states, ))

    lator = s.get_translator(n_states)

    with s.new_frame():
        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.span,
                            'assert init is only allowed in the first state')
                    for init in prog.inits():
                        assert i == 0
                        s.add(lator.translate_expr(init.expr))
                else:
                    s.add(lator.translate_expr(New(c.expr, i)))
            else:
                te: syntax.TransitionExpr = c.transition
                if isinstance(te, syntax.AnyTransition):
                    logic.assert_any_transition(s,
                                                lator,
                                                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(
                            z3.Implies(
                                tid,
                                translate_transition_call(s, lator, i, call)))
                    s.add(z3.Or(*l))

                i += 1

        return sat_checker(s, n_states)
Exemple #6
0
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))
Exemple #7
0
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])
Exemple #8
0
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])