// Replace "assume x == NULL" with "assume x == NULL; assert false;" // provided x can indeed alias NULL // Also returns a map from allocation_site to possible branches affected by it public static Tuple <Program, Dictionary <int, HashSet <int> > > Run(Program program, string ep, bool useAA, bool injectAssert) { var ib = new InstrumentBranches(program, useAA, injectAssert); ib.instrument(ep); if (!useAA) { Console.WriteLine("For deadcode detection, we added {0} angelic assertions", ib.assertsAdded); return(Tuple.Create <Program, Dictionary <int, HashSet <int> > >(program, null)); } var inp = new PersistentProgram(program, ep, 1); //inp.writeToFile("progbefore.bpl"); // Make sure that aliasing queries are on identifiers only var af = AliasAnalysis.SimplifyAliasingQueries.Simplify(program); // Do SSA program = SSA.Compute(program, PhiFunctionEncoding.Verifiable, new HashSet <string> { "int" }); //BoogieUtil.PrintProgram(program, "b3.bpl"); // Run AA AliasAnalysis.AliasAnalysisResults res = AliasAnalysis.AliasAnalysis.DoAliasAnalysis(program); // allocation site of null var nil = res.allocationSites[ib.nullQuery.Name].FirstOrDefault(); Debug.Assert(nil != null); var deadcodeAssertId = 0; // add the assert false OR assume reach(true) var MkAssertFalse = new Func <int, PredicateCmd>(i => { var acmd = injectAssert ? BoogieAstFactory.MkAssert(Expr.False) as PredicateCmd : new AssumeCmd(Token.NoToken, new NAryExpr(Token.NoToken, new FunctionCall(ib.reach), new List <Expr> { Expr.True })) as PredicateCmd; acmd.Attributes = new QKeyValue(Token.NoToken, "deadcode", new List <object> { Expr.Literal(i) }, null); return(acmd); }); // build a map from AA allocation sites to allocation_site id var as2id = new Dictionary <string, HashSet <int> >(); foreach (var tup in ib.allocationSite2Func) { var asites = res.allocationSites[tup.Value.Name]; asites.Where(s => !as2id.ContainsKey(s)).Iter(s => as2id.Add(s, new HashSet <int>())); asites.Iter(s => as2id[s].Add(tup.Key)); } if (AliasAnalysis.AliasConstraintSolver.environmentPointersUnroll != 0) { Console.WriteLine("AA Warning: EnvironmentPointersUnroll is non-zero, which means that the dependency information for deadcode branches is not sound."); Console.WriteLine("AA Warning: We currently rely on: forall unknown allocation sites that return a, ReachableAllocationSitesViaFields(a) = {a}."); } // map from allocation_site to possible branches affected by it var depInfo = new Dictionary <int, HashSet <int> >(); program = inp.getProgram(); var id = 0; var added = 0; foreach (var impl in program.TopLevelDeclarations.OfType <Implementation>()) { foreach (var blk in impl.Blocks) { blk.Cmds.RemoveAll(c => (c is AssumeCmd) && QKeyValue.FindBoolAttribute((c as AssumeCmd).Attributes, "ForDeadCodeDetection")); var ncmds = new List <Cmd>(); for (int i = 0; i < blk.Cmds.Count; i++) { ncmds.Add(blk.Cmds[i]); var acmd = blk.Cmds[i] as AssumeCmd; if (acmd == null) { continue; } id++; if (!ib.id2Func.ContainsKey(id)) { continue; } var asites = res.allocationSites[ib.id2Func[id].Name]; //if (!Options.disbleDeadcodeOpt || !asites.Contains(nil) && asites.Count != 0) { var assertid = deadcodeAssertId++; ncmds.Add(MkAssertFalse(assertid)); // compute dependent allocations for this branch var dep = new HashSet <int>(); asites.Where(a => as2id.ContainsKey(a)) .Iter(a => dep.UnionWith(as2id[a])); dep.Where(d => !depInfo.ContainsKey(d)) .Iter(d => depInfo.Add(d, new HashSet <int>())); dep.Iter(d => depInfo[d].Add(assertid)); added++; } //i++; } blk.Cmds = ncmds; } } //BoogieUtil.PrintProgram(program, "progafter.bpl"); Console.WriteLine("For deadcode detection, we added {0} angelic assertions", added); return(Tuple.Create(program, depInfo)); }
static Program GetProgram(string filename) { var init = GetInputProgram(filename); if (Options.addInitialization) { ComputeandInitializeUninitializedLocals(init); } // Do some instrumentation for the input program if (Options.markAssumesAsSlic) { // Mark all assumes as "slic" var AddAnnotation = new Action <AssumeCmd>(ac => { ac.Attributes = new QKeyValue(Token.NoToken, "slic", new List <object>(), ac.Attributes); }); init.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds.OfType <AssumeCmd>() .Iter(AddAnnotation))); } // Only keep assertions in assertProc procedures if (Options.assertProcs != null) { (new Instrumentations.PruneNonAssertProcs(Options.assertProcs)).Visit(init); } // Inline procedures supplied with {:inline} annotation cba.Driver.InlineProcedures(init); // Remove {:inline} impls init.RemoveTopLevelDeclarations(decl => (decl is Implementation) && (BoogieUtil.checkAttrExists("inline", decl.Attributes) || BoogieUtil.checkAttrExists("inline", (decl as Implementation).Proc.Attributes))); // Restrict entrypoints to those provided explicitly (overrides any other way to providing entryPoints) if (Options.entryPointProcs != null) { //only consider the user provided entry points in command line Options.useHarnessTag = false; Options.useProvidedEntryPoints = true; init.TopLevelDeclarations.OfType <NamedDeclaration>() .Iter(d => d.Attributes = BoogieUtil.removeAttr("entrypoint", d.Attributes)); } var matchesEntryPointExclude = new Func <string, bool>(s => { return(Options.entryPointExcludes.Any(t => new System.Text.RegularExpressions.Regex(t).IsMatch(s))); }); //when both entryPointProcs == null and entryPointExcludes == null, it should not add any entrypointProcs if (Options.entryPointProcs != null || Options.entryPointExcludes != null) { init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => d is Procedure || d is Implementation) .Where(d => Options.entryPointProcs == null || Options.entryPointProcs.Contains(d.Name)) .Where(d => (Options.entryPointExcludes == null || !matchesEntryPointExclude(d.Name))) .Iter(d => d.AddAttribute("entrypoint")); } // Add {:entrypoint} to procs with {:harness} if (Options.useHarnessTag) { foreach (var decl in init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => QKeyValue.FindBoolAttribute(d.Attributes, "harness"))) { decl.AddAttribute("entrypoint"); } } // inlining introduces havoc statements; lets just delete them (TODO: make inlining not introduce redundant havoc statements) //foreach (var impl in init.TopLevelDeclarations.OfType<Implementation>()) //{ // impl.Blocks.Iter(blk => // blk.Cmds.RemoveAll(cmd => cmd is HavocCmd)); //} ReplaceHavocsWithNonDet(init); //Instrument to create the harness harnessInstrumentation = new Instrumentations.HarnessInstrumentation(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.useProvidedEntryPoints); harnessInstrumentation.DoInstrument(); //resolve+typecheck wo bothering about modSets CommandLineOptions.Clo.DoModSetAnalysis = true; init = BoogieUtil.ReResolveInMem(init); CommandLineOptions.Clo.DoModSetAnalysis = false; // Update mod sets BoogieUtil.DoModSetAnalysis(init); if (Options.AddMapSelectNonNullAssumptions) { (new Instrumentations.AssertMapSelectsNonNull()).Visit(init); } BoogieUtil.pruneProcs(init, AvnAnnotations.CORRAL_MAIN_PROC); if (Options.deadCodeDetect) { // Tag branches as reachable var tup = InstrumentBranches.Run(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.UseAliasAnalysisForAngelicAssertions, false); init = tup.Item1; // TODO: inject this information into the program itself DeadCodeBranchesDependencyInfo = tup.Item2; } return(init); }
static Program GetProgram(string filename) { var init = GetInputProgram(filename); if (Options.addInitialization) { ComputeandInitializeUninitializedLocals(init); } // Do some instrumentation for the input program if (Options.markAssumesAsSlic) { // Mark all assumes as "slic" var AddAnnotation = new Action <AssumeCmd>(ac => { ac.Attributes = new QKeyValue(Token.NoToken, "slic", new List <object>(), ac.Attributes); }); init.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds.OfType <AssumeCmd>() .Iter(AddAnnotation))); } // Inline procedures supplied with {:inline} annotation cba.Driver.InlineProcedures(init); // Remove {:inline} impls init.RemoveTopLevelDeclarations(decl => (decl is Implementation) && (BoogieUtil.checkAttrExists("inline", decl.Attributes) || BoogieUtil.checkAttrExists("inline", (decl as Implementation).Proc.Attributes))); // Add {:entrypoint} to procs with {:harness} if (Options.useHarnessTag) { foreach (var decl in init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => QKeyValue.FindBoolAttribute(d.Attributes, "harness"))) { decl.AddAttribute("entrypoint"); } } // inlining introduces havoc statements; lets just delete them (TODO: make inlining not introduce redundant havoc statements) foreach (var impl in init.TopLevelDeclarations.OfType <Implementation>()) { impl.Blocks.Iter(blk => blk.Cmds.RemoveAll(cmd => cmd is HavocCmd)); } //Instrument to create the harness harnessInstrumentation = new Instrumentations.HarnessInstrumentation(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.useProvidedEntryPoints); harnessInstrumentation.DoInstrument(); //resolve+typecheck wo bothering about modSets CommandLineOptions.Clo.DoModSetAnalysis = true; init = BoogieUtil.ReResolve(init); CommandLineOptions.Clo.DoModSetAnalysis = false; // Update mod sets BoogieUtil.DoModSetAnalysis(init); if (Options.AddMapSelectNonNullAssumptions) { (new Instrumentations.AssertMapSelectsNonNull()).Visit(init); } BoogieUtil.pruneProcs(init, AvnAnnotations.CORRAL_MAIN_PROC); if (Options.deadCodeDetect) { // Tag branches as reachable var tup = InstrumentBranches.Run(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.UseAliasAnalysisForAngelicAssertions, false); init = tup.Item1; // TODO: inject this information into the program itself DeadCodeBranchesDependencyInfo = tup.Item2; } return(init); }