Esempio n. 1
0
def tryAndVerifyWithSplitterPreds(
        fun: Function,
        old_sound_invs: Set[AstExpr],
        boogie_invs: Set[AstExpr],
        splitterPreds: List[AstExpr],
        partialInvs: List[AstExpr],
        timeout: Optional[int] = None) -> TryAndVerifyResult:
    """ Wrapper around tryAndVerify_impl that adds implication with
        the splitter predicates to all candidate invariants. Returns
          ((p1_overfit, p2_overfit), (p1_nonindg, p2_nonind), sound, violations)

        Where

          p1_overfit, p2_ovefit are lists of pairs of overfittted invariants
                    and their respective counterexamples from passes 1 and 2
          p1_nonind, p2_nonind are lists of pairs of noninductive invariants
                    and their respective counterexamples from passes 1 and 2
          sound is a set of sound invariants
          violations is a list of any safety violations permitted by the sound
          invariants
    """
    initial_sound = old_sound_invs.union(partialInvs)
    boogieTypeEnv = fun.getTypeEnv()
    z3TypeEnv = boogieToZ3TypeEnv(boogieTypeEnv)

    # First lets find the invariants that are sound without implication
    p1_overfitted, p1_nonind, p1_sound, violations =\
      tryAndVerify_impl(fun, initial_sound, boogie_invs, timeout)
    p1_sound = \
        set([x for x in p1_sound \
               if not conservative_tautology(expr_to_z3(x, z3TypeEnv))])

    # Next lets add implication  to all unsound invariants from first pass
    # Also add manually specified partialInvs
    unsound: List[AstExpr] = [
        inv_ctr_pair[0] for inv_ctr_pair in p1_overfitted + p1_nonind
    ]
    candidate_precedents: List[AstExpr] = \
            [ ast_and(pSet) for pSet in nonempty(powerset(splitterPreds)) ]
    p2_invs: List[AstExpr] = [
        AstBinExpr(precc, "==>", inv) for precc in candidate_precedents
        for inv in unsound
    ]
    p2_invs += partialInvs

    p2_invs = \
        list(set([ x for x in p2_invs \
                if not conservative_tautology(expr_to_z3(x, z3TypeEnv)) ]))

    # And look for any new sound invariants
    p2_overfitted, p2_nonind, p2_sound, violations = \
            tryAndVerify_impl(fun, p1_sound.union(set(partialInvs)), \
                              p2_invs, timeout)
    sound = p1_sound.union(p2_sound)

    return ((p1_overfitted, p2_overfitted), \
            (p1_nonind, p2_nonind), \
            sound, \
            violations)
Esempio n. 2
0
def loadBoogieLvlSet(lvlSetFile: str) -> Tuple[str, Dict[str, BoogieTraceLvl]]:
    # Small helper funct to make sure we didn't
    # accidentally give two levels the same name
    def assertUniqueKeys(kvs):
        keys = [x[0] for x in kvs]
        assert (len(set(keys)) == len(keys))
        return dict(kvs)

    lvlSet = load(open(lvlSetFile, "r"), object_pairs_hook=assertUniqueKeys)
    lvlSetDir = dirname(abspath(realpath(lvlSetFile)))
    error("Loading level set " + lvlSet["name"] + " from " + lvlSetFile)
    lvls: Dict[str, BoogieTraceLvl] = OrderedDict()
    for t in lvlSet["levels"]:
        lvlName = t[0]
        lvlPath = t[1]

        for i in range(len(lvlPath)):
            lvlPath[i] = join(lvlSetDir, lvlPath[i])

        error("Loading level: ", lvlPath[0])
        lvl = loadBoogieFile(lvlPath[0])
        lvl["path"] = lvlPath

        if (len(t) > 2):
            splitterPreds = [parseExprAst(exp) for exp in t[2]]
            splitterPred = ast_and(splitterPreds)
            remainderInv = parseExprAst(t[3])

            lvl['data'][0] = [
                row for row in lvl['data'][0]
                if eval_quick(splitterPred,
                              {k: v
                               for k, v in zip(lvl['variables'], row)})
            ]

            if (len(lvl['data'][0]) == 0):
                error("SKIPPING : ", lvlName, " due to no filtered rows.")
                continue

            lvl['partialInv'] = remainderInv
            lvl['splitterPreds'] = splitterPreds

        lvls[lvlName] = lvl

    return (lvlSet["name"], lvls)
Esempio n. 3
0
def daikonToBoogieExpr(astn: dast.AstExpr) -> bast.AstExpr:
    if (isinstance(astn, dast.AstUnExpr)):
        cn = daikonToBoogieExpr(astn.expr)
        try:
            boogieOp = {
                '-': '-',
                '!': '!',
            }[astn.op]
            return bast.AstUnExpr(boogieOp, cn)
        except:
            raise Exception("Don't know how to translate " + str(astn))
    elif (isinstance(astn, dast.AstBinExpr)):
        ln, rn = list(map(daikonToBoogieExpr, [astn.lhs, astn.rhs]))

        # We can translate power operators to a constant power
        if (astn.op == "**" and isinstance(astn.rhs, dast.AstNumber)):
            res = ln
            for _ in range(astn.rhs.num - 1):
                res = bast.AstBinExpr(res, '*', ln)
            return res
        else:
            try:
                boogieOp = {
                    '&&': '&&',
                    '||': '||',
                    '==': '==',
                    '!=': '!=',
                    '<': '<',
                    '>': '>',
                    '<=': '<=',
                    '>=': '>=',
                    '+': '+',
                    '-': '-',
                    '*': '*',
                    '/': '/',
                    '%': 'mod',
                    '==>': '==>'
                }[astn.op]
                return bast.AstBinExpr(ln, boogieOp, rn)
            except:
                raise Exception("Don't know how to translate " + str(astn))
    elif (isinstance(astn, dast.AstId)):
        return bast.AstId(astn.name)
    elif (isinstance(astn, dast.AstNumber)):
        return bast.AstNumber(astn.num)
    elif (isinstance(astn, dast.AstTrue)):
        return bast.AstTrue()
    elif (isinstance(astn, dast.AstFalse)):
        return bast.AstFalse()
    elif (isinstance(astn, dast.AstIsOneOf)):
        cn = daikonToBoogieExpr(astn.expr)
        return bast.ast_or([
            bast.AstBinExpr(cn, "==", x)
            for x in [daikonToBoogieExpr(y) for y in astn.options]
        ])
    elif (isinstance(astn, dast.AstInRange)):
        cn = daikonToBoogieExpr(astn.expr)
        low = astn.lower.num
        hi = astn.upper.num
        return bast.ast_and([
            bast.AstBinExpr(bast.AstNumber(low), "<=", cn),
            bast.AstBinExpr(cn, "<=", bast.AstNumber(hi))
        ])
    elif (isinstance(astn, dast.AstIsBoolean)):
        cn = daikonToBoogieExpr(astn.expr)
        return bast.ast_or([
            bast.AstBinExpr(cn, "==", bast.AstNumber(0)),
            bast.AstBinExpr(cn, "==", bast.AstNumber(1))
        ])
    elif (isinstance(astn, dast.AstIsEven)):
        cn = daikonToBoogieExpr(astn.expr)
        return bast.AstBinExpr(bast.AstBinExpr(cn, "mod", bast.AstNumber(2)),
                               "==", bast.AstNumber(0))
    elif (isinstance(astn, dast.AstIsConstMod)):
        expr = daikonToBoogieExpr(astn.expr)
        remainder = daikonToBoogieExpr(astn.remainder)
        modulo = ccast(daikonToBoogieExpr(astn.modulo), bast.AstNumber)

        assert modulo.num != 0

        return bast.AstBinExpr(bast.AstBinExpr(expr, "mod", modulo), "==",
                               remainder)
    elif (isinstance(astn, dast.AstHasValues)):
        if (len(astn.values) > 300):
            raise Exception("Can't convert HasValues: Too many options: " +\
                            str(len(astn.values)))
        cn = daikonToBoogieExpr(astn.expr)
        values = list(map(daikonToBoogieExpr, astn.values))
        return bast.ast_or([bast.AstBinExpr(cn, "==", v) for v in values])
    else:
        raise Exception("Don't know how to translate " + str(astn))
Esempio n. 4
0
      print("Level, Num Invariants Found, Invariants Found, " +\
            "Num Sound Invariants, Sound Invariants, IsSolved")
    else:
      print("Level, Num Invariants Found, Invariants Found, " +\
            "Num Sound Invariants, Sound Invariants")

  for lvlName, lvl in lvls.items():
    (vs, header_vals) = (lvl["variables"], lvl["data"][0])
    fuzz_path: str = lvl["path"][0][:-len(".bpl")] + ".fuzz_traces"
    if (exists(fuzz_path)):
      for f in listdir(fuzz_path):
        t = eval(open(fuzz_path + "/" + f).read());
        t_loop_headers = [x for x in t if 'LoopHead' in x[0]]
        assert (len(set([x[0] for x in t_loop_headers])) == 1)
        if ("splitterPreds" in lvl):
          splitterPred = bast.ast_and(lvl["splitterPreds"])
          t_loop_headers = \
                  [row for row in t_loop_headers if eval_quick(splitterPred, row[1][0])]

        t_header_vals = [ [ row[1][0][v] for v in vs ] \
                          for row in t_loop_headers ]
        header_vals = header_vals + t_header_vals
    invs = runDaikon(vs, header_vals, args.no_suppression)

    binvs = [ ]
    for inv in invs:
      try:
        binvs.append(daikonToBoogieExpr(inv))
      except Exception:
        if (not args.csv_table):
          sys.stderr.write("Can't translate " + str(inv) + "\n");
Esempio n. 5
0
  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)")
    continue
  conj = bast.ast_and(preds);
  lvl = lvls[originalToSplitM[origName][0]]
  try:
    (overfit, nonind, sound, violations) = verify(lvl, [conj])