// goto label1, label2; // // label1: // assume {:avn tok} !assertsPassed; // return; // // label2: // assume assertsPassed; // goto lab; // // lab: // // Inputs: the list of blocks being constructed; the current block being constructed. // End current block and adds two new blocks. // Returns "lab". private string addInstr(List <Block> instrumented, List <Cmd> curr, string curr_label, int token) { string lbl1 = getNewLabel(); string lbl2 = getNewLabel(); List <String> ssp = new List <String> { lbl1, lbl2 }; instrumented.Add(new Block(Token.NoToken, curr_label, curr, new GotoCmd(Token.NoToken, ssp))); string common_label = getNewLabel(); // assume (!assertsPassed) AssumeCmd cmd1 = new AssumeCmd(Token.NoToken, Expr.Not(Expr.Ident(assertsPassed))); if (token >= 0) { cmd1.Attributes = new QKeyValue(Token.NoToken, "avn", new List <object> { Expr.Literal(token) }, cmd1.Attributes); } // assume (assertsPassed) AssumeCmd cmd2 = new AssumeCmd(Token.NoToken, Expr.Ident(assertsPassed)); curr = new List <Cmd>(); curr.Add(cmd1); instrumented.Add(new Block(Token.NoToken, lbl1, curr, new ReturnCmd(Token.NoToken))); curr = new List <Cmd>(); curr.Add(cmd2); instrumented.Add(new Block(Token.NoToken, lbl2, curr, BoogieAstFactory.MkGotoCmd(common_label))); return(common_label); }
void Desugar(Variable lhs, Expr cond, Expr then, Expr els, ref List <Cmd> currCmds, ref Block currBlock, List <Block> newBlocks) { // create three new blocks var lab1 = GetNewLabel(); var lab2 = GetNewLabel(); var lab3 = GetNewLabel(); var tmp = CreateTmp(btype.Bool); currCmds.Add(BoogieAstFactory.MkVarEqExpr(tmp, cond)); // end current block currBlock.Cmds = currCmds; currBlock.TransferCmd = new GotoCmd(Token.NoToken, new List <string> { lab1, lab2 }); newBlocks.Add(currBlock); var blk1 = new Block(Token.NoToken, lab1, new List <Cmd>(), BoogieAstFactory.MkGotoCmd(lab3)); var blk2 = new Block(Token.NoToken, lab2, new List <Cmd>(), BoogieAstFactory.MkGotoCmd(lab3)); blk1.Cmds.AddRange( new List <Cmd> { BoogieAstFactory.MkAssume(Expr.Ident(tmp)), BoogieAstFactory.MkVarEqExpr(lhs, then) }); blk2.Cmds.AddRange( new List <Cmd> { BoogieAstFactory.MkAssume(Expr.Not(Expr.Ident(tmp))), BoogieAstFactory.MkVarEqExpr(lhs, els) }); newBlocks.Add(blk1); newBlocks.Add(blk2); currBlock = new Block(Token.NoToken, lab3, new List <Cmd>(), null); currCmds = new List <Cmd>(); }
private static void InjectCode(Implementation impl, int anyParamsPosition, QKeyValue anyParamsAttributes, int anyParamsPositionOut, QKeyValue anyParamsAttributesOut, Implementation procSig, InsertAtBeginningRule rule, Dictionary <Declaration, Expr> paramSubstitution) { //TODO handle anyParams in the OutParam case var doesAnyParamOccurInRhs = false; if (anyParamsPosition != int.MaxValue) { var anyParam = procSig.InParams[anyParamsPosition]; var oiv = new OccursInVisitor(anyParam); oiv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); doesAnyParamOccurInRhs = oiv.Success; } if (doesAnyParamOccurInRhs) { for (int i = anyParamsPosition; i < impl.InParams.Count; i++) { var p = impl.InParams[i]; // If attributes for the ##anyparams in the toMatch are given, we only insert code for those parameters of impl // with matching (subset) attributes // we look both in the implementation's and the procedure declaration's signature if (anyParamsAttributes == null || ExprMatchVisitor.AreAttributesASubset(anyParamsAttributes, impl.Proc.InParams[i].Attributes)) { if (!procSig.InParams[anyParamsPosition].TypedIdent.Type.Equals(p.TypedIdent.Type)) { continue; //skip parameters that don't match type } var id = new IdentifierExpr(Token.NoToken, p.Name, p.TypedIdent.Type, true); var substitution = new Dictionary <Declaration, Expr> { { procSig.InParams[anyParamsPosition], id } }; foreach (var kvp in paramSubstitution) { substitution.Add(kvp.Key, kvp.Value); } var sv = new SubstitionVisitor(substitution); var newCmds = sv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); if (impl.Blocks.Count > 0 && !QKeyValue.FindBoolAttribute(procSig.Attributes, ExprMatchVisitor.BoogieKeyWords.ReplaceImplementation)) { impl.Blocks.Insert(0, BoogieAstFactory.MkBlock(newCmds, BoogieAstFactory.MkGotoCmd(impl.Blocks.First().Label))); } else { impl.Blocks = new List <Block>(); impl.Blocks.Add( BoogieAstFactory.MkBlock(newCmds)); } } } } else { var sv = new SubstitionVisitor(paramSubstitution); var newCmds = sv.VisitCmdSeq(rule.ProcedureToMatchToInsertion[procSig]); if (impl.Blocks.Count > 0 && !QKeyValue.FindBoolAttribute(procSig.Attributes, ExprMatchVisitor.BoogieKeyWords.ReplaceImplementation)) { impl.Blocks.Insert(0, BoogieAstFactory.MkBlock(newCmds, BoogieAstFactory.MkGotoCmd(impl.Blocks.First().Label))); } else { impl.Blocks = new List <Block>(); impl.Blocks.Add( BoogieAstFactory.MkBlock(newCmds)); } } }
private PersistentCBAProgram instrument(PersistentCBAProgram pprogram, HashSet <string> candidates) { Debug.Assert(candidates.Count != 0); labelProcMap = new Dictionary <string, string>(); var program = pprogram.getProgram(); var nameImplMap = BoogieUtil.nameImplMapping(program); // Each candidate gets its own variable var procVars = new Dictionary <string, Variable>(); foreach (var str in candidates) { procVars.Add(str, new GlobalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "ep_var_" + str, Microsoft.Boogie.Type.Bool))); program.AddTopLevelDeclaration(procVars[str]); } // Add the new variables to each procedures' modifies clause foreach (var decl in program.TopLevelDeclarations) { if (decl is Implementation) { var impl = decl as Implementation; foreach (var str in candidates) { impl.Proc.Modifies.Add(new IdentifierExpr(Token.NoToken, procVars[str])); } } } // Instrument program foreach (var str in candidates) { var impl = nameImplMap[str]; var ncmds = new List <Cmd>(); ncmds.Add(BoogieAstFactory.MkVarEqConst(procVars[str], false)); ncmds.AddRange(impl.Blocks[0].Cmds); impl.Blocks[0].Cmds = ncmds; } // Instrument main. // -- Assign true to the new variables // -- Change the assert // (We assume that main only has one assert) var mainImpl = nameImplMap[pprogram.mainProcName]; var newCmds = new List <Cmd>(); foreach (var str in candidates) { newCmds.Add(BoogieAstFactory.MkVarEqConst(procVars[str], true)); } newCmds.AddRange(mainImpl.Blocks[0].Cmds); mainImpl.Blocks[0].Cmds = newCmds; // Find the assert Block blkWithAssert = null; AssertCmd assertCmd = null; bool found = false; foreach (var blk in mainImpl.Blocks) { found = false; foreach (var cmd in blk.Cmds) { if (cmd is AssertCmd) { assertCmd = cmd as AssertCmd; found = true; break; } } if (found) { blkWithAssert = blk; break; } } Debug.Assert(blkWithAssert != null); // Construct the new blocks var newLabs = new Dictionary <string, string>(); var restLab = getNewLabel(); foreach (var str in candidates) { newLabs.Add(str, getNewLabel()); var tcmds = new List <Cmd>(); tcmds.Add(new AssertCmd(Token.NoToken, Expr.Or(Expr.Ident(procVars[str]), assertCmd.Expr))); mainImpl.Blocks.Add(new Block(Token.NoToken, newLabs[str], tcmds, BoogieAstFactory.MkGotoCmd(restLab))); } // change blkWithAssert to include only commands upto the assert // Add the rest of commands to a new block found = false; newCmds = new List <Cmd>(); var newBlk = new Block(Token.NoToken, restLab, new List <Cmd>(), blkWithAssert.TransferCmd); foreach (Cmd cmd in blkWithAssert.Cmds) { if (cmd is AssertCmd) { found = true; continue; } if (!found) { newCmds.Add(cmd); } else { newBlk.Cmds.Add(cmd); } } blkWithAssert.Cmds = newCmds; var targets = new List <String>(newLabs.Values.ToArray()); blkWithAssert.TransferCmd = new GotoCmd(Token.NoToken, targets); mainImpl.Blocks.Add(newBlk); var ret = new PersistentCBAProgram(program, pprogram.mainProcName, pprogram.contextBound); //ret.writeToFile("ep_instrumented.bpl"); return(ret); }
private static List <Block> splitBlockForSourceInfo(Block block) { var ret = new List <Block>(); var curr = new List <Cmd>(); var label = block.Label; var origCmds = block.Cmds; var origTransfer = block.TransferCmd; if (origCmds.Count == 0) { ret.Add(block); return(ret); } // Lets construct the list of cmds for the input block -- this is // the list of cmds up to (and excluding): // -- The first cmd with source info that is not the 0^th cmd var cnt = 0; for (cnt = 0; cnt < origCmds.Count; cnt++) { if (hasSourceInfo(origCmds[cnt]) && cnt != 0) { break; } curr.Add(origCmds[cnt]); } if (cnt == origCmds.Count) { ret.Add(block); return(ret); } block.Cmds = curr; label = getNewLabel(); block.TransferCmd = BoogieAstFactory.MkGotoCmd(label); ret.Add(block); curr = new List <Cmd>(); // Now for the rest of the cmds while (cnt < origCmds.Count) { Debug.Assert(hasSourceInfo(origCmds[cnt])); curr.Add(origCmds[cnt]); cnt++; for (; cnt < origCmds.Count; cnt++) { if (hasSourceInfo(origCmds[cnt])) { break; } curr.Add(origCmds[cnt]); } var next = getNewLabel(); ret.Add(new Block(Token.NoToken, label, curr, BoogieAstFactory.MkGotoCmd(next))); label = next; curr = new List <Cmd>(); } ret.Last().TransferCmd = origTransfer; return(ret); }
private string addTraceRec(ErrorTrace trace) { Debug.Assert(trace.Blocks.Count != 0); // First, construct the procedure declaration: only a name change required string newName = getNewName(trace.procName); Procedure proc = nameToProc[trace.procName]; output.AddTopLevelDeclaration( new Procedure(Token.NoToken, newName, proc.TypeParameters, proc.InParams, proc.OutParams, proc.Requires, proc.Modifies, proc.Ensures, proc.Attributes)); // Now to peice together the commands from the implementation. We keep around // multiple blocks to make sure that trace mapping works out. var traceBlocks = new List <Block>(); Implementation impl = nameToImpl[trace.procName]; var labelToBlock = BoogieUtil.labelBlockMapping(impl); // These two need not agree. This happens when impl.Block[0] has // no commands. // Debug.Assert(impl.Blocks[0].Label == trace.Blocks[0].blockName); Debug.Assert(reachableViaEmptyBlocks(impl.Blocks[0].Label, labelToBlock).Contains(trace.Blocks[0].blockName)); for (int i = 0, n = trace.Blocks.Count; i < n; i++) { Block curr = labelToBlock[trace.Blocks[i].blockName]; Block traceBlock = new Block(); traceBlock.Cmds = new List <Cmd>(); traceBlock.Label = addIntToString(trace.Blocks[i].blockName, i); // (The "i" is to deal with loops) if (i != n - 1) { traceBlock.TransferCmd = BoogieAstFactory.MkGotoCmd(addIntToString(trace.Blocks[i + 1].blockName, i + 1)); } else { traceBlock.TransferCmd = new ReturnCmd(Token.NoToken); } tinfo.addTrans(newName, trace.Blocks[i].blockName, traceBlock.Label); #region Check consistency Debug.Assert(curr.Cmds.Count >= trace.Blocks[i].Cmds.Count); if (trace.Blocks[i].Cmds.Count != curr.Cmds.Count) { Debug.Assert((i == n - 1)); } if (curr.TransferCmd is ReturnCmd) { Debug.Assert(i == n - 1); } else if (curr.TransferCmd is GotoCmd) { List <String> targets = (curr.TransferCmd as GotoCmd).labelNames; // one of these targets should be the next label if (i != n - 1) { Debug.Assert(reachableViaEmptyBlocks(targets, labelToBlock).Contains(trace.Blocks[i + 1].blockName)); } } else { throw new InternalError("Unknown transfer command"); } #endregion // Index into trace.Blocks[i].Cmds int instrCount = -1; foreach (Cmd c in curr.Cmds) { instrCount++; if (instrCount == trace.Blocks[i].Cmds.Count) { break; } ErrorTraceInstr curr_instr = trace.Blocks[i].Cmds[instrCount]; if (curr_instr.info.isValid) { traceBlock.Cmds.Add(InstrumentationConfig.getFixedContextProc(curr_instr.info.executionContext)); newFixedContextProcs.Add(curr_instr.info.executionContext); } // Don't keep "fix context value" procs from the input program if (InstrumentationConfig.getFixedContextValue(c) != -1) { traceBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.True)); addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); continue; } // Don't keep "fix raise exception" procs from the input program if (InstrumentationConfig.isFixedRaiseExceptionProc(c)) { traceBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.True)); addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); continue; } if (addConcretization && c is HavocCmd && curr_instr.info != null && curr_instr.info.hasIntVar("si_arg") && (c as HavocCmd).Vars.Count > 0 && (c as HavocCmd).Vars[0].Decl.TypedIdent.Type.IsInt) { // concretize havoc-ed variable var val = curr_instr.info.getIntVal("si_arg"); traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst((c as HavocCmd).Vars[0].Decl, val)); addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); continue; } if (!(c is CallCmd)) { if (convertNonFailingAssertsToAssumes && c is AssertCmd && !(curr_instr.info is AssertFailInstrInfo)) { traceBlock.Cmds.Add(new AssumeCmd(c.tok, (c as AssertCmd).Expr, (c as AssertCmd).Attributes)); } else { traceBlock.Cmds.Add(c); } Debug.Assert(!curr_instr.isCall()); addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); continue; } Debug.Assert(curr_instr.isCall()); CallCmd cc = c as CallCmd; CallInstr call_instr = curr_instr as CallInstr; if (!nameToImpl.ContainsKey(cc.Proc.Name) || !call_instr.hasCalledTrace) { // This is a call to a procedure without implementation; skip; calledProcsNoImpl.Add(cc.Proc.Name); traceBlock.Cmds.Add(c); Debug.Assert(!call_instr.hasCalledTrace); if (addConcretization && cc.Outs.Count == 1 && call_instr.info.hasVar("si_arg")) { if (!addConcretizationAsConstants) { if (call_instr.info.hasBoolVar("si_arg")) { traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst(cc.Outs[0].Decl, call_instr.info.getBoolVal("si_arg"))); } else if (call_instr.info.hasIntVar("si_arg")) { traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst(cc.Outs[0].Decl, call_instr.info.getIntVal("si_arg"))); } else { Debug.Assert(false); } } else { // create a constant that is equal to this literal, then use the constant // for concretization // do we use a specific name for the constant? var constantName = QKeyValue.FindStringAttribute(cc.Attributes, ConcretizeConstantNameAttr); if (constantName == null) { constantName = ""; } var constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("alloc_{0}__{1}", constantName, const_counter), cc.Outs[0].Decl.TypedIdent.Type), false); const_counter++; traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqVar(cc.Outs[0].Decl, constant)); output.AddTopLevelDeclaration(constant); if (call_instr.info.hasIntVar("si_arg")) { output.AddTopLevelDeclaration(new Axiom(Token.NoToken, Expr.Eq(Expr.Ident(constant), Expr.Literal(call_instr.info.getIntVal("si_arg"))))); } else if (call_instr.info.hasVar("si_arg") && cc.Outs[0].Decl.TypedIdent.Type.IsCtor) { uvalueToConstants.InitAndAdd(call_instr.info.getVal("si_arg").ToString(), constant); } var id = QKeyValue.FindIntAttribute(cc.Attributes, ConcretizeCallIdAttr, -1); concretizeConstantToCall.Add(constant.Name, id); } } addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); continue; } Debug.Assert(call_instr.calleeTrace.procName == cc.Proc.Name); var callee = addTraceRec(call_instr.calleeTrace); var newcmd = new CallCmd(Token.NoToken, callee, cc.Ins, cc.Outs, cc.Attributes, cc.IsAsync); traceBlock.Cmds.Add(newcmd); addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds); } traceBlocks.Add(traceBlock); } Debug.Assert(traceBlocks.Count != 0); if (trace.raisesException) { var exitblk = traceBlocks.Last(); exitblk.Cmds.Add(InstrumentationConfig.getFixedRaiseExceptionProc()); addRaiseExceptionProcDecl = true; } // Add the implementation to output //var block = new Block(Token.NoToken, trace.Blocks[0].blockName, traceCmdSeq, new ReturnCmd(Token.NoToken)); //List<Block> blocks = new List<Block>(); //blocks.Add(block); //tinfo.addTrans(newName, trace.Blocks[0].blockName, trace.Blocks[0].blockName); tinfo.addProcNameTrans(trace.procName, newName); output.AddTopLevelDeclaration( new Implementation(Token.NoToken, newName, impl.TypeParameters, impl.InParams, impl.OutParams, impl.LocVars, traceBlocks, QKeyValue.FindStringAttribute(impl.Attributes, "origRTname") == null ? new QKeyValue(Token.NoToken, "origRTname", new List <object> { impl.Name }, impl.Attributes) : impl.Attributes)); return(newName); }
// Short-circuit the chain of returns produced by raiseException public void optimizeRaiseExceptionInstrumentation(CBAProgram program) { var procMap = BoogieUtil.nameImplMapping(program); var mainImpl = procMap[program.mainProcName]; var labelBlockMap = BoogieUtil.labelBlockMapping(mainImpl); // For each block, check if the first statement is "assume raiseException" foreach (var blk in mainImpl.Blocks) { if (blk.Cmds.Count == 0) { continue; } var cmd = blk.Cmds[0]; if (!(cmd is AssumeCmd)) { continue; } var expr = (cmd as AssumeCmd).Expr; if (expr is IdentifierExpr) { var v = (expr as IdentifierExpr).Decl; if (v.Name != "raiseException") { continue; } } else { continue; } // Yup, its "assume raiseException" -- follow the chain of gotos through empty blocks var lab = getSingleSucc(blk.TransferCmd); if (lab == null) { continue; } var b = labelBlockMap[lab]; var chainLen = 0; /* Heuristic, possibly unsound: some blocks have a single statement that contains * an assignment for the return value. Note that once raiseException has been raised, * no return value is needed. */ while (b.Cmds.Count <= 1) { var next = getSingleSucc(b.TransferCmd); if (next == null) { break; } lab = next; b = labelBlockMap[lab]; chainLen++; } blk.TransferCmd = BoogieAstFactory.MkGotoCmd(lab); if (chainLen != 0) { Log.WriteLine(Log.Debug, "raiseException chain shortened by " + chainLen.ToString()); } } }
// If the impl has multiple calls: // "call foo(args); return;" // with the same args, then merge these calls into one public static string mergeRecCalls(Implementation impl) { // find the recursive calls var rBlocks = new List <Block>(); foreach (var blk in impl.Blocks) { var rc = blk.Cmds .OfType <CallCmd>() .Where(cc => cc.callee == impl.Name); if (!rc.Any()) { continue; } if (rc.Count() != 1) { return(null); } // make sure recursive call is last in the block var rcall = rc.First(); if (rcall != blk.Cmds.Last()) { return(null); } // check return if (!(blk.TransferCmd is ReturnCmd)) { return(null); } rBlocks.Add(blk); } if (rBlocks.Count <= 1) { return(null); } // grab the rec calls var recCalls = new Dictionary <string, CallCmd>(); rBlocks.Iter(blk => recCalls.Add(blk.Label, blk.Cmds.Last() as CallCmd)); // prune attributes var origAttr = new Dictionary <string, QKeyValue>(); recCalls.Iter(kvp => origAttr.Add(kvp.Key, kvp.Value.Attributes)); recCalls.Values .Iter(cc => cc.Attributes = BoogieUtil.removeAttrs(new HashSet <string> { "si_unique_call", "si_old_unique_call" }, cc.Attributes)); // check that all recursive calls have the same arguments // Check 1: ToString var callStr = new HashSet <string>(); recCalls.Values .Iter(cc => { var str = new System.IO.StringWriter(); var tt = new TokenTextWriter(str); cc.Emit(tt, 0); tt.Close(); callStr.Add(str.ToString()); str.Close(); }); if (callStr.Count != 1) { // restore attributes recCalls .Iter(kvp => kvp.Value.Attributes = origAttr[kvp.Key]); return(null); } // Check 2: AST var rc1 = recCalls[recCalls.Keys.First()]; if ( recCalls.Values .Where(c => !IsSame(rc1, c)) .Any()) { // restore attributes recCalls .Iter(kvp => kvp.Value.Attributes = origAttr[kvp.Key]); return(null); } // Merge rc1.Attributes = origAttr[recCalls.Keys.First()]; var nb = BoogieAstFactory.MkBlock(rc1); rBlocks.Iter(blk => blk.Cmds.Remove(blk.Cmds.Last())); rBlocks.Iter(blk => { var gc = BoogieAstFactory.MkGotoCmd(nb.Label); gc.labelTargets = new List <Block>(); gc.labelTargets.Add(nb); blk.TransferCmd = gc; }); impl.Blocks.Add(nb); return(nb.Label); }