Ejemplo n.º 1
0
def loadBoogieFile(fname: str) -> BoogieTraceLvl:
    """ Load a boogie file, asserting it contains a single function with a single loop.
    """
    fun: Function = unique(list(Function.load(fname)))
    hdr: BB = unique(fun.loopHeaders())

    # The variables to trace are all live variables at the loop header
    vs = list(livevars(fun)[(hdr, 0)])

    # Make sure variable names are different modulo case
    assert len(vs) == len(set([var.lower() for var in vs]))

    # See if there is a .trace or a .hint file
    hint = None
    header_vals = None
    terminates = False
    try:
        (vs, header_vals) = readTrace(fname[:-4] + '.trace', fun.getTypeEnv())
        hint = load(open(fname[:-4] + '.hint'))
    except Exception:  #TODO (Dimo) IOError here instead?
        pass

    assert (header_vals is not None)
    return {
        'variables': vs,
        'data': [[[row[v] for v in vs] for row in header_vals], [], []],
        'hint': hint,
        'program': fun,
        'loop': hdr
    }
Ejemplo n.º 2
0
def findLoopHeaderLabel(dotFile):
    g = unique(graph_from_dot_file(dotFile))
    nodes = g.get_nodes()
    shapeList = [(n.get_shape(), n.get_label()) for n in nodes]
    doubleCircles = [t for t in shapeList if t[0] == '"doublecircle"']
    # The loop header should be the unique node with a double circle shape
    # Its label will be a string of the form '"N[0-9]*\\n[0-9]"'. We care
    # just about the first [0-9]* part.
    return unique(doubleCircles)[1].split("\\n")[0][2:]
Ejemplo n.º 3
0
def tryAndVerify_impl(
    fun: Function,
    oldSoundInvs: Iterable[AstExpr],
    invs: Iterable[AstExpr],
    timeout: Optional[int] = None
) -> Tuple[List[Tuple[AstExpr, Violation]], List[Tuple[AstExpr, Violation]],
           Set[AstExpr], List[Violation]]:
    """ Wrapper around checkInvNetwork for the case of a function
        with a single loop and no pre- post- conditions.
        Returns a tuple (overfitted, nonind, sound, violations) where
          overfitted, nonind are each a list of tuples (inv, Violation)
          sound is a set of sound invariants
          violations is a (potentially empty) list of safety Violations
            for the sound invariants.
    """
    loopHdr = unique(fun.loopHeaders()).label
    cps: InvNetwork = {loopHdr: set(oldSoundInvs).union(set(invs))}

    (overfitted, nonind, sound, violations) =\
      filterCandidateInvariants(fun, AstTrue(), AstTrue(), cps, timeout)

    overfittedL = list(overfitted[loopHdr])
    nonindInvsL = list(nonind[loopHdr])
    soundL = sound[loopHdr]

    return overfittedL, nonindInvsL, soundL, violations
Ejemplo n.º 4
0
def loop_exit_bb(body_paths, bbs):
    loop_header_succ = set(bbs[body_paths[0][0]].successors)
    bbs_in_loop = set([p[1] for p in body_paths])
    assert (len(loop_header_succ) == len(bbs_in_loop) + 1
            )  # Singular exit node
    # TODO: Check that no other paths exit the loop (sanity)
    return unique(loop_header_succ.difference(bbs_in_loop))
Ejemplo n.º 5
0
def tryAndVerifyLvl(
        lvl: BoogieTraceLvl,
        userInvs: Iterable[AstExpr],
        otherInvs: Set[AstExpr],
        timeout: Optional[int] = None, \
  useSplitters: bool = True,
        addSPs: bool = True,
        generalizeUserInvs: bool = False
) -> TryAndVerifyResult:
    """ Try and verify a given Lvl.

          lvl - level to verify
          userInvs - invariant candidate from the user
          otherInvs - invariant candidates from other sources (e.g. previous
                      users).
                      Note: We will keep userInvs and otherInvs separate in the
                      results.
          timeout - if specified, the z3 timeout for each query
          useSplitters - if the level supports splitter predicates, whether to
                         use them or not.
          addSPs - if true, try to propagte SP through the loop and add the
                   results as invariants. For example if before the loop we 
                   have "assert n>0;" and n is not modified in the loop, we
                   can determine that"n>0" holds through the loop and add
                   that to our cnadidate invariants.
          generalizeUserInvs - if true, for any invariant I involving a
                   constant C, where one of the variables V shown to the user
                   was always equal to C in the traces, try substituting C with V.
                   For example if in the level always n=4, and the user
                   entered i<=4, the generalizaition would also try i<=n.
    """
    fun: Function = lvl['program']
    loopHdr: BB = unique(fun.loopHeaders())
    partialInvs: List[AstExpr] = [ lvl['partialInv'] ] \
            if ('partialInv' in lvl) and useSplitters else []
    splitterPreds: List[AstExpr] = lvl['splitterPreds'] \
            if ('splitterPreds' in lvl) and useSplitters else [ ]
    if (generalizeUserInvs):
        replMaps: List[ReplMap_T] = generalizeConstTraceVars(lvl)
    else:
        replMaps = []

    # Push any SPs that are syntactically unmodified
    if (addSPs):
        sps = propagateUnmodifiedPreds(fun)[(loopHdr, 0)]
        if (sps is not None):
            otherInvs = otherInvs.union(set(sps))

    return tryAndVerify(fun, splitterPreds, partialInvs, \
                        userInvs, otherInvs, replMaps, timeout)
Ejemplo n.º 6
0
    def load(fname: str, lvlId: str) -> "FlowgameLevel":
        fun: Function = unique(list(Function.load(fname)))
        try:
            (vs, header_vals) = readTrace(fname[:-4] + '.trace',
                                          fun.getTypeEnv())
        except:
            (vs, header_vals) = (None, None)

        if (header_vals is not None):
            assert len(
                fun.loopHeaders()
            ) == 1, "TODO: Not implemented trace format for multi-loop functions"

        return FlowgameLevel(lvlId, fun, header_vals, fname)
Ejemplo n.º 7
0
def getEnsamble(
    fun: Function,
    exec_limit: int,
    tryFind: int = 100,
    vargens: Optional[Iterator[Store]] = None
) -> Iterator[Tuple[List[Store], Set[str]]]:
    loopHdr: BB = unique(fun.loopHeaders())
    traceVs: List[str] = list(livevars(fun)[(loopHdr, 0)])
    # TODO: Actually check the types
    randF: RandF = lambda state, varName: randint(0, 100)
    choiceF: ChoiceF = lambda states: [choice(list(states))]

    if vargens is None:

        def candidatef() -> Iterator[Store]:
            # TODO: Make this typesafe w.r.t. Function type env
            while True:
                yield {v: randint(0, 30) for v in traceVs}

        vargens = candidatef()

    tried: Set[Tuple[int, ...]] = set()
    #TODO: Not a smart way for generating random start values. Fix.
    s = 0
    print("Trying to find ", tryFind, " traces of length up to ", exec_limit)
    while s < tryFind:
        candidate = next(vargens)
        hashable = tuple(ccast(candidate[v], int) for v in traceVs)
        if hashable in tried:
            continue
        tried.add(hashable)

        found = False
        (active_traces,
         done_traces) = trace_n_from_start(fun, candidate, exec_limit, randF,
                                           choiceF)
        for trace in active_traces + done_traces:
            vals: List[Store] = [
                store for ((bb, idx), store, status) in trace
                if bb == loopHdr and idx == 0
            ]
            bbhit: Set[str] = set(bb.label for ((bb, idx), _, _) in trace)
            yield (vals, bbhit)
            found = True
            s += 1
            if (s >= tryFind):
                break

        if (not found):
            s += 1
Ejemplo n.º 8
0
def loopInvSafetyCtrex(
        fun: Function, \
  invs: Iterable[AstExpr], \
  timeout: Optional[int] = None
) -> List[Store]:
    """ Given a candidate loop invariant inv find 'safety'
      counterexamples.  I.e. find counterexamples to "inv ==> post" or "inv ==>
      assert".  Returns a potentially empty set of environments (dicts) that
      the invariant should satisfy.
  """
    loopHdr = unique(fun.loopHeaders()).label
    cps: InvNetwork = {loopHdr: set(invs)}
    violations = checkInvNetwork(fun, AstTrue(), AstTrue(), cps, timeout)

    return ([
        x.endEnv() for x in violations if x.isSafety() and  # Safety fail
        x.startBB() == loopHdr
    ])  # From Inv
Ejemplo n.º 9
0
def loopInvOverfittedCtrex(
        fun: Function, \
  invs: Iterable[AstExpr], \
  timeout: Optional[int] = None
) -> List[Store]:
    """ Given a candidate loop invariant inv find 'overfittedness'
      counterexamples.  I.e. find counterexamples to "precondition ==> inv".
      Returns a potentially empty set of environments (dicts) that the invariant
      should satisfy.
  """
    loopHdr = unique(fun.loopHeaders()).label
    cps: InvNetwork = {loopHdr: set(invs)}
    violations = checkInvNetwork(fun, AstTrue(), AstTrue(), cps, timeout)
    entryBB = fun.entry().label

    return ([
        x.endEnv() for x in violations
        if x.isInductive() and  # Implication fail
        x.startBB() == entryBB and  # From entry
        x.endBB() == loopHdr
    ])  # To loop inv
Ejemplo n.º 10
0
def loadBoogieFile(fname, multiround):
    bbs = get_bbs(fname)
    ensureSingleExit(bbs)
    loop = unique(loops(bbs),
                  "Cannot handle program with multiple loops:" + fname)

    # The variables to trace are all live variables at the loop header
    vs = list(livevars(bbs)[loop.loop_paths[0][0]])

    # Make sure variable names are different modulo case
    assert len(vs) == len(set([var.lower() for var in vs]))

    # See if there is a .trace or a .hint file
    hint = None
    header_vals = None
    terminates = False
    try:
        (vs, header_vals) = readTrace(fname[:-4] + '.trace')
        hint = load(open(fname[:-4] + '.hint'))
    except Exception:  #TODO (Dimo) IOError here instead?
        pass

    if (not header_vals):
        header_vals, terminates = _tryUnroll(loop, bbs, 0, 4, None, None)
        # Assume we have no tests with dead loops
        assert (header_vals != [])
        invTemplates = ["_sv_x<_sv_y", "_sv_x<=_sv_y", "_sv_x==_sc_c", \
                        "_sv_x==_sv_y", "_sv_x==0", "_sv_x<0"]
        invTemplates = [parseExprAst(inv) for inv in invTemplates]

        new_header_vals, new_terminates = \
                getInitialData(loop, bbs, 4, invTemplates, [ "_sv_x", "_sv_y" ])

        if (new_header_vals != None):
            header_vals = new_header_vals
            terminates = new_terminates
            writeTrace(fname[:-4] + ".trace", new_header_vals)

    return {
        'variables':
        vs,
        'data': [[[str(row[v]) for v in vs] for row in header_vals], [], []],
        'exploration_state':
        [([str(header_vals[0][v]) for v in vs], len(header_vals), terminates)],
        'hint':
        hint,
        'goal': {
            "verify": True
        },
        'support_pos_ex':
        True,
        'support_neg_ex':
        True,
        'support_ind_ex':
        True,
        'multiround':
        multiround,
        'program':
        bbs,
        'loop':
        loop
    }
Ejemplo n.º 11
0
        print "Print split lvl ", lvl_name, "is missing splitterPreds"

    if (endsWithNumP.match(lvl_name) and not "partialInv" in lvl):
        print "Print split lvl ", lvl_name, "is missing partialInv"

    if (endsWithNumP.match(lvl_name)):
        origName = justEnd.split(lvl_name)[0]
        originalToSplitM[origName] = originalToSplitM.get(origName, []) +\
                                     [ lvl_name ]
        splitToOriginal[lvl_name] = origName

print "Checking splitter predicates non-ovrelapping"
for origName in originalToSplitM.keys():
    # For now we assume each split level has a single splitterPred
    preds = [
        unique(lvls[x]["splitterPreds"]) for x in originalToSplitM[origName]
    ]

    for i in xrange(0, len(preds)):
        for j in xrange(i + 1, len(preds)):
            if (not unsatisfiable(
                    expr_to_z3(bast.ast_and([preds[i], preds[j]]),
                               AllIntTypeEnv()))):
                print "Predicates ", preds[i], "and", preds[j], "from split of ", \
                       origName, "are not independent"

print "Checking conjunction of partial predicates is a solution"
for origName in originalToSplitM.keys():
    # For now we assume each split level has a single splitterPred
    preds = [lvls[x]["partialInv"] for x in originalToSplitM[origName]]
    if (len(preds) == 1):
Ejemplo n.º 12
0
def run_lvl(lvl_name: str) -> None:
    print(("== " + lvl_name))

    lvl = lvls[lvl_name]
    spliter_pred = find_split_pred(find_original_boogie_file(lvl))
    print(("Spliter pred: " + str(spliter_pred)))

    if spliter_pred:
        print("Skiping programs with spliter preds.")
        return

    # vs = lvl["variables"]
    # vs.sort()

    fun: Function = lvl["program"]
    loopHdr: BB = unique(fun.loopHeaders())
    liveVars = list(livevars(fun)[(loopHdr, 0)])
    liveVars.sort()

    allVars = list(fun.getTypeEnv().keys())
    print(("live vars: " + str(liveVars)))

    store_gen = varproduct({v: gen(v, allVars) for v in allVars})

    target_len = 7

    tried: Set[Tuple[int, ...]] = set()
    #filt_f = lambda bbs, states:  [choice(states)]
    filt_f = lambda states: states
    rand_f = lambda state, Id: randint(-1000, 1000)

    done = False
    while not done:
        try:
            starting_store = next(store_gen)
        except StopIteration:
            print("Exhausted candidate stores (not more in iteration)")
            break
        hashable = tuple(starting_store[v] for v in liveVars)
        if hashable in tried:
            print("Exhausted candidate stores (getting duplicate stores)")
            break
        tried.add(hashable)
        print(("Evaluating in starting store: " + str(starting_store)))
        (active, inactive) = trace_n_from_start(fun, starting_store,
                                                args.limit, rand_f, filt_f)
        traces = active + [t for t in inactive if finished(t[-1])]
        traces = [[st.store for st in tr if st.pc.bb == loopHdr]
                  for tr in traces]
        for trace in traces:
            print(("Found trace of length " + str(len(trace)) + ": "))
            print((trace_to_str(trace)))
            if spliter_pred:
                (t0, t1) = split_trace(trace, spliter_pred)
                if len(t0) >= target_len and len(t1) >= target_len:
                    print(("Found split traces with lengths >= " +
                           str(target_len) + ". Writing first " +
                           str(target_len) + " elmts."))
                    write_trace_col_format(lvl, trace[0:target_len])
                    write_trace_col_format(lvl, t0[0:target_len], "0")
                    write_trace_col_format(lvl, t1[0:target_len], "1")
                    done = True
                    break
            else:
                if len(trace) >= target_len:
                    print(("Found trace with length >= " + str(target_len) +
                           ". Writing first " + str(target_len) + " elmts."))
                    write_trace_col_format(lvl, trace[0:target_len])
                    done = True
                    break

    print_comparison(lvl_name)
Ejemplo n.º 13
0
  if (endsWithNumP.match(lvl_name) and not "splitterPreds" in lvl):
    print("Print split lvl ", lvl_name, "is missing splitterPreds")

  if (endsWithNumP.match(lvl_name) and not "partialInv" in lvl):
    print("Print split lvl ", lvl_name, "is missing partialInv")

  if (endsWithNumP.match(lvl_name)):
    origName = justEnd.split(lvl_name)[0]
    originalToSplitM[origName] = originalToSplitM.get(origName, []) +\
                                 [ lvl_name ]
    splitToOriginal[lvl_name] = origName

print("Checking splitter predicates non-ovrelapping")
for origName in list(originalToSplitM.keys()):
  # For now we assume each split level has a single splitterPred
  preds = [ unique(lvls[x]["splitterPreds"])
          for x in originalToSplitM[origName] ]

  for i in range(0, len(preds)):
    for j in range(i+1, len(preds)):
      if (not unsatisfiable(expr_to_z3(bast.ast_and([preds[i], preds[j]]),
                            AllIntTypeEnv()))):
        print("Predicates ", preds[i], "and", preds[j], "from split of ", \
               origName, "are not independent")

print("Checking conjunction of partial predicates is a solution")
for origName in list(originalToSplitM.keys()):
  # For now we assume each split level has a single splitterPred
  preds = [ lvls[x]["partialInv"] for x in originalToSplitM[origName] ]
  if (len(preds) == 1):
    print("Skipping ", origName, "- only 1 split level (no other side of split)")