private void add(PptTopLevel ppt, ValueTuple vt) { // Add the sample to any splitters if (ppt.has_splitters()) { for (PptSplitter ppt_split : ppt.splitters) { PptConditional ppt_cond = ppt_split.choose_conditional(vt); if (ppt_cond != null) add(ppt_cond, vt); else debug.fine(": sample doesn't pick conditional"); } } // if this is a numbered exit, apply to the combined exit as well if (!(ppt instanceof PptConditional) && ppt.ppt_name.isNumberedExitPoint()) { PptTopLevel parent = all_ppts.get(ppt.ppt_name.makeExit()); if (parent != null) { parent.get_missingOutOfBounds(ppt, vt); add(parent, vt); } } // If the point has no variables, skip it if (ppt.var_infos.length == 0) return; // We should have received sample here before, or there is nothing // to check. // Yoav added: It can be that the different dtrace and inv files have different program points if (false && ppt.num_samples() <= 0) Assert.assertTrue( ppt.num_samples() > 0, "ppt " + ppt.name + " has 0 samples and " + ppt.var_infos.length + " variables"); // Loop through each slice slice_loop: for (Iterator<PptSlice> i = ppt.views_iterator(); i.hasNext(); ) { PptSlice slice = i.next(); if (debug_detail.isLoggable(Level.FINE)) debug_detail.fine( ": processing slice " + slice + "vars: " + Debug.toString(slice.var_infos, vt)); // If any variables are missing, skip this slice for (int j = 0; j < slice.var_infos.length; j++) { VarInfo v = slice.var_infos[j]; int mod = vt.getModified(v); if (v.isMissing(vt)) { if (debug_detail.isLoggable(Level.FINE)) debug_detail.fine(": : Skipping slice, " + v.name() + " missing"); continue slice_loop; } if (v.missingOutOfBounds()) { if (debug_detail.isLoggable(Level.FINE)) debug.fine(": : Skipping slice, " + v.name() + " out of bounds"); continue slice_loop; } } // Loop through each invariant for (Invariant inv : slice.invs) { if (debug_detail.isLoggable(Level.FINE)) debug_detail.fine(": : Processing invariant: " + inv); if (!inv.isActive()) { if (debug_detail.isLoggable(Level.FINE)) debug_detail.fine(": : skipped non-active " + inv); continue; } // Yoav added if (!activeInvariants.contains(inv)) { // System.out.printf ("skipping invariant %s:%s\n", inv.ppt.name(), // inv.format()); continue; } // String invRep = invariant2str(ppt, inv); testedInvariants.add(inv); InvariantStatus status = inv.add_sample(vt, 1); sample_cnt++; if (status != InvariantStatus.NO_CHANGE) { LineNumberReader lnr = FileIO.data_trace_state.reader; String line = (lnr == null) ? "?" : String.valueOf(lnr.getLineNumber()); if (!quiet) { output_stream.println( "At ppt " + ppt.name + ", Invariant '" + inv.format() + "' invalidated by sample " + Debug.toString(slice.var_infos, vt) + "at line " + line + " in file " + FileIO.data_trace_state.filename); } failedInvariants.add(inv); activeInvariants.remove(inv); error_cnt++; } } } }
/** * This does the work of main, but it never calls System.exit, so it is appropriate to be called * progrmmatically. Termination of the program with a message to the user is indicated by throwing * Daikon.TerminationMessage. * * @see #main(String[]) * @see daikon.Daikon.TerminationMessage */ public static void mainHelper(final String[] args) throws FileNotFoundException, StreamCorruptedException, OptionalDataException, IOException, ClassNotFoundException { daikon.LogHelper.setupLogs(daikon.LogHelper.INFO); LongOpt[] longopts = new LongOpt[] { new LongOpt(Daikon.config_option_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(output_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(dir_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(conf_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(filter_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debugAll_SWITCH, LongOpt.NO_ARGUMENT, null, 0), new LongOpt(Daikon.debug_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.ppt_regexp_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), new LongOpt(Daikon.track_SWITCH, LongOpt.REQUIRED_ARGUMENT, null, 0), }; Getopt g = new Getopt("daikon.tools.InvariantChecker", args, "h", longopts); int c; while ((c = g.getopt()) != -1) { switch (c) { case 0: // got a long option String option_name = longopts[g.getLongind()].getName(); if (Daikon.help_SWITCH.equals(option_name)) { System.out.println(usage); throw new Daikon.TerminationMessage(); } else if (conf_SWITCH.equals(option_name)) { doConf = true; } else if (filter_SWITCH.equals(option_name)) { doFilter = true; } else if (dir_SWITCH.equals(option_name)) { dir_file = new File(g.getOptarg()); if (!dir_file.exists() || !dir_file.isDirectory()) throw new Daikon.TerminationMessage("Error reading the directory " + dir_file); } else if (output_SWITCH.equals(option_name)) { output_file = new File(g.getOptarg()); output_stream = new PrintStream(new FileOutputStream(output_file)); } else if (Daikon.config_option_SWITCH.equals(option_name)) { String item = g.getOptarg(); daikon.config.Configuration.getInstance().apply(item); break; } else if (Daikon.debugAll_SWITCH.equals(option_name)) { Global.debugAll = true; } else if (Daikon.debug_SWITCH.equals(option_name)) { LogHelper.setLevel(g.getOptarg(), LogHelper.FINE); } else if (Daikon.track_SWITCH.equals(option_name)) { LogHelper.setLevel("daikon.Debug", LogHelper.FINE); String error = Debug.add_track(g.getOptarg()); if (error != null) { throw new Daikon.TerminationMessage( "Error parsing track argument '" + g.getOptarg() + "' - " + error); } } else { throw new RuntimeException("Unknown long option received: " + option_name); } break; case 'h': System.out.println(usage); throw new Daikon.TerminationMessage(); case '?': break; // getopt() already printed an error default: System.out.println("getopt() returned " + c); break; } } // Loop through each filename specified for (int i = g.getOptind(); i < args.length; i++) { // Get the file and make sure it exists File file = new File(args[i]); if (!file.exists()) { throw new Error("File " + file + " not found."); } // These aren't "endsWith()" because there might be a suffix on the end // (eg, a date). String filename = file.toString(); if (filename.indexOf(".inv") != -1) { if (inv_file != null) { throw new Daikon.TerminationMessage("multiple inv files specified", usage); } inv_file = file; } else if (filename.indexOf(".dtrace") != -1) { dtrace_files.add(filename); } else { throw new Error("Unrecognized argument: " + file); } } if (dir_file == null) { checkInvariants(); return; } // Yoav additions: File[] filesInDir = dir_file.listFiles(); if (filesInDir == null || filesInDir.length == 0) throw new Daikon.TerminationMessage("The directory " + dir_file + " is empty", usage); ArrayList<File> invariants = new ArrayList<File>(); for (File f : filesInDir) if (f.toString().indexOf(".inv") != -1) invariants.add(f); if (invariants.size() == 0) throw new Daikon.TerminationMessage( "Did not find any invariant files in the directory " + dir_file, usage); ArrayList<File> dtraces = new ArrayList<File>(); for (File f : filesInDir) if (f.toString().indexOf(".dtrace") != -1) dtraces.add(f); if (dtraces.size() == 0) throw new Daikon.TerminationMessage( "Did not find any dtrace files in the directory " + dir_file, usage); System.out.println( "Collecting data for invariants files " + invariants + " and dtrace files " + dtraces); dtrace_files.clear(); for (File dtrace : dtraces) { dtrace_files.add(dtrace.toString()); } String commaLine = ""; for (File inFile : invariants) { String name = inFile.getName().replace(".inv", "").replace(".gz", ""); commaLine += "," + name; } outputComma.add(commaLine); commaLine = ""; for (File inFile : invariants) { inv_file = inFile; failedInvariants.clear(); testedInvariants.clear(); error_cnt = 0; output_stream = new PrintStream( new FileOutputStream( inFile.toString().replace(".inv", "").replace(".gz", "") + ".false-positives.txt")); checkInvariants(); output_stream.close(); int failedCount = failedInvariants.size(); int testedCount = testedInvariants.size(); String percent = toPercentage(failedCount, testedCount); commaLine += "," + percent; } outputComma.add(commaLine); System.out.println(); for (String output : outputComma) System.out.println(output); }
private static void checkInvariants() throws IOException { // Read the invariant file PptMap ppts = FileIO.read_serialized_pptmap(inv_file, true); // Yoav: make sure we have unique invariants InvariantFilters fi = InvariantFilters.defaultFilters(); // Set<String> allInvariantsStr = new HashSet<String>(); Set<Invariant> allInvariants = new HashSet<Invariant>(); for (PptTopLevel ppt : ppts.all_ppts()) for (Iterator<PptSlice> i = ppt.views_iterator(); i.hasNext(); ) { PptSlice slice = i.next(); for (Invariant inv : slice.invs) { if (doConf && inv.getConfidence() < Invariant.dkconfig_confidence_limit) { // System.out.printf ("inv ignored (conf): %s:%s\n", inv.ppt.name(), // inv.format()); continue; } if (doFilter && fi.shouldKeep(inv) == null) { // System.out.printf ("inv ignored (filter): %s:%s\n", // inv.ppt.name(), inv.format()); continue; } activeInvariants.add(inv); // String n = invariant2str(ppt, inv); // if (!allInvariants.contains(inv) && allInvariantsStr.contains(n)) throw new // Daikon.TerminationMessage("Two invariants have the same ppt.name+inv.rep:"+n); allInvariants.add(inv); // allInvariantsStr.add(n); } } // Read and process the data trace files FileIO.Processor processor = new InvariantCheckProcessor(); Daikon.FileIOProgress progress = new Daikon.FileIOProgress(); progress.start(); progress.clear(); FileIO.read_data_trace_files(dtrace_files, ppts, processor, false); progress.shouldStop = true; System.out.println(); System.out.printf( "%s: %,d errors found in %,d samples (%s)\n", inv_file, error_cnt, sample_cnt, toPercentage(error_cnt, sample_cnt)); int failedCount = failedInvariants.size(); int testedCount = testedInvariants.size(); String percent = toPercentage(failedCount, testedCount); System.out.println( inv_file + ": " + failedCount + " false positives, out of " + testedCount + ", which is " + percent + "."); if (false) { for (Invariant inv : failedInvariants) { System.out.printf("+%s:%s\n", inv.ppt.name(), inv.format()); } } }