private void CreateMainProcedure(Function reach) { //blocks List <Block> mainBlocks = new List <Block>(); List <Variable> locals = new List <Variable>(); HashSet <Constant> blockCallConsts = new HashSet <Constant>(); foreach (Implementation impl in prog.TopLevelDeclarations.Where(x => x is Implementation)) { // skip this impl if it is not marked as an entrypoint if (useProvidedEntryPoints && !QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "entrypoint")) { continue; } impl.Attributes = BoogieUtil.removeAttr("entrypoint", impl.Attributes); impl.Proc.Attributes = BoogieUtil.removeAttr("entrypoint", impl.Proc.Attributes); // skip initialization procedure if (QKeyValue.FindBoolAttribute(impl.Attributes, AvnAnnotations.InitialializationProcAttr) || QKeyValue.FindBoolAttribute(impl.Proc.Attributes, AvnAnnotations.InitialializationProcAttr)) { continue; } entrypoints.Add(impl.Name); //allocate params var args = new List <Variable>(); var rets = new List <Variable>(); impl.OutParams.ForEach(v => rets.Add(BoogieAstFactory.MkLocal(v.Name + "_" + impl.Name, v.TypedIdent.Type))); if (Options.allocateParameters) { // use impl.Proc here to pickup scalar/pointer attributes impl.Proc.InParams.ForEach(v => { var l = BoogieAstFactory.MkLocal(v.Name + "_" + impl.Name, v.TypedIdent.Type); // We are delibrately dropping the attributes so that // all parameters are initialized by allocation //l.Attributes = v.Attributes; args.Add(l); }); locals.AddRange(args); } else { impl.Proc.InParams.ForEach(v => { var g = BoogieAstFactory.MkGlobal(v.Name + "_" + impl.Name, v.TypedIdent.Type); //g.Attributes = v.Attributes; args.Add(g); }); globalParams.AddRange(args); } locals.AddRange(rets); //call var blockCallConst = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "__block_call_" + impl.Name, btype.Bool), false); blockCallConsts.Add(blockCallConst); blockEntryPointConstants[blockCallConst.Name] = impl.Name; impl2BlockingConstant[impl.Name] = blockCallConst; var blockCallAssumeCmd = new AssumeCmd(Token.NoToken, IdentifierExpr.Ident(blockCallConst)); var cmds = new List <Cmd>(); cmds.Add(blockCallAssumeCmd); if (Options.allocateParameters) // allocate parameters if option is enabled { var argMallocCmds = AllocatePointersAsUnknowns(args); cmds.AddRange(argMallocCmds); } // The beginning of an entry point must be reachable: assume reach(true); cmds.Add(new AssumeCmd(Token.NoToken, new NAryExpr(Token.NoToken, new FunctionCall(reach), new List <Expr> { Expr.True }))); var callCmd = new CallCmd(Token.NoToken, impl.Name, args.ConvertAll(x => (Expr)IdentifierExpr.Ident(x)), rets.ConvertAll(x => IdentifierExpr.Ident(x))); callCmd.Attributes = new QKeyValue(Token.NoToken, AvUtil.AvnAnnotations.AvhEntryPointAttr, new List <object>(), callCmd.Attributes); cmds.Add(callCmd); //succ var txCmd = new ReturnCmd(Token.NoToken); var blk = BoogieAstFactory.MkBlock(cmds, txCmd); mainBlocks.Add(blk); } foreach (Procedure proc in prog.TopLevelDeclarations.OfType <Procedure>()) { proc.Attributes = BoogieUtil.removeAttr("entrypoint", proc.Attributes); } // add global variables to prog // globals.Iter(x => prog.AddTopLevelDeclaration(x)); //add the constants to the prog blockCallConsts.Iter(x => prog.AddTopLevelDeclaration(x)); //TODO: get globals of type refs/pointers and maps var initCmd = (AssumeCmd)BoogieAstFactory.MkAssume(Expr.True); var globalCmds = new List <Cmd>() { initCmd }; //add call to corralExtraInit var init = Instrumentations.GetEnvironmentAssumptionsProc(prog); if (init != null && !Options.DelayInitialization) { globalCmds.Add(BoogieAstFactory.MkCall(init, new List <Expr>(), new List <Variable>())); } // Dont initialize Boogie instrumentation variables prog.GlobalVariables .Where(g => g.Name == "alloc" || BoogieUtil.checkAttrExists(AvnAnnotations.AllocatorVarAttr, g.Attributes)) .Where(g => !BoogieUtil.checkAttrExists("scalar", g.Attributes)) .Iter(g => g.AddAttribute("scalar")); // initialize globals prog.GlobalVariables .Where(g => g.Name != "alloc" && !BoogieUtil.checkAttrExists(AvnAnnotations.AllocatorVarAttr, g.Attributes)) .Iter(g => g.Attributes = BoogieUtil.removeAttrs(new HashSet <string> { "scalar", "pointer" }, g.Attributes)); globalCmds.AddRange(AllocatePointersAsUnknowns(prog.GlobalVariables.Select(x => (Variable)x).ToList())); if (init != null && Options.DelayInitialization) { globalCmds.Add(BoogieAstFactory.MkCall(init, new List <Expr>(), new List <Variable>())); } // globals for parameters prog.AddTopLevelDeclarations(globalParams); //first block var transferCmd = mainBlocks.Count > 0 ? (TransferCmd)(new GotoCmd(Token.NoToken, mainBlocks)) : (TransferCmd)(new ReturnCmd(Token.NoToken)); Block blkStart = new Block(Token.NoToken, "CorralMainStart", globalCmds, transferCmd); var blocks = new List <Block>(); blocks.Add(blkStart); blocks.AddRange(mainBlocks); var mainProcImpl = BoogieAstFactory.MkImpl(AvnAnnotations.CORRAL_MAIN_PROC, new List <Variable>(), new List <Variable>(), locals, blocks); mainProcImpl[0].AddAttribute("entrypoint"); prog.AddTopLevelDeclarations(mainProcImpl); }
//Change the body of any stub that returns a pointer into calling unknown() //TODO: only do this for procedures with a single return with a pointer type private void MkStubImplementation(List <Implementation> stubImpls, Procedure p) { List <Cmd> cmds = new List <Cmd>(); List <Variable> localVars = new List <Variable>(); stubs.Add(p.Name); foreach (var op in p.OutParams) { if (IsPointerVariable(op)) { cmds.Add(AllocatePointerAsUnknown(op)); } else { // Avoid using Havoc -- we'll let this fall on the floor as an // uninitialized variable. AVN will take care of concretizing it //cmds.Add(BoogieAstFactory.MkHavocVar(op)); } } foreach (var v in p.Modifies.Select(ie => ie.Decl)) { if (IsPointerVariable(v)) { cmds.Add(AllocatePointerAsUnknown(v)); } else { // unsupported Console.WriteLine("Warning: demonic havoc of global {0} in {1}", v.Name, p.Name); } } foreach (var ip in p.InParams) { if (!BoogieUtil.checkAttrExists("ref", ip.Attributes)) { continue; } string mapName = QKeyValue.FindStringAttribute(ip.Attributes, "ref"); if (mapName == null) { Utils.Print(String.Format("Expecting a map <name> with {:ref <name>} annotation on procedure {0}", p.Name), Utils.PRINT_TAG.AV_WARNING); continue; } var mapVars = prog.TopLevelDeclarations.OfType <Variable>().Where(x => x.Name == mapName && x.TypedIdent.Type.IsMap); if (mapVars.Count() != 1) { Utils.Print(String.Format("Mapname {0} provided in {{:ref}} for parameter {1} for procedure {2} has {3} matches, expecting exactly 1 match", mapName, ip.Name, p.Name, mapVars.Count()), Utils.PRINT_TAG.AV_WARNING); continue; } var tmpVar = BoogieAstFactory.MkLocal("__tmp_" + ip.Name, ip.TypedIdent.Type); localVars.Add(tmpVar); cmds.Add(AllocatePointerAsUnknown(tmpVar)); cmds.Add(BoogieAstFactory.MkMapAssign(mapVars.First(), IdentifierExpr.Ident(ip), IdentifierExpr.Ident(tmpVar))); } if (cmds.Count == 0) { return; //don't create a body if no statements } var blk = BoogieAstFactory.MkBlock(cmds, new ReturnCmd(Token.NoToken)); var blks = new List <Block>() { blk }; //don't insert the proc as it already exists var impl = BoogieAstFactory.MkImpl(p.Name, DropAnnotations(p.InParams), DropAnnotations(p.OutParams), new List <Variable>(), blks); ((Implementation)impl[1]).LocVars.AddRange(localVars); stubImpls.Add((Implementation)impl[1]); }