示例#1
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)
示例#2
0
def really_verified_by_play(lvl, assignment, worker, exp, play, timeout):
    invs = set([
        parseExprAst(x.payl()['canonical']) for x in play
        if x.type == 'FoundInvariant'
    ])
    (overfitted,
     _), (nonind,
          _), sound, violations = tryAndVerifyLvl(lvl, invs, set(), timeout)
    assert type(violations) == list
    return len(violations) == 0
示例#3
0
def loadLvl(levelSet: str, lvlId: str, mturkId: MturkIdT, individualMode:bool = False) -> BoogieTraceLvl:
    """ Load a given level. """
    if (levelSet not in traces):
        raise Exception("Unkonwn level set " + levelSet)

    if (lvlId not in traces[levelSet]):
        raise Exception("Unkonwn trace " + lvlId + " in levels " + levelSet)

    lvl = traces[levelSet][lvlId]
    fun: Function = lvl['program']
    lvl = {
            'lvlSet': levelSet,
            'id': lvlId,
            'variables': lvl['variables'],
            'data': lvl['data'],
            'typeEnv': typeEnvToJson(fun.getTypeEnv()),
            'hint': lvl['hint'],
            'goal': 'verify'
    }

    if args.colSwap:
      nCols = len(lvl["variables"])
      if nCols not in columnSwaps:
        raise Exception("No column swap for %d columns" % nCols)

      nSwaps = (nCols + 1) // 2 # swaps are 0 to nSwaps - 1 inclusive

      session = sessionF()

      colSwaps: List[int] = [0] * nSwaps
      if individualMode:
        workerId = mturkId[0]
        allInvs(session, enames=[args.ename], lvlsets=[curLevelSetName],
          lvls=[lvlId], workers=[workerId], colSwaps=colSwaps)
      else:
        allInvs(session, enames=[args.ename], lvlsets=[curLevelSetName],
          lvls=[lvlId], colSwaps=colSwaps)
      sortKeys = colSwaps

      nSwap = sorted(zip(sortKeys, list(range(nSwaps))), key=lambda x: x[0])[0][1]
      lvl["colSwap"] = nSwap
      lvl["variables"] = swapColumns(lvl["variables"], nSwap)
      lvl["data"] = [[swapColumns(row, nSwap) for row in rows]
        for rows in lvl["data"]]

    lvl["startingInvs"] = []
    if args.replay:
      # Only show players their own invariants, even if individual mode is off
      invs = allInvs(session, enames=[args.ename], lvlsets=[curLevelSetName],
        lvls=[lvlId], workers=[workerId])

      lvl["startingInvs"] = [(inv[0], boogieToEsprima(parseExprAst(inv[1])))
        for inv in invs]

    return lvl
示例#4
0
    if (endsWithNumP.match(lvl_name)):
        origName = justEnd.split(lvl_name)[0]
        originalToSplitM[origName] = \
                originalToSplitM.get(origName, []) + [ lvl_name ]
        splitToOriginal[lvl_name] = origName


print("Level, #Splits, Solved, #FoundInvariants, #Added Implications, " +\
      "#Added SPs, #Sound, #Overfit, #Nonind")
for origName in originalToSplitM:
    found = reduce(
        lambda x, y: x.union(y),
        [lvlStats[z]["invariantsFound"] for z in originalToSplitM[origName]],
        set())
    implied = [ set([ bast.AstBinExpr(precc, "==>", bast.parseExprAst(inv[1]))
                      for inv in lvlStats[z]["invariantsFound"] \
                          for precc in lvls[z]["splitterPreds"] ])
                for z in originalToSplitM[origName] ]
    implied = reduce(lambda x, y: x.union(y), implied, set())
    found = set([bast.parseExprAst(x[1]) for x in found])
    nraw = len(found)
    nimplied = len(implied)
    lvl = lvls[originalToSplitM[origName][0]]
    bbs = lvl["program"]
    loop = lvl["loop"]
    loop_header = loop.loop_paths[0][0]
    sps = propagate_sp(bbs)[loop_header]
    nsps = len(sps)
    invs = found.union(sps).union(implied)
示例#5
0
p.add_argument('--lvlid', type=str, \
        default = 'desugared-boogie-benchmarks', \
        help='Lvl-id in level set to try and verify"')
p.add_argument('invs', type=str, nargs="+", help="Invariants to try")
p.add_argument('--timeout', type=int, \
        help="Optional z3 timeout", default=None)

args = p.parse_args();

_, lvls = loadBoogieLvlSet(args.lvlset)
lvl = lvls[args.lvlid]
boogie_invs = set([])

for inv in args.invs:
  try:
    bInv = parseExprAst(inv);
    boogie_invs.add(bInv);
  except Exception:
    error("Failed parsing invariant " + inv);
    exit(-1);

((overfitted, overfitted_p2), (nonind, nonind_p2), sound, violations) =\
  tryAndVerifyLvl(lvl, boogie_invs, set(), args.timeout)

overfitted = set(overfitted).union(overfitted_p2)
nonind = set(nonind).union(nonind_p2)

print("Overfitted: ", overfitted)
print("Nonind: ", nonind)
print("Sound: ", sound)
print("Violations: ", violations)
示例#6
0
def tryAndVerify(
  levelSet: str,
  levelId: str,
  invs: List[EsprimaNode],
  mturkId: MturkIdT,
  individualMode: bool
  ) -> Tuple[List[Tuple[EsprimaNode, StoreArr]],\
             List[Tuple[EsprimaNode, Tuple[StoreArr, StoreArr]]],\
             List[EsprimaNode],\
             List[StoreArr],
             List[StoreArr]]:
    """ 
        Given a level (levelSet, levelId) and a set of invaraints invs do:
        1) Find all invariants OldI that were not DEFINITELY false from the
           last time we tried to verify this level (getLastVerResult)

        2) Try and verify the level using S = OldI + invs. This is done by
           calling tryAndVerifyLvl. For more on that see comment in
           tryAndVerifyLvl

        3) Return object containing:
           overfitted - all invariants in invs not implied by precondition
           nonind - all invariants in invs that are not inductive
           sound - all invariants in invs that are sound
           post_ctrex - any safety counterexamples to the "sound" invariants.
              If this set is empty, then the level is verified.
           direct_ctrex - any safety counterexamples to ALL of the passed in
              invs (not just the sound ones). This is used by the 'rounds' game
              mode to generate red rows for the next level.
    """ 
    s = sessionF()
    if (levelSet not in traces):
        raise Exception("Unkonwn level set " + str(levelSet))

    if (levelId not in traces[levelSet]):
        raise Exception("Unkonwn trace " + str(levelId) + \
                        " in levels " + str(levelSet))

    if (len(invs) == 0):
        raise Exception("No invariants given")

    lvl: BoogieTraceLvl = traces[levelSet][levelId]

    assert 'program' in lvl
    workerId, _, _ = mturkId
    userInvs = set([ esprimaToBoogie(x, {}) for x in invs ])
    otherInvs: Set[AstExpr] = set([])
    lastVer: Optional[Dict[str, Any]] = None
    #lastVer = getLastVerResult(levelSet, levelId, s,
    #  workerId=(workerId if individualMode else None))

    if (lastVer):
      otherInvs = otherInvs.union([parseExprAst(x) for x in lastVer["sound"]])
      otherInvs = otherInvs.union([parseExprAst(x) for x in lastVer["nonind"]])

    ((overfitted, _), (nonind, _), sound, violations) = \
      tryAndVerifyLvl(lvl, userInvs, otherInvs, 1) # making all calls 1 sec args.timeout)

    # See if the level is solved
    solved = len(violations) == 0
    fix = lambda x: _from_dict(lvl['variables'], x, 0)
    # TODO: Why is this shit needed?
    if (not solved):
        fun: Function = lvl["program"]
        direct_ctrexs = loopInvSafetyCtrex(fun, otherInvs.union(userInvs),\
                                            1) # making all calls 1 sec args.timeout)
    else:
        direct_ctrexs = []

    # Convert all invariants from Boogie to esprima expressions, and
    # counterexamples to arrays
    # from dictionaries
    overfittedEsp = [ (boogieToEsprima(inv), fix(v.endEnv()))
      for (inv, v) in overfitted ]
    nonindEsp = [ (boogieToEsprima(inv), (fix(v.startEnv()), fix(v.endEnv())))
      for (inv, v) in nonind ]
    soundEsp = [ boogieToEsprima(inv) for inv in sound ]
    safetyCtrexsArr = [ fix(v.startEnv()) for v in violations ]
    directCtrexsArr = [ fix(v) for v in direct_ctrexs ]
    res = (overfittedEsp, nonindEsp, soundEsp, safetyCtrexsArr, directCtrexsArr)

    # Log verification result in Db (storing invariants as boogie strings)
    payl = {
      "lvlset": levelSet,
      "lvlid": levelId,
      "overfitted":nodups([str(inv) for (inv, _) in overfitted]),
      "nonind":nodups([str(inv) for (inv,_) in nonind]),
      "sound":nodups([str(inv) for inv in sound]),
      "post_ctrex":safetyCtrexsArr,
      "direct_ctrex": directCtrexsArr
    }
    addEvent("verifier", "VerifyAttempt", time(), args.ename, \
             "localhost", payl, s, mturkId)

    return res
示例#7
0
def processLevel(args,
                 lvl,
                 lvls=None,
                 lvlName=None,
                 additionalInvs=[],
                 storeArgs=None,
                 worker=None,
                 assignment=None):
    workers = args.workers if worker is None else [worker]
    assignments = None if assignment is None else [assignment]

    sessionF = open_db(args.db)
    s = sessionF()

    actualEnames = set()
    actualLvls = set()
    actualLvlsets = set()
    actualWorkers = set()
    actualAssignments = set()
    dbInvs = allInvs(s,
                     enames=args.enames,
                     lvls=lvls,
                     lvlsets=args.lvlsets,
                     workers=workers,
                     assignments=assignments,
                     enameSet=actualEnames,
                     lvlSet=actualLvls,
                     lvlsetSet=actualLvlsets,
                     workerSet=actualWorkers,
                     assignmentSet=actualAssignments)

    invs = set(parseExprAst(inv[1]) for inv in dbInvs)
    invs.update(additionalInvs)

    if lvlName is not None:
        print("_" * 40)
        print("RESULTS FOR LEVEL", lvlName)
        print()
    print("ENAMES:", ", ".join(actualEnames))
    print("LVLS:", ", ".join(actualLvls))
    print("LVLSETS:", ", ".join(actualLvlsets))
    if len(actualWorkers) < 6:
        print("WORKERS:", ", ".join(actualWorkers))
    else:
        print("UNIQUE WORKERS:", len(actualWorkers))
    if len(actualAssignments) < 3:
        print("ASSIGNMENTS:", ", ".join(actualAssignments))
    else:
        print("UNIQUE ASSIGNMENTS:", len(actualAssignments))
    if len(additionalInvs) < 6:
        print("ADDITIONAL INVARIANTS:",
              ", ".join(str(x) for x in additionalInvs))
    else:
        print("ADDITIONAL INVARIANTS:", len(additionalInvs))
    if len(invs) < 6:
        print("UNIQUE INVARIANTS:", ", ".join(map(str, invs)))
    else:
        print("UNIQUE INVARIANTS:", len(invs))
    print()

    payload = {
        "enames": list(actualEnames),
        "lvls": list(actualLvls),
        "lvlsets": list(actualLvlsets),
        "workers": list(actualWorkers),
        "assignments": list(actualAssignments)
    }

    overfittedSet = set()
    nonindSet = set()
    soundSet = set()
    proved = verify(lvl,
                    invs,
                    timeout=args.timeout,
                    overfittedSet=overfittedSet,
                    nonindSet=nonindSet,
                    soundSet=soundSet)
    payload["overfitted"] = list(str(s) for s in overfittedSet)
    payload["nonind"] = list(str(s) for s in nonindSet)
    payload["sound"] = list(str(s) for s in soundSet)

    if storeArgs is not None:
        config, lvlset, now = storeArgs
        storeVerify(s, config, lvlset, lvlName, args.timeout, now, proved,
                    payload)
示例#8
0
        print("Either --bpl or --lvlset must be specified")
        exit(1)

    additionalInvs = {}
    if args.additionalInvs:
        with open(args.additionalInvs) as f:
            r = csv.reader(f, delimiter=",")
            for row in r:
                if not row:
                    continue
                invs = []
                for invstr in invlist.split(";"):
                    if not len(invstr.strip()):
                        continue
                    try:
                        inv = parseExprAst(invstr)
                        if tautology(expr_to_z3(inv, AllIntTypeEnv())):
                            print(
                                "Dropping additional invariant (tautology): ",
                                inv)
                            continue
                    except RuntimeError:
                        # Some invariants are too large to parse
                        print("Dropping additional invariant (parse): ", inv)
                        continue
                    except Unknown:
                        # Timeouts could be valid invariants
                        pass
                    invs.append(inv)
                additionalInvs[lvlName] = invs
示例#9
0
                                    "Not Proved"))
                    print("-- Worker ID: " + worker_id + \
                            ( "" if worker_id == assn_worker_id else \
                              " (NOTE: different from worker ID in assignment)"))
                    print("-- IP: " + ip)
                    print("-- Time when finished: " + time_str)
                    print("-- User invs: " + ", ".join(js_invs))

                    boogie_user_invs = [ esprimaToBoogie(x, {}) \
                                            for x in canon_invs ]
                    try:
                        solName = os.path.join(get_lvlset_dir(lvl_set), \
                                               lvl_id + ".soln")
                        with open(solName) as f:
                            for l in f:
                                boogie_soln_inv = ast.parseExprAst(l)
                                header = "-- Soln " + str(boogie_soln_inv) + \
                                        ": "
                                found = False
                                for boogie_user_inv in boogie_user_invs:
                                    if equiv(boogie_soln_inv, boogie_user_inv):
                                        print(header + "Found as user " +\
                                              "predicate (canon version): " + \
                                              str(boogie_user_inv))
                                        found = True
                                if not found:
                                    print(header + "No equiv found")
                    except IOError:
                        print("-- No .soln file")

                if event_name == "GameDone":
示例#10
0
    print("Missing C path for ", lvl_name)
  else:
    if (not(exists(paths[1]))):
      print("C file for ", lvl_name, ":", paths[1], "is missing")

  if (len(paths) == 0):
    print("Missing desugared boogie file path for", lvl_name);
  else:
    if (not exists(paths[0])):
      print("Desugared boogie for ", lvl_name, ":", paths[0], "is missing");


print("Checking all solutions work...")
for lvl_name, lvl in list(lvls.items()):
  sol = open(lvl["path"][0].replace(".bpl", ".sol")).read()
  sol = bast.parseExprAst(sol);
  bbs = lvl["program"]
  loop = lvl["loop"]

  try:
    (overfit, nonind, sound, violations) = verify(lvl, [sol])
    if (not len(violations) == 0):
      print(lvl_name, "doesn't satisfy solution ", sol, "details:", \
              (overfit, nonind, sound, violations))
  except Unknown:
    print("Can't tell for level ", lvl_name)
    continue

endsWithNumP = reComp(".*\.[0-9]*$")
justEnd = reComp("\.[0-9]*$")
示例#11
0
def parseInvGenInvariant(inv):
    replaceEq = re.compile("([^<>=])=([^<>=])")
    inv = replaceEq.sub(r"\1==\2", inv)
    inv = inv.replace("=<", "<=")
    return parseExprAst(inv)