def compute_from_smt(self, smt): assigns = self.exprmgr.mkBoolConst(True) exe = Execution() for relation in self.relations: assign = self.symboltable.lookup(relation) value = smt.getValue(assign) rel = self.__relation_from_formula(relation, value) assert (rel is not None) exe.set_relation_by_name(relation, rel) if relation in self.blocking_relations: assign = self.exprmgr.mkExpr(EQUAL, assign, value) assigns = self.exprmgr.mkExpr(AND, assigns, assign) for variable in self.variables: assign = self.symboltable.lookup(variable) value = smt.getValue(assign).toString() exe.add_condition(variable, value) assign = self.exprmgr.mkExpr(EQUAL, assign, smt.getValue(assign)) assigns = self.exprmgr.mkExpr(AND, assigns, assign) blocking = self.exprmgr.mkExpr(NOT, assigns) Logger.log("Blocking: %s" % (blocking.toString()), 2) self.models.append(exe) self.write_models(self.models, False) return ([blocking], exe)
def compute_from_sharedobjs(self, shared_objs): executions = Executions() executions.executions = shared_objs assertions = self.encoder.print_assert_neg_execs( executions, self.blocking_relations) Logger.log("Blocking: \n%s" % ("\n".join(assertions)), 2) return "\n" + ("\n".join(assertions))
def __compute_models(self, model, solver, num, blocking_manager, constraints=None, shared_objects=None): if constraints: model += "\n" + constraints assertions = blocking_manager.compute_from_sharedobjs(shared_objects) model += "\n" + assertions num_sols = 0 while True: if (num != -1) and (num_sols >= num): break ret = self.solve_one(model, solver) self.__clean_files() if ret is None: return (shared_objects, 0) num_sols += 1 (bclauses, shared_obj) = blocking_manager.compute_from_smt(ret) Logger.msg(".", 0, True, 0) if shared_obj not in shared_objects: shared_objects.append(shared_obj) else: if constraints is not None: return (shared_objects, 2) model += bclauses return (shared_objects, 1)
def prune_not_eq(self, ao_execs, executions, model, program, threads): self.c4vexecsmanager.preload = False beparser = BeParser() eq_progs = [] equivalent_AOs = [] events_dic = dict([(x.name, x) for x in program.get_events()]) if threads > 1: valid_aos = self.__check_all_mt(model, ao_execs, executions, threads) else: valid_aos = self.__check_all(model, ao_execs, executions) for exe in valid_aos: rel = Relation(AO) rel.tuples = [(events_dic[str(x[0])], events_dic[str(x[1])]) for x in exe.get_AO().tuples] exe.set_AO(rel) exe.program = program equivalent_AOs.append(exe) program = beparser.program_from_execution(exe) eq_progs.append(program) Logger.log(" DONE", 1) if Logger.level(1): for el in equivalent_AOs: Logger.log("EQUIVALENT: %s" % el.get_AO(), 1) return eq_progs
def compute_from_smt(self, smt): AlloyValidExecsModelsManager.id_blocking += 1 exe = self.__generate_execution(smt) blocking = [] for rel in self.blocking_relations: tuples = self.__extract_tuples(self.__relname_mapping()[rel], smt) if len(tuples[0]) == 0: blocking.append("(no %s.rel)" % (self.__relname_mapping()[rel])) else: btup = [] for tup in tuples: btup.append(" -> ".join(tuple(tup))) blocking.append("%s.rel = %s" % (self.__relname_mapping()[rel], " + ".join( ["{(%s)}" % x for x in btup]))) for var in self.variables: value = self.__get_condition(smt, var) if value is not None: blocking.append("(%s.value = %s)" % (var, value)) exe.add_condition(var, value) blocking = "fact block_smt_%s {not (%s)}\n" % ( AlloyValidExecsModelsManager.id_blocking, " and ".join(blocking)) Logger.log("Blocking: %s" % (blocking), 2) self.models.append(exe) self.write_models(self.models, False) return (blocking, exe)
def solve_all_cvc4(self, model, program=None, nexecs=-1, threads=1): self.cvc4_vexecsmanager.program = program if program.has_conditions: self.cvc4_vexecsmanager.set_additional_variables( program.get_conditions()) timer = Logger.start_timer("CVC4 solve all") ret = self.c4solver.solve_allsmt(model, self.cvc4_vexecsmanager, nexecs, threads) Logger.stop_timer(timer) return len(ret)
def solve_all_alloy(self, model, program=None, nexecs=-1, threads=1): self.alloy_vexecsmanager.program = program if program.has_conditions: self.alloy_vexecsmanager.set_additional_variables( program.get_conditions()) model += self.alloyencoder.print_run_condition(program) timer = Logger.start_timer("Alloy solve all") ret = self.alloysolver.solve_allsmt(model, self.alloy_vexecsmanager, nexecs, threads) Logger.stop_timer(timer) return len(ret)
def compute_from_smt(self, smt): assigns = self.exprmgr.mkBoolConst(True) model = [] for varstr in self.labelling_vars: assign = self.symboltable.lookup(varstr) value = smt.getValue(assign) model.append( "%s%s" % ("" if value.getConstBoolean() else "~", assign.toString())) assign = self.exprmgr.mkExpr(EQUAL, assign, smt.getValue(assign)) assigns = self.exprmgr.mkExpr(AND, assigns, assign) blocking = self.exprmgr.mkExpr(NOT, assigns) Logger.log("Blocking: %s" % (blocking.toString()), 2) return ([blocking], "(%s)" % " & ".join(model))
def compute_from_smt(self, model): AlloyConstraintAnalyzerManager.id_blocking += 1 blocking = [] bddmodel = [] for var in self.labelling_vars: value = self.__get_condition(model, var) if value is not None: blocking.append("(%s.value = %s)" % (var, value)) bddmodel.append("(%s%s)" % ("~" if value == "TRUE" else "", var)) blocking_str = "fact block_smt_%s {not (%s)}\n" % ( AlloyConstraintAnalyzerManager.id_blocking, " and ".join(blocking)) Logger.log("Blocking: %s" % (blocking_str), 2) return (blocking_str, (" and ".join(blocking), " & ".join(bddmodel)))
def solutions_separators(self): if not self.program: return [] ao_set = [(x.name, y.name) for x in self.program.get_events() for y in self.program.get_events() if x != y] ao_cons = [ self.encoder.assert_formula("(AO [%s, %s])" % (x)) for x in ao_set ] Logger.msg("(%s)" % len(ao_cons), 0) if self.shuffle_constraints: random.shuffle(ao_cons) return ao_cons
def __print_models(self, models): msg = " -> Found %s solution%s" % (len(models), "" if len(models) == 1 else "s") if models == ["()"]: Logger.log("VALID\n", 0) elif len(models) == 0: Logger.log("FALSE\n", 0) else: Logger.log(msg, 0) Logger.log("%s\n" % (" | \n".join(models)), 0)
def solve_allsmt(self, model, blocking_manager, num_sols=-1, num_t=1): num_t = 1 self.__init_solvers(num_t) pre_objs = blocking_manager.load_models() Logger.msg("." * len(pre_objs), 0, True, 0) ret = None if num_t > 1: rb_cons = blocking_manager.solutions_separators() num_t = min(len(rb_cons), num_t) if num_t < 3: # Multithread is not necessary ret = self.__solve_nsat(model, num_sols, blocking_manager, pre_objs) else: with Manager() as manager: shared_objs = manager.list([]) for el in pre_objs: shared_objs.append(el) rb_cons = manager.list(rb_cons) threads = [] for i in range(num_t - 1): process = Process(target=self.__solve_nsat, args=(model, -1, blocking_manager, shared_objs, i, num_t - 1, rb_cons)) threads.append(process) process.start() shared_objs = self.__solve_nsat(model, num_sols, blocking_manager, shared_objs, 0) for thread in threads: thread.terminate() ret = list(shared_objs) else: ret = self.__solve_nsat(model, num_sols, blocking_manager, pre_objs) self.__quit_solvers() return ret
def solve_one(self, model, solver): if Logger.level(3): linenum = 0 for line in model.split("\n"): linenum += 1 Logger.log("%s: %s" % (linenum, line), 3) solver.stdin.write(('%s\nreset\n' % (model)).encode()) solver.stdin.flush() out = "" while True: line = solver.stdout.readline().decode() out += line if line in ["sat\n", "unsat\n"]: break out = out.split("\n") Logger.log("Solver: %s" % out[0], 2) if out[-2] == "sat": return out else: return None
def solutions_separators(self): if not self.program: return [] rf = True cr = self.encoder.get_compatible_reads(self.program) rb_cons = [ self.encoder.assert_formula("(RBF %s)" % (x)) for x in cr[1] ] if rf: rb_cons += [ self.encoder.assert_formula("(RF %s)" % (x)) for x in cr[0] ] Logger.msg("(%s)" % len(rb_cons), 0) if self.shuffle_constraints: random.shuffle(rb_cons) return rb_cons
def user_defined_analyses(self, mmodels, nmodels): config = configparser.ConfigParser() config.optionxform = str with open(UNMATCHED_FILE, "r") as f: config.read_string(u"" + f.read()) analyses = [] for value in config: if value == DEFAULT: continue analysis = config[value] analyses.append((analysis[DESCRIPTION], analysis[FORMULA])) for analysis in analyses: Logger.log(analysis[0], 0) formula = analysis[1].replace("unmatched", "{u}").replace( "matched", "{m}").replace("!", "~") formula = formula.format(m=" | ".join(mmodels), u=" | ".join(nmodels)) formula = self.bsolver.simplify(formula, True) self.__print_models(formula)
def __process_quantifier_int(self, formula, set_dict, set_type_dict, sup): cond1 = False cond2 = False cond3 = False quantifier = None if type(formula) == list: quantifier = self.FORALL if (self.FORALL in formula[0]) else \ self.EXISTS if (self.EXISTS in formula[0]) else \ self.BIGUNION if (self.BIGUNION in formula[0]) else \ self.BIGSUM if (self.BIGSUM in formula[0]) else None cond1 = quantifier is not None if (len(formula) > 1): cond2 = ((len(formula[1]) > 0) and (" IN " in formula[1][0])) cond3 = (" IN " not in self.__print_formula(formula[2:])) if cond1 and cond2 and cond3: Logger.log( "%% Processing quantifier %s: %s" % (quantifier, self.__print_formula(formula)), 2) if self.expand_sets or (quantifier == self.BIGUNION) or (quantifier == self.BIGSUM): value = self.__sub_quantifier_expand(formula, quantifier, set_dict) else: value = self.__sub_quantifier(formula, quantifier, set_type_dict) sup[0] = True return value else: if type(formula) == list: for i in range(len(formula)): formula[i] = self.__process_quantifier_int( formula[i], set_dict, set_type_dict, sup) return formula
def solve_all_synth(self, model, program, threads): timer = Logger.start_timer("CVC4 intersect") (ao_execs, executions) = self.find_all_intersect(model, program, threads) Logger.stop_timer(timer) timer = Logger.start_timer("CVC4 prune equivalent") ret = self.prune_not_eq(ao_execs, executions, model, program, threads) Logger.stop_timer(timer) return ret
def solve_all_synth_hybrid(self, cvc4model, alloymodel, program, threads): timer = Logger.start_timer("Alloy intersect") (ao_execs, executions) = self.alloy_synth.find_all_intersect( alloymodel, program, 1) Logger.stop_timer(timer) timer = Logger.start_timer("CVC4 prune equivalent") ret = self.cvc4_synth.prune_not_eq(ao_execs, executions, cvc4model, program, threads) Logger.stop_timer(timer) return ret
def unmatched_analysis(config): analyzer = ConstraintsAnalyzer() analyzer.set_models_file(config.models) analyzer.set_outputs_file(config.outputs) Logger.log("\n** Unmatched Outputs Analysis **", 0) config.unmatched = True if not config.defines: config.defines = "" config.defines += CONS_LABELLING program = parse_program(config) Logger.msg("Generating model... ", 0) if config.use_alloy: strmodel = generate_alloy_model(config, program) else: strmodel = generate_cvc_model(config, program) Logger.log("DONE", 0) if config.only_model: return 0 if (config.force_solving): del_file(config.outputs) if config.use_alloy: analyzer.analyze_constraints_alloy(program, \ strmodel, \ config.jsengine, \ config.runs, \ config.threads, \ config.outprogram+".js") else: analyzer.analyze_constraints_cvc4(program, \ strmodel, \ config.jsengine, \ config.runs, \ config.threads, \ config.outprogram+".js") return 0
def __compute_models(self, model, num, blocking_manager, constraints=None, shared_objects=None): opts = Options() opts.setInputLanguage(CVC4.INPUT_LANG_CVC4) exit_with_unknown = False if shared_objects is None: shared_objects = [] exprmgr = ExprManager(opts) smt = SmtEngine(exprmgr) smt.setOption("produce-models", SExpr(True)) smt.setOption("fmf-bound", SExpr(True)) smt.setOption("macros-quant", SExpr(True)) smt.setOption("finite-model-find", SExpr(True)) # smt.setOption("repeat-simp", SExpr(True)) # smt.setOption("check-models", SExpr(True)) # smt.setOption("full-saturate-quant", SExpr(True)) smt.setOption("incremental", SExpr(True)) ind = 0 assertions = blocking_manager.compute_from_sharedobjs(shared_objects) model = model + assertions if constraints: model += "\n%s;" % (constraints) parserbuilder = ParserBuilder(exprmgr, "", opts) parserbuilder.withStringInput(model) parser = parserbuilder.build() symboltable = parser.getSymbolTable() blocking_manager.exprmgr = exprmgr blocking_manager.symboltable = symboltable while True: cmd = parser.nextCommand() if not cmd: break cmd.invoke(smt) while True: checksat = CheckSatCommand() checksat.invoke(smt) sat = checksat.getResult().isSat() == 1 unk = checksat.getResult().isUnknown() uns = (not sat) and (not unk) Logger.log("sat: %s, uns: %s, unk: %s" % (sat, uns, unk), 2) exitcond = (not sat) if exit_with_unknown else uns if exitcond: return (shared_objects, 0) (bclauses, shared_obj) = blocking_manager.compute_from_smt(smt) Logger.log("%s" % str(shared_obj), 2) if shared_obj not in shared_objects: shared_objects.append(shared_obj) else: if constraints is not None: return (shared_objects, 2) for bclause in bclauses: assertion = AssertCommand(bclause) assertion.invoke(smt) Logger.msg(".", 0, constraints is None, 0) ind += 1 if (num != -1) and (ind >= num): return (shared_objects, 1) return (None, -1)
def analyze_constraints(self, program, model, jsengine, runs, threads, jsprogram, use_alloy): matched = None unmatched = None config = Config() config.command = jsengine config.input_file = jsprogram config.threads = threads config.number = runs config.silent = True config.models = True if use_alloy: labelling_vars = [y[2] for y in [x.split(" ") for x in model.split("\n") if len(x.split(" "))>2] \ if y[2][:len(LABELLING_VAR_PREF)] == LABELLING_VAR_PREF] else: labelling_vars = [x.split(" ")[0] for x in model.split("\n") \ if x[:len(LABELLING_VAR_PREF)] == LABELLING_VAR_PREF] if len(labelling_vars) == 0: Logger.error("No labelling vars defined") return None if use_alloy: self.al_consamanager.labelling_vars = labelling_vars else: self.c4_consamanager.labelling_vars = labelling_vars (matched, unmatched) = self.__load_outputs(config.number, self.outfile, jsengine) if (matched is None) and (unmatched is None): timer = Logger.start_timer("Run Litmus") (matched, unmatched) = run_litmus(config) Logger.stop_timer(timer) self.__save_outputs(config.number, self.outfile, jsengine, matched, unmatched) timer = Logger.start_timer("Analyze output") parser = BeParser() mexecs = parser.executions_from_string("\n".join(matched), program) uexecs = parser.executions_from_string("\n".join(unmatched), program) Logger.log(" -> Found %s matched models" % (len(matched)), 0) Logger.log(" -> Found %s unmatched models" % (len(unmatched)), 0) if len(unmatched) == 0: Logger.error("No unmatched models") Logger.stop_timer(timer) return None rels = [x for x in RELATIONS if x != AO] matched = self.al_encoder.print_assert_exl_execs(mexecs, rels) if use_alloy else \ self.c4_encoder.print_assert_exl_execs(mexecs, rels) unmatched = self.al_encoder.print_assert_exl_execs(uexecs, rels) if use_alloy else \ self.c4_encoder.print_assert_exl_execs(uexecs, rels) objs = [] Logger.log("\nMatched models analysis", 0) Logger.msg("Solving... ", 0) if use_alloy: vmodel = "\n".join([ model, matched, self.al_encoder.print_run_condition(program, True) ]) objs = self.al_solver.compute_models(vmodel, self.al_consamanager, objs) mmodels = " | ".join([x[1] for x in objs]) else: vmodel = "%s\n%s" % (model, matched) objs = self.c4_solver.compute_models(vmodel, self.c4_consamanager, objs) mmodels = " | ".join(objs) Logger.log(" DONE", 0) mmodels = self.bsolver.simplify(mmodels, True) self.__print_models(mmodels) objs = [] Logger.log("Unmatched models analysis", 0) Logger.msg("Solving... ", 0) if use_alloy: vmodel = "\n".join([ model, unmatched, self.al_encoder.print_run_condition(program, True) ]) objs = self.al_solver.compute_models(vmodel, self.al_consamanager, objs) nmodels = " | ".join([x[1] for x in objs]) else: vmodel = "%s\n%s" % (model, unmatched) objs = self.c4_solver.compute_models(vmodel, self.c4_consamanager, objs) nmodels = " | ".join(objs) Logger.log(" DONE", 0) nmodels = self.bsolver.simplify(nmodels, True) self.__print_models(nmodels) Logger.log("Difference analysis (exist support(matched) in unmatched)", 0) diffmodels = self.bsolver.support_exist(" | ".join(mmodels), " | ".join(nmodels), True) self.__print_models(diffmodels) self.user_defined_analyses(mmodels, nmodels) Logger.stop_timer(timer) return (mmodels, nmodels, diffmodels)
def __solve_nsat(self, model, n, blocking_manager, shared_objs=None, id_thread=None, total=None, constraints=None): applying_cons = None if shared_objs is None: shared_objs = [] is_multithread = id_thread is not None is_master = constraints is None if is_multithread: if is_master: process = self.alloy_processes[0] else: process = self.alloy_processes[id_thread + 1] else: process = self.alloy_processes[0] if not is_multithread or is_master: self.__clean_files() if constraints is not None: applying_cons = constraints[id_thread] if not is_multithread: (sol, ret) = self.__compute_models(model, process, n, blocking_manager, applying_cons, shared_objs) for el in sol: if el not in shared_objs: shared_objs.append(el) blocking_manager.write_models(shared_objs, ret == 0) return sol sol = None prvsolsize = 0 solsize = 0 while (solsize < n) or (n == -1): prvsolsize = solsize (sol, ret) = self.__compute_models(model, process, 1, blocking_manager, applying_cons, shared_objs) for el in sol: if el not in shared_objs: shared_objs.append(el) solsize = len(sol) if is_master: blocking_manager.write_models(shared_objs, ret == 0) if (self.verbosity > 0) and is_multithread and is_master: if ((solsize - prvsolsize) > 1): gain = (solsize - prvsolsize) - 1 Logger.msg("+%s%s" % (gain, "." * (gain)), 0, True, 0) if not is_master: if ret == 0: #UNSAT if id_thread >= len(constraints) - 1: break Logger.msg("d", 0) constraints[id_thread] = constraints[-1] del (constraints[-1]) applying_cons = constraints[id_thread] continue if ret == 2: # Not interesting constraint Logger.msg("s", 0) if len(constraints) > total: tmp = constraints[id_thread] constraints[id_thread] = constraints[-1] constraints[-1] = tmp constraints[total:] = constraints[total + 1:] + [ constraints[total] ] applying_cons = constraints[id_thread] if ret == 0: break return shared_objs
def synth_program(config): analyzer = EquivalentExecutionSynthetizer() analyzer.set_models_file(config.models) Logger.log("\n** Equivalent Programs Synthesis **", 0) config.synth = True if not config.defines: config.defines = "" config.defines += RELAX_AO program = parse_program(config) if program.has_conditions(): Logger.msg("Program synthesis does not support conditional programs", 0) return 0 Logger.msg("Generating relaxed SMT model... ", 0) if config.use_alloy or config.hybrid: strmodel_alloy = generate_alloy_model(config, program) if not config.use_alloy or config.hybrid: strmodel_cvc4 = generate_cvc_model(config, program) Logger.log("DONE", 0) if config.only_model: return 0 Logger.msg("Solving... ", 0) if config.use_alloy: programs = analyzer.solve_all_synth_alloy(strmodel_alloy, program, config.threads) else: if config.hybrid: programs = analyzer.solve_all_synth_hybrid(strmodel_cvc4, strmodel_alloy, program, config.threads) else: programs = analyzer.solve_all_synth_cvc(strmodel_cvc4, program, config.threads) totmodels = len(programs) Logger.log(" DONE", 0) if totmodels > 0: Logger.log( " -> Found %s equivalent program%s" % (totmodels, "" if totmodels == 1 else "s"), 0) else: Logger.log(" -> No viable equivalent programs found", 0) Logger.msg("Generating equivalent programs... ", 0) printer = PrintersFactory.printer_by_name(BePrinter.get_name()) filename = (config.inputfile.split("/")[-1]).split(".")[0] for i in range(len(programs)): with open(config.eqprogs % (filename, str(i + 1)), "w") as eqprog: eqprog.write(printer.print_program(programs[i])) Logger.log("DONE", 0) Logger.log("", 1) Logger.log("** Original Program: **\n", 1) Logger.log(printer.print_program(program), 1) for program in programs: Logger.log( "** Equivalent Program %s: **\n" % (programs.index(program) + 1), 1) Logger.log(printer.print_program(program), 1) return 0
def find_all_intersect(self, model, program, threads): self.c4vexecsmanager.program = program executions = Executions() executions.executions = self.c4vexecsmanager.load_models() self.c4vexecsmanager.preload = False vmodel = model + "\n" + self.c4_encoder.print_general_AO(program) qupre = QuantPreprocessor() qupre.set_expand_sets(True) vmodel = qupre.preprocess_from_string(vmodel) self.c4vexecsmanager.blocking_relations = [AO] ao_execs = [] for models_blocking in [[RBF]]: assertions = self.c4_encoder.print_assert_exl_execs( executions, models_blocking) vmodel += "\n%s\n" % assertions execs = self.c4_solver.solve_allsmt( vmodel, self.c4vexecsmanager, -1, threads if ao_execs == [] else 1) ao_execs += [x for x in execs if x not in ao_execs] self.c4vexecsmanager.prevmodels = ao_execs Logger.msg(" ", 0) self.c4vexecsmanager.prevmodels = None Logger.log(" -> Found %s possible candidates" % (len(ao_execs)), 1) Logger.msg("Checking correctness... ", 1) if Logger.level(1): Logger.msg("\n", -1) for el in ao_execs: Logger.log("INTERSECTING: %s" % el.get_AO(), 1) return (ao_execs, executions)
def find_all_intersect(self, model, program, threads): run_condition = self.alloy_encoder.print_run_condition(program) self.allvexecsmanager.program = program executions = Executions() executions.executions = self.allvexecsmanager.load_models() self.allvexecsmanager.preload = False vmodel = "\n".join( [model, self.alloy_encoder.print_general_AO(program)]) self.allvexecsmanager.blocking_relations = [AO] ao_execs = [] for models_blocking in [[RBF]]: assertions = self.alloy_encoder.print_assert_exl_execs( executions, models_blocking) vmodel += "\n%s\n" % assertions execs = self.alloy_solver.solve_allsmt( vmodel + run_condition, self.allvexecsmanager, -1, threads if ao_execs == [] else 1) ao_execs += [x for x in execs if x not in ao_execs] self.allvexecsmanager.prevmodels = ao_execs Logger.msg(" ", 0) self.allvexecsmanager.prevmodels = None Logger.log(" -> Found %s possible candidates" % (len(ao_execs)), 1) Logger.msg("Checking correctness... ", 1) if Logger.level(1): Logger.msg("\n", -1) for el in ao_execs: Logger.log("INTERSECTING: %s" % el.get_AO(), 1) return (ao_execs, executions)
def analyze_program(config): config.generate_filenames() Logger.log("\n** Program Analysis **", 0) Logger.msg("Generating bounded execution... ", 0) program = parse_program(config) Logger.log("DONE", 0) Logger.msg("Generating model... ", 0) if config.use_alloy: strmodel = generate_alloy_model(config, program) else: strmodel = generate_cvc_model(config, program) Logger.log("DONE", 0) if config.only_model: return 0 if (not config.skip_solving): Logger.msg("Solving... ", 0) totmodels = solve(config, program, strmodel) if (not config.skip_solving): Logger.log(" DONE", 0) if totmodels > 0: Logger.log( " -> Found %s possible model%s" % (totmodels, "" if totmodels == 1 else "s"), 0) else: Logger.log(" -> No viable executions found", 0) # Generation of the JS litmus test # pprinter = PrintersFactory.printer_by_name(config.jsprinter) dprinter = PrintersFactory.printer_by_name(DotPrinter().get_name()) dprinter.set_printing_relations(config.printing_relations) prefix = config.prefix params = program.get_params() models = config.models for idparam in range(program.param_size()): if program.params: config.prefix = "%sparam%03d/" % (prefix, idparam + 1) config.generate_filenames() program.apply_param(dict(params[idparam])) if config.verbosity > 0: conf = params[idparam] pconf = ["%s=\"%s\"" % (x[0], x[1]) for x in conf] Logger.log( "\nParameter configuration (%03d): %s" % (idparam + 1, (", ".join(pconf))), 0) executions = None if (totmodels > 0): Logger.msg("Computing expected outputs... ", 0) parser = BeParser() parser.DEBUG = config.debug with open(models, "r") as modelfile: executions = parser.executions_from_string( modelfile.read(), program) Logger.log("DONE", 0) Logger.msg("Generating program... ", 0) outfiles = [config.outprogram] if config.jsdir: filename = config.outprogram.replace("../", "").replace("/", "-").replace( "..", "") outprogram = "%s/%s" % (config.jsdir, filename) outfiles = [outprogram] extension = pprinter.get_extension() for outfile in outfiles: with open(outfile + extension, "w") as f: f.write(pprinter.print_program(program, executions)) Logger.log("DONE", 0) if (totmodels > 0): Logger.msg("Generating expected outputs... ", 0) # Generation of all possible outputs for the JS litmus test # execs = pprinter.compute_possible_executions(program, executions) if config.debug: if execs is not None: with open(config.execs, "w") as exefile: exefile.write("\n".join(execs)) # Generation of all possible MM interpretations # mms = dprinter.print_executions(program, executions) for i in range(len(mms)): with open(config.dots % (str(i + 1)), "w") as dot: dot.write(mms[i]) if config.graphviz: with open(config.grap % (str(i + 1)), "w") as dot: graphviz_gen(config, config.dots % (str(i + 1)), config.grap % (str(i + 1))) Logger.log("DONE", 0) Logger.log( " -> Found %s possible output%s" % (len(execs), "" if len(execs) == 1 else "s"), 0) return 0
def main(args): parser = argparse.ArgumentParser( description='EMME: ECMAScript Memory Model Evaluator', formatter_class=RawTextHelpFormatter) parser.add_argument('input_file', metavar='program', type=str, help='the input file describing the program') jsprinters = [ " - \"%s\": %s" % (x.get_name(), x.get_desc()) for x in PrintersFactory.get_printers_by_type(PrinterType.PROGRAMS) ] config = Config() # Files generation parser.set_defaults(jsprinter=config.jsprinter) parser.add_argument( '-p', '--jsprinter', metavar='jsprinter', type=str, nargs='?', help='select the JS printer between (Default is \"%s\"):\n%s' % (config.jsprinter, "\n".join(jsprinters))) parser.set_defaults(jsdir=None) parser.add_argument( '-d', '--jsdir', metavar='jsdir', type=str, nargs='?', help= 'directory where to store all JS programs. (Default is the same as the input file)' ) parser.set_defaults(graphviz=False) parser.add_argument( '-g', '--graphviz', dest='graphviz', action='store_true', help= "generates the png files of each execution (requires neato). (Default is \"%s\")" % False) parser.set_defaults(relations=config.printing_relations) parser.add_argument( '-r', '--relations', metavar='relations', type=str, nargs='?', help= 'a (comma separated) list of relations to consider in the graphviz file.\nKeyword \"%s\" means all.' % ALL) parser.set_defaults(prefix=None) parser.add_argument( '-x', '--prefix', metavar='prefix', type=str, nargs='?', help= 'directory where to store the results. (Default is the same as the input file)' ) # Possible analyses parser.set_defaults(synth=False) parser.add_argument( '--synth', dest='synth', action='store_true', help="enables equivalent programs synthesis. (Default is \"%s\")" % False) parser.set_defaults(unmatched=False) parser.add_argument( '--unmatched', dest='unmatched', action='store_true', help="enables unmatched outputs analysis. (Default is \"%s\")" % False) parser.set_defaults(jsengine=None) parser.add_argument( '--jsengine', metavar='jsengine', type=str, nargs='?', help= 'the command used to call the JavaScript engine, to use with \"--unmatched\".' ) parser.set_defaults(runs=10) parser.add_argument( '-n', '--runs', metavar='runs', type=str, help= 'number of runs for the unmatched outputs analysis, to use with \"--unmatched\".\n(Default is \"10\")' ) # Solvers selection parser.set_defaults(use_cvc4=False) parser.add_argument( '-c', '--use-cvc4', dest='use_cvc4', action='store_true', help="relies on CVC4 instead of Alloy Analyzer. (Default is \"%s\")" % False) parser.set_defaults(best=False) parser.add_argument( '-b', '--best', dest='best', action='store_true', help= "relies on CVC4 or Alloy Analyzer for best performance. (Default is \"%s\")" % False) # Simple configurations parser.set_defaults(verbosity=1) parser.add_argument('-v', dest='verbosity', metavar="verbosity", type=int, help="verbosity level. (Default is \"%s\")" % 1) parser.set_defaults(nexecs=-1) parser.add_argument( '-e', '--max-executions', dest='nexecs', metavar='nexecs', type=int, help='maximum number of executions. (Default is \"unlimited\")') parser.set_defaults(force_solving=False) parser.add_argument( '-f', '--force-solving', dest='force_solving', action='store_true', help= "forces the solving part by discharging the previous models. (Default is \"%s\")" % False) parser.set_defaults(skip_solving=False) parser.add_argument('-k', '--skip-solving', dest='skip_solving', action='store_true', help="skips the solving part. (Default is \"%s\")" % False) parser.set_defaults(silent=False) parser.add_argument('-l', '--silent', dest='silent', action='store_true', help="silent mode. (Default is \"%s\")" % False) parser.set_defaults(check_sat=False) parser.add_argument( '-s', '--only-sat', dest='check_sat', action='store_true', help="performs only the satisfiability checking. (Default is \"%s\")" % False) parser.set_defaults(only_model=False) parser.add_argument( '-m', '--only-model', dest='only_model', action='store_true', help="exits right after the model generation. (Default is \"%s\")" % False) # Advanced configurations parser.set_defaults(threads=1) parser.add_argument( '-j', '--threads', metavar='number', type=int, help='number of threads - EXPERIMENTAL. (Default is \"1\")') parser.set_defaults(debug=False) parser.add_argument('--debug', dest='debug', action='store_true', help="enables debugging setup. (Default is \"%s\")" % False) parser.set_defaults(time=False) parser.add_argument( '-t', '--time', dest='time', action='store_true', help="enables time debugging setup. (Default is \"%s\")" % False) parser.set_defaults(no_expand_bounded_sets=False) parser.add_argument( '--no-exbounded', dest='no_expand_bounded_sets', action='store_true', help= "disables the bounded sets quantifier expansion. (Default is \"%s\")" % False) parser.set_defaults(defines=None) parser.add_argument( '--defines', metavar='defines', type=str, nargs='?', help='the set of preprocessor\'s defines. (Default is none)') parser.set_defaults(preproc=CPP) parser.add_argument( '--preproc', metavar='preproc', type=str, nargs='?', help='the memory model preprocessor. (Default is \"%s\")' % CPP) if len(sys.argv) == 1: parser.print_help() sys.exit(1) args = parser.parse_args(args) prefix = args.prefix if not prefix: prefix = args.input_file.split("/") prefix[-1] = prefix[-1].split(".")[0] prefix = "/".join(prefix) prefix += "/" if not os.path.exists(args.input_file): print("File not found: \"%s\"" % args.input_file) return 1 config.inputfile = args.input_file config.prefix = prefix config.preproc = args.preproc config.expand_bounded_sets = not args.no_expand_bounded_sets config.verbosity = args.verbosity config.defines = args.defines config.sat = args.check_sat config.only_model = args.only_model config.skip_solving = args.skip_solving config.printing_relations = args.relations config.graphviz = args.graphviz config.jsdir = args.jsdir config.debug = args.debug config.force_solving = args.force_solving config.threads = args.threads config.jsengine = args.jsengine config.runs = args.runs config.nexecs = args.nexecs config.use_alloy = not args.use_cvc4 config.unmatched = args.unmatched config.time = args.time if args.jsprinter in [ str(x.get_name()) for x in PrintersFactory.get_printers_by_type(PrinterType.PROGRAMS) ]: config.jsprinter = args.jsprinter else: Logger.error("Printer \"%s\" not found" % (args.jsprinter)) if config.unmatched and not config.jsengine: Logger.error("JavaScript engine not specified") return 1 if not config.use_alloy: try: import CVC4 except Exception: Logger.error("Error importing CVC4 module") return 1 if args.synth and args.best: config.hybrid = True if not args.synth and not args.unmatched and args.best: config.use_alloy = True if args.silent: config.verbosity = 0 if args.relations == ALL: config.printing_relations = None Logger.verbosity = config.verbosity Logger.log("** Processing file \"%s\" **" % (config.inputfile), -1) try: Logger.time = config.time ret = -1 ret = analyze_program(config) if ret == 0 and args.synth: ret = synth_program(config) if ret == 0 and args.unmatched: ret = unmatched_analysis(config) #cleanup if not config.debug: del_file(config.block_type) del_file(config.bound_int) del_file(config.alloy_model) del_file(config.cvc_model) del_file(config.cvc_model_ex) del_file(config.id_type) del_file(config.instance) Logger.log("\nExiting...", 0) return ret except Exception as e: if config.debug: raise print("\nERROR! Run with --debug option for more information") return 1