def compile(self, name): global compiled if self.verif: key = (self.width, name + "-verif") else: key = (self.width, name + "-synth") if not self.cachable(key) or key not in compiled: bin = tempfile.NamedTemporaryFile(delete=not args.args.keeptemps, dir=args.args.ofiledir) gcc = self.gccargs[name] + ["-o", bin.name, "-lm"] compiled[key] = bin bin.close() perf.start("gcc") if args.args.verbose > 1: print " ".join(gcc) subprocess.call(gcc) else: with open(os.devnull, "w") as fnull: subprocess.call(gcc, stdout=fnull, stderr=fnull) perf.end("gcc") return bin else: return compiled[key]
def generalize(prog, checker, width, targetwidth, tests, codelen): perf.start("generalize") ret = heuristic_generalize(prog, checker, width, targetwidth, codelen) perf.end("generalize") return ret
def kalashnikov(checker): codelen = args.args.seqlen wordlen = args.args.wordwidth targetwordlen = args.args.targetwordwidth n = 1 tests = gentests(wordlen, codelen) exclusions = [] correct = [] starttime = time.time() seqlim = args.args.seqlim nconsts = 0 signal.alarm(args.args.timeout) if args.args.consts >= 0: nconsts = args.args.consts if args.args.exhaustive: numsearch = -1 else: numsearch = 1 perf.start() while codelen <= seqlim and len(correct) != numsearch: sys.stdout.flush() perf.inc("iterations") if not args.args.verbose: endtime = time.time() elapsed = endtime - starttime print("Iteration: " + BOLD + RED + "%d" + ENDC) % n print("Code sequence length: " + BOLD + RED + "%d/%d" + ENDC) % (codelen, args.args.seqlim) print("Word width: " + BOLD + RED + "%d/%d" + ENDC) % (wordlen, targetwordlen) print("Excluded sequences: " + BOLD + RED + "%d/%d" + ENDC) % (len(exclusions), args.args.exclude) print("Test vectors: " + BOLD + RED + "%d" + ENDC) % len(tests) print("Constants: " + BOLD + RED + "%d" + ENDC) % nconsts print("Elapsed time: " + BOLD + RED + "%.02fs" + ENDC) % elapsed if args.args.exhaustive: print("Correct sequences: " + BOLD + RED + "%d" + ENDC) % (len(correct)) print UP * 2 + "\r" print UP * 8 + "\r" sys.stdout.flush() if args.args.verbose > 0: print correct n += 1 if args.args.verbose > 1: print "Test vectors: %s" % str(tests) prog = synth(tests, exclusions + correct, wordlen, codelen, nconsts) if prog == None: if args.args.verbose > 0: print "No sequence possible!" if args.args.consts < 0 and nconsts < codelen: nconsts += 1 else: codelen += 1 if args.args.consts < 0: nconsts = 0 exclusions = [] if args.args.verbose > 0: print "Increasing constants to %d\n" % nconsts print "Increasing sequence length to %d\n" % codelen continue if args.args.verbose > 0: print str(prog) test = verif(prog, checker, wordlen, codelen) if test is None: if args.args.verbose > 0: print "Correct for wordlen=%d" % wordlen if wordlen == targetwordlen: correct.append(prog) continue test = verif(prog, checker, targetwordlen, codelen) if test is None: if args.args.verbose > 0: print "Also correct for wordlen=%d!" % targetwordlen correct.append(prog) continue if args.args.verbose > 0: print "Trying to generalize..." newprog = generalize(prog, checker, wordlen, targetwordlen, tests, codelen) if newprog: if args.args.verbose > 1: print "Generalized!" correct.append(newprog) prog = newprog continue if args.args.verbose > 0: print "Couldn't generalize :-(" if len(exclusions) < args.args.exclude: if args.args.verbose > 0: print "Excluding current sequence" perf.inc("exclusions") exclusions.append(prog) else: exclusions = [] wordlen *= 2 if wordlen > targetwordlen: wordlen = targetwordlen tests = gentests(wordlen, codelen) tests = list(set(tests)) if args.args.verbose > 0: print "Increasing wordlen to %d" % wordlen else: if args.args.verbose > 0: print "Fails for %s\n" % str(test) tests.append(test) perf.end() endtime = time.time() elapsed = endtime - starttime print "\n" * 6 print "Finished in %0.2fs\n" % elapsed for prog in correct: print str(prog) print ""
def verif(prog, checker, width, codelen): """ Verify that a sequence is correct & extract a new test vector if it's not." """ perf.start("verify") sz = max(len(o) for o in prog.ops) bmc = Checker(sz, width, len(prog.consts[0]), verif=True) solfile = open("/tmp/solution", "w") solfile.write(" ".join("0x%x" % (x & 0xffffffff) for x in prog.evars) + "\n") for i in xrange(args.args.progs): nops = len(prog.ops[i]) solfile.write("%d\n" % nops) for j in xrange(nops): solfile.write( "%d %d %d %d\n" % (prog.ops[i][j], prog.params[i][3 * j], prog.params[i][3 * j + 1], prog.params[i][3 * j + 2])) nconsts = len(prog.consts[i]) for j in xrange(nconsts): solfile.write("0x%x\n" % (prog.consts[i][j] & 0xffffffff)) solfile.close() cfile = open("/tmp/exec.c", "w") cfile.write(r""" #include "synth.h" volatile int execok; void exec(prog_t *prog, word_t args[NARGS], word_t res[NRES]) { """) for i in xrange(args.args.progs): cfile.write(r""" if (prog == &solution.progs[%d]) { """ % i) for j in xrange(sz): cfile.write(" res[%d] = 0;\n" % j) cfile.write( prog.prog2str(prog.ops[i], prog.params[i], prog.consts[i], executable=True)) cfile.write("\n }\n") cfile.write("}") cfile.close() bmc.write(r""" #include "synth.h" solution_t solution = { { """) for i in xrange(args.args.progs): bmc.write(r""" { %d, { %s }, { %s }, { %s }, }, """ % (len(prog.ops[i]), ", ".join(str(o) for o in prog.ops[i]), ", ".join( str(p) for p in prog.params[i]), ", ".join( str(c) for c in prog.consts[i]))) bmc.write(r""" }, { %s } }; """ % (", ".join(str(e) for e in prog.evars))) try: (retcode, output) = bmc.run() finally: perf.end("verify") cex = None if retcode == 10: # We got a counterexample -- extract a new test case from it for l in output: mx = cexre.search(l) if mx: cex = tuple(str2ints(mx.group(1))) else: # No counterexample -- this sequence is correct! pass return cex
def synth(tests, exclusions, width, codelen, nconsts): """ Synthesise a new code sequence. """ perf.start("synth") bmc = Checker(codelen, width, nconsts) testfile = open("/tmp/testvectors", "w") # Write the test inputs... bmc.write(r""" #include "synth.h" void tests(solution_t *solution) { word_t input[NARGS]; """) testfile.write("%d\n" % len(tests)) #random.shuffle(tests) for x in tests: for i in xrange(len(x)): bmc.write(" input[%d] = %d;\n" % (i, x[i])) bmc.write(" test(solution, input);\n\n") testfile.write(" ".join(str(d) for d in x) + "\n") testfile.close() # Now we're going to list each of the programs we # already know are wrong... for soln in exclusions: ops = soln.ops parms = soln.params consts = soln.consts evars = soln.evars bmc.write(" assume(!(") for i in xrange(len(ops)): if i != 0: bmc.write(" && ") bmc.write("solution->prog.ops[%d] == %d " % (i, ops[i])) bmc.write( "&& solution->prog.params[%d] == %d && solution->prog.params[%d] == %d && solution->prog.params[%d] == %d" % (3 * i, parms[3 * i], 3 * i + 1, parms[3 * i + 1], 3 * i + 1, parms[3 * i + 2])) for i in xrange(len(consts)): bmc.write("&& solution->prog.consts[%d] == %d" % (i, consts[i])) for i in xrange(len(evars)): bmc.write("&& solution->evars[%d] == %d" % (i, evars[i])) bmc.write("));\n") bmc.write("}\n") try: (retcode, output) = bmc.run() finally: perf.end("synth") prog = None if retcode == 10: # A counterexample was found -- extract the code sequence from it! prog = Prog() prog.parse(output) return prog
def run(self): self.scratchfile.flush() perf.start("checker") procs = [] strategy = None if args.args.verif_strategy == "default": args.args.verif_strategy = args.args.strategy if args.args.synth_strategy == "default": args.args.synth_strategy = args.args.strategy if self.verif: if args.args.verif_strategy in ("all", "evolve"): strategies = ["explicit", "cbmc"] else: strategies = [args.args.verif_strategy] else: if args.args.synth_strategy == "all": strategies = ["explicit", "cbmc", "genetic", "anneal"] elif args.args.synth_strategy == "evolve": strategies = ["genetic", "anneal"] else: strategies = [args.args.synth_strategy] try: if "cbmc" in strategies: if args.args.verbose > 1: print " ".join(self.cbmcargs) cbmcfile = tempfile.NamedTemporaryFile( delete=not args.args.keeptemps) cbmcproc = subprocess.Popen(self.cbmcargs, stdout=cbmcfile, preexec_fn=os.setpgrp) procs.append((cbmcproc, cbmcfile, "cbmc")) bins = {} for s in ("explicit", "genetic", "anneal"): if s in strategies: bin = self.compile(s) bins[s] = bin outfile = tempfile.NamedTemporaryFile( delete=not args.args.keeptemps) if args.args.verbose > 1: print bin.name proc = subprocess.Popen([bin.name], stdout=outfile, preexec_fn=os.setpgrp) procs.append((proc, outfile, s)) (finished, retcode) = os.wait() finally: perf.end("checker") for (proc, _, _) in procs: try: os.killpg(proc.pid, signal.SIGKILL) proc.wait() except: pass retfile = None for (proc, outfile, checker) in procs: if proc.pid == finished: retfile = outfile perf.inc(checker) if args.args.verbose > 0: print "Fastest checker: %s" % checker retfile.seek(0) return (os.WEXITSTATUS(retcode), retfile)