//Function to produce memory allocation as boogie reference types using "alloc" private void GenerateGlobalProcedureAllocMany() { // generate the internal one without base constructors string procName = "HavocAllocMany"; List <BoogieVariable> inParams = new List <BoogieVariable>(); List <BoogieVariable> outParams = new List <BoogieVariable>(); List <BoogieAttribute> attributes = new List <BoogieAttribute>(); if (Flags_HelperClass.GenerateInlineAttributes) { attributes.Add(new BoogieAttribute("inline", 1)); } ; BoogieProcedure procedure = new BoogieProcedure(procName, inParams, outParams, attributes); context.getProgram.AddBoogieDeclaration(procedure); var oldAlloc = new BoogieLocalVariable(new BoogieTypedIdent("oldAlloc", new BoogieMapType(BoogieType.Ref, BoogieType.Bool))); List <BoogieVariable> localVars = new List <BoogieVariable>() { oldAlloc }; BoogieStmtList procBody = new BoogieStmtList(); BoogieIdentifierExpr oldAllocIdentExpr = new BoogieIdentifierExpr("oldAlloc"); BoogieIdentifierExpr allocIdentExpr = new BoogieIdentifierExpr("Alloc"); // oldAlloc = Alloc procBody.AddStatement(new BoogieAssignCmd(oldAllocIdentExpr, allocIdentExpr)); // havoc Alloc procBody.AddStatement(new BoogieHavocCmd(allocIdentExpr)); var qVar = QVarGenerator.NewQVar(0, 0); BoogieMapSelect allocMapSelect = new BoogieMapSelect(allocIdentExpr, qVar); BoogieMapSelect oldAllocMapSelect = new BoogieMapSelect(oldAllocIdentExpr, qVar); BoogieExpr allocAssumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.IMP, oldAllocMapSelect, allocMapSelect); procBody.AddStatement(new BoogieAssumeCmd(new BoogieQuantifiedExpr(true, new List <BoogieIdentifierExpr>() { qVar }, new List <BoogieType>() { BoogieType.Ref }, allocAssumeExpr))); BoogieImplementation implementation = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.getProgram.AddBoogieDeclaration(implementation); }
private BoogieStmtList GenerateHavocBlock(ContractDefinition contract, List <BoogieVariable> localVars) { BoogieStmtList stmtList = new BoogieStmtList(); foreach (BoogieVariable localVar in localVars) { string varName = localVar.TypedIdent.Name; if (!varName.Equals("this")) { stmtList.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(varName))); } } return(stmtList); }
private BoogieStmtList HavocLocals(List <BoogieVariable> locals) { BoogieStmtList stmtList = new BoogieStmtList(); foreach (BoogieVariable localVar in locals) { string varName = localVar.TypedIdent.Name; if (!varName.Equals("this")) { stmtList.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(varName))); } } return(stmtList); }
private BoogieWhileCmd GenerateCorralWhileLoop(ContractDefinition contract) { BoogieStmtList body = new BoogieStmtList(); body.AddStatement(GenerateCorralCall(contract)); List <BoogiePredicateCmd> candidateInvs = new List <BoogiePredicateCmd>(); // add the contract invariant if present if (contractInvariants.ContainsKey(contract.Name)) { contractInvariants[contract.Name].ForEach(x => candidateInvs.Add(new BoogieLoopInvCmd(x))); } return(new BoogieWhileCmd(new BoogieLiteralExpr(true), body, candidateInvs)); }
//Generate Fresh Procedure Boogie Type and add as new reference to BoogieProgram private void BuildGlobalProcedureFresh() { // generate the internal one without base constructors string procName = "FreshRefGenerator"; List <BoogieVariable> inParams = new List <BoogieVariable>(); var outVar = new BoogieFormalParam(new BoogieTypedIdent("newRef", BoogieType.Ref)); List <BoogieVariable> outParams = new List <BoogieVariable>() { outVar }; List <BoogieAttribute> attributes = new List <BoogieAttribute>(); if (Flags_HelperClass.GenerateInlineAttributes) { attributes.Add(new BoogieAttribute("inline", 1)); } ; BoogieProcedure procedure = new BoogieProcedure(procName, inParams, outParams, attributes); context.getProgram.AddBoogieDeclaration(procedure); List <BoogieVariable> localVars = new List <BoogieVariable>(); BoogieStmtList procBody = new BoogieStmtList(); var outVarIdentifier = new BoogieIdentifierExpr("newRef"); BoogieIdentifierExpr allocIdentExpr = new BoogieIdentifierExpr("Alloc"); // havoc tmp; procBody.AddStatement(new BoogieHavocCmd(outVarIdentifier)); // assume Alloc[tmp] == false; BoogieMapSelect allocMapSelect = new BoogieMapSelect(allocIdentExpr, outVarIdentifier); BoogieExpr allocAssumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, allocMapSelect, new BoogieLiteralExpr(false)); procBody.AddStatement(new BoogieAssumeCmd(allocAssumeExpr)); // Alloc[tmp] := true; procBody.AddStatement(new BoogieAssignCmd(allocMapSelect, new BoogieLiteralExpr(true))); // assume tmp != null procBody.AddStatement(new BoogieAssumeCmd( new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.NEQ, outVarIdentifier, new BoogieIdentifierExpr("null")))); BoogieImplementation implementation = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.getProgram.AddBoogieDeclaration(implementation); }
private void GenerateStructConstructors(ContractDefinition contract, StructDefinition structDefn) { // generate the internal one without base constructors string procName = structDefn.CanonicalName + "_ctor"; List <BoogieVariable> inParams = new List <BoogieVariable>(); inParams.AddRange(TransUtils.GetDefaultInParams()); foreach (var member in structDefn.Members) { Debug.Assert(!member.TypeDescriptions.IsStruct(), "Do no handle nested structs yet!"); var formalType = TransUtils.GetBoogieTypeFromSolidityTypeName(member.TypeName); var formalName = member.Name; inParams.Add(new BoogieFormalParam(new BoogieTypedIdent(formalName, formalType))); } List <BoogieVariable> outParams = new List <BoogieVariable>(); List <BoogieAttribute> attributes = new List <BoogieAttribute>(); if (context.TranslateFlags.GenerateInlineAttributes) { attributes.Add(new BoogieAttribute("inline", 1)); } ; BoogieProcedure procedure = new BoogieProcedure(procName, inParams, outParams, attributes); context.Program.AddDeclaration(procedure); List <BoogieVariable> localVars = new List <BoogieVariable>(); BoogieStmtList procBody = new BoogieStmtList(); foreach (var member in structDefn.Members) { //f[this] = f_arg Debug.Assert(!member.TypeDescriptions.IsStruct(), "Do no handle nested structs yet!"); var mapName = member.Name + "_" + structDefn.CanonicalName; var formalName = member.Name; var mapSelectExpr = new BoogieMapSelect(new BoogieIdentifierExpr(mapName), new BoogieIdentifierExpr("this")); procBody.AddStatement(new BoogieAssignCmd(mapSelectExpr, new BoogieIdentifierExpr(member.Name))); } BoogieImplementation implementation = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.Program.AddDeclaration(implementation); }
private BoogieStmtList GenerateHavocBlock(ContractDefinition contract, List <BoogieVariable> localVars) { BoogieStmtList stmtList = new BoogieStmtList(); foreach (BoogieVariable localVar in localVars) { string varName = localVar.TypedIdent.Name; if (!varName.Equals("this")) { stmtList.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(varName))); } } if (context.TranslateFlags.InstrumentGas) { TransUtils.havocGas(stmtList); } var nowVar = new BoogieIdentifierExpr("now"); var tmpNowVar = new BoogieIdentifierExpr("tmpNow"); stmtList.AddStatement(new BoogieAssignCmd(tmpNowVar, nowVar)); stmtList.AddStatement(new BoogieHavocCmd(nowVar)); stmtList.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GT, nowVar, tmpNowVar))); stmtList.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.NEQ, new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("null")))); if (context.TranslateFlags.NoTxnsFromContract) { foreach (var contractDef in context.ContractDefinitions) { BoogieIdentifierExpr contractIdent = new BoogieIdentifierExpr(contractDef.Name); stmtList.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation( BoogieBinaryOperation.Opcode.NEQ, new BoogieMapSelect(new BoogieIdentifierExpr("DType"), new BoogieIdentifierExpr("msgsender_MSG")), contractIdent))); } stmtList.AddStatement((new BoogieAssignCmd(new BoogieMapSelect(new BoogieIdentifierExpr("Alloc"), new BoogieIdentifierExpr("msgsender_MSG")), new BoogieLiteralExpr(true)))); } return(stmtList); }
private void GenerateBoogieHarnessForContract(ContractDefinition contract, Dictionary <int, BoogieExpr> houdiniVarMap) { string harnessName = "BoogieEntry_" + contract.Name; List <BoogieVariable> inParams = new List <BoogieVariable>(); List <BoogieVariable> outParams = new List <BoogieVariable>(); BoogieProcedure harness = new BoogieProcedure(harnessName, inParams, outParams); context.Program.AddDeclaration(harness); List <BoogieVariable> localVars = CollectLocalVars(contract); BoogieStmtList harnessBody = new BoogieStmtList(); harnessBody.AddStatement(GenerateDynamicTypeAssumes(contract)); GenerateConstructorCall(contract).ForEach(x => harnessBody.AddStatement(x)); harnessBody.AddStatement(GenerateWhileLoop(contract, houdiniVarMap, localVars)); BoogieImplementation harnessImpl = new BoogieImplementation(harnessName, inParams, outParams, localVars, harnessBody); context.Program.AddDeclaration(harnessImpl); }
private void GenerateCorralChoiceProcForContract(ContractDefinition contract) { string procName = "CorralChoice_" + contract.Name; List <BoogieVariable> inParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("this", BoogieType.Ref)), }; List <BoogieVariable> outParams = new List <BoogieVariable>(); BoogieProcedure harness = new BoogieProcedure(procName, inParams, outParams); context.Program.AddDeclaration(harness); List <BoogieVariable> localVars = RemoveThisFromVariables(CollectLocalVars(contract)); BoogieStmtList procBody = GenerateHavocBlock(contract, localVars); procBody.AddStatement(GenerateChoiceBlock(contract)); BoogieImplementation procImpl = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.Program.AddDeclaration(procImpl); }
private BoogieStmtList CreateBodyOfSend(List <BoogieVariable> inParams, List <BoogieVariable> outParams, string fbProcName) { var fromIdExp = new BoogieIdentifierExpr(inParams[0].Name); var amtIdExp = new BoogieIdentifierExpr(inParams[2].Name); var guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), fromIdExp), amtIdExp); // call FallbackDispatch(from, to, amount) var toIdExpr = new BoogieIdentifierExpr(inParams[1].Name); var callStmt = new BoogieCallCmd( fbProcName, new List <BoogieExpr>() { fromIdExp, toIdExpr, amtIdExp }, new List <BoogieIdentifierExpr>() ); var thenBody = new BoogieStmtList(); var successIdExp = new BoogieIdentifierExpr(outParams[0].Name); thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balFrom = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[0].Name)); var balTo = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[1].Name)); var msgVal = new BoogieIdentifierExpr(inParams[2].Name); //balance[msg.sender] = balance[msg.sender] - msg.value thenBody.AddStatement(new BoogieAssignCmd(balFrom, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balFrom, msgVal))); //balance[this] = balance[this] + msg.value thenBody.AddStatement(new BoogieAssignCmd(balTo, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balTo, msgVal))); thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); thenBody.AddStatement(callStmt); thenBody.AddStatement(new BoogieAssignCmd(successIdExp, new BoogieLiteralExpr(true))); var elseBody = new BoogieAssignCmd(successIdExp, new BoogieLiteralExpr(false)); return(BoogieStmtList.MakeSingletonStmtList(new BoogieIfCmd(guard, thenBody, BoogieStmtList.MakeSingletonStmtList(elseBody)))); }
private BoogieWhileCmd GenerateCorralWhileLoop(ContractDefinition contract) { BoogieStmtList body = new BoogieStmtList(); string callee = "CorralChoice_" + contract.Name; List <BoogieExpr> inputs = new List <BoogieExpr>() { new BoogieIdentifierExpr("this"), }; body.AddStatement(new BoogieCallCmd(callee, inputs, null)); List <BoogiePredicateCmd> candidateInvs = new List <BoogiePredicateCmd>(); // add the contract invariant if present if (contractInvariants.ContainsKey(contract.Name)) { contractInvariants[contract.Name].ForEach(x => candidateInvs.Add(new BoogieLoopInvCmd(x))); } return(new BoogieWhileCmd(new BoogieLiteralExpr(true), body, candidateInvs)); }
private void GenerateCorralHarnessForContract(ContractDefinition contract) { string harnessName = "CorralEntry_" + contract.Name; List <BoogieVariable> inParams = new List <BoogieVariable>(); List <BoogieVariable> outParams = new List <BoogieVariable>(); BoogieProcedure harness = new BoogieProcedure(harnessName, inParams, outParams); context.Program.AddDeclaration(harness); List <BoogieVariable> localVars = new List <BoogieVariable> { new BoogieLocalVariable(new BoogieTypedIdent("this", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgsender_MSG", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgvalue_MSG", BoogieType.Int)), }; if (context.IsConstructorDefined(contract)) { FunctionDefinition ctor = context.GetConstructorByContract(contract); localVars.AddRange(GetParamsOfFunction(ctor)); } BoogieStmtList harnessBody = new BoogieStmtList(); harnessBody.AddStatement(GenerateDynamicTypeAssumes(contract)); GenerateConstructorCall(contract).ForEach(x => harnessBody.AddStatement(x)); if (context.TranslateFlags.ModelReverts) { BoogieExpr assumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, new BoogieIdentifierExpr("revert")); if (context.TranslateFlags.InstrumentGas) { assumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, assumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } harnessBody.AddStatement(new BoogieAssumeCmd(assumePred)); } harnessBody.AddStatement(GenerateCorralWhileLoop(contract)); BoogieImplementation harnessImpl = new BoogieImplementation(harnessName, inParams, outParams, localVars, harnessBody); context.Program.AddDeclaration(harnessImpl); }
private BoogieWhileCmd GenerateWhileLoop(ContractDefinition contract, Dictionary <int, BoogieExpr> houdiniVarMap, List <BoogieVariable> localVars) { // havoc all local variables except `this' BoogieStmtList body = GenerateHavocBlock(contract, localVars); // generate the choice block body.AddStatement(GenerateChoiceBlock(contract)); // generate candidate invariants for Houdini List <BoogiePredicateCmd> candidateInvs = new List <BoogiePredicateCmd>(); foreach (int id in houdiniVarMap.Keys) { BoogieIdentifierExpr houdiniVar = new BoogieIdentifierExpr(GetHoudiniVarName(id, contract)); BoogieExpr candidateInv = houdiniVarMap[id]; BoogieExpr invExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.IMP, houdiniVar, candidateInv); BoogieLoopInvCmd invCmd = new BoogieLoopInvCmd(invExpr); candidateInvs.Add(invCmd); } return(new BoogieWhileCmd(new BoogieLiteralExpr(true), body, candidateInvs)); }
public static BoogieStmtList constrainVarValues(TranslatorContext context, VariableDeclaration var, BoogieIdentifierExpr boogieVar) { BoogieStmtList stmts = new BoogieStmtList(); if (context.TranslateFlags.UseModularArithmetic) { if (var.TypeDescriptions.IsUintWSize(null, out uint uintSize)) { BigInteger maxUIntValue = (BigInteger)Math.Pow(2, uintSize); BoogieBinaryOperation lower = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, boogieVar, new BoogieLiteralExpr(BigInteger.Zero)); BoogieBinaryOperation upper = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, boogieVar, new BoogieLiteralExpr(maxUIntValue)); stmts.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, lower, upper))); } else if (var.TypeDescriptions.IsIntWSize(out uint intSize)) { BigInteger maxIntValue = (BigInteger)Math.Pow(2, intSize); BoogieBinaryOperation lower = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, boogieVar, new BoogieLiteralExpr(-maxIntValue)); BoogieBinaryOperation upper = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, boogieVar, new BoogieLiteralExpr(maxIntValue)); stmts.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, lower, upper))); } } return(stmts); }
public void Generate() { // Collect Global Variables. HashSet <BoogieGlobalVariable> globals = new HashSet <BoogieGlobalVariable>(); foreach (var decl in context.Program.Declarations) { if (decl is BoogieGlobalVariable) { var g = (BoogieGlobalVariable)decl; if (mustHaveShadow(g.Name)) { globals.Add(g); } } } // Generate shadow state. foreach (var g in globals) { var varName = g.TypedIdent.Name; BoogieTypedIdent shadowGlobal = new BoogieTypedIdent("__tmp__" + varName, g.TypedIdent.Type); BoogieGlobalVariable shadowGlobalDecl = new BoogieGlobalVariable(shadowGlobal); context.Program.AddDeclaration(shadowGlobalDecl); shadowGlobals.Add(varName, shadowGlobalDecl); } // Duplicate and rename methods. Dictionary <string, BoogieImplementation> proceduresWithImpl = new Dictionary <string, BoogieImplementation>(); procsWiltImplNames = proceduresWithImpl.Keys; foreach (var decl in context.Program.Declarations) { if (decl is BoogieImplementation) { var boogieImpl = ((BoogieImplementation)decl); if (proceduresInProgram.ContainsKey(boogieImpl.Name)) { proceduresWithImpl.Add(boogieImpl.Name, boogieImpl); } } } Dictionary <string, BoogieProcedure> failProcedures = new Dictionary <string, BoogieProcedure>(); foreach (var implPair in proceduresWithImpl) { BoogieProcedure proc = proceduresInProgram[implPair.Key]; if (isPublic(proc) || isConstructor(proc.Name)) { // If public maintain original definition as the wrapper. BoogieProcedure successVersion = duplicateProcedure(proc, "success", true); //BoogieImplementation successImpl = duplicateImplementation(implPair.Value, "success"); context.Program.AddDeclaration(successVersion); //context.Program.AddDeclaration(successImpl); BoogieProcedure failVersion = duplicateProcedure(proc, "fail", true); context.Program.AddDeclaration(failVersion); // Use original name of the procedure. failProcedures.Add(implPair.Key, failVersion); } else if (!isHarnessProcudure(proc.Name)) { // Otherwise reuse original definition/impl as the "successful" method. BoogieProcedure failVersion = duplicateProcedure(proc, "fail"); context.Program.AddDeclaration(failVersion); // Use original name of the procedure. failProcedures.Add(implPair.Key, failVersion); // Reuse original node proc.Name = proc.Name + "__success"; implPair.Value.Name = implPair.Value.Name + "__success"; } } // Create implementations for failing methods. foreach (var failProcedurePair in failProcedures) { string originalProcName = failProcedurePair.Key; BoogieProcedure proc = failProcedurePair.Value; var originalImpl = proceduresWithImpl[originalProcName]; context.Program.AddDeclaration(createFailImplementation(proc.Name, originalImpl)); context.Program.AddDeclaration(createSuccessImplementation(originalProcName + "__success", originalImpl)); // Remove original implementation for non-public methods if (!isPublic(proceduresInProgram[originalProcName]) && !isConstructor(originalProcName)) { context.Program.Declarations.Remove(originalImpl); } } foreach (var implPair in proceduresWithImpl) { // Update non-public methods in harness methods if (isHarnessProcudure(implPair.Key)) { context.Program.AddDeclaration(createSuccessImplementation(implPair.Key, implPair.Value)); context.Program.Declarations.Remove(implPair.Value); } } // Create wrappers for public methods. foreach (var proc in proceduresInProgram.Values) { if (proceduresWithImpl.ContainsKey(proc.Name) && (isPublic(proc) || isConstructor(proc.Name))) { BoogieImplementation impl = proceduresWithImpl[proc.Name]; impl.StructuredStmts = new BoogieStmtList(); impl.LocalVars = new List <BoogieVariable>(); var exceptionVarName = "__exception"; var revertGlobalName = "revert"; impl.LocalVars.Add(new BoogieLocalVariable(new BoogieTypedIdent(exceptionVarName, BoogieType.Bool))); var stmtList = impl.StructuredStmts; stmtList.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(exceptionVarName))); stmtList.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(revertGlobalName), new BoogieLiteralExpr(false))); // Call Successful version. BoogieStmtList successCallStmtList = new BoogieStmtList(); successCallStmtList.AddStatement(new BoogieCallCmd(impl.Name + "__success", impl.InParams.Select(inParam => (BoogieExpr) new BoogieIdentifierExpr(inParam.Name)).ToList(), impl.OutParams.Select(outParam => new BoogieIdentifierExpr(outParam.Name)).ToList())); successCallStmtList.AddStatement(new BoogieAssumeCmd(new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, new BoogieIdentifierExpr(revertGlobalName)))); // Call fail version. BoogieStmtList failCallStmtList = new BoogieStmtList(); // Write global variables to temps foreach (var shadowGlobalPair in shadowGlobals) { string origVarName = shadowGlobalPair.Key; string shadowName = shadowGlobalPair.Value.Name; failCallStmtList.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(shadowName), new BoogieIdentifierExpr(origVarName))); } failCallStmtList.AddStatement(new BoogieCallCmd(impl.Name + "__fail", impl.InParams.Select(inParam => (BoogieExpr) new BoogieIdentifierExpr(inParam.Name)).ToList(), impl.OutParams.Select(outParam => new BoogieIdentifierExpr(outParam.Name)).ToList())); failCallStmtList.AddStatement(new BoogieAssumeCmd(new BoogieIdentifierExpr(revertGlobalName))); stmtList.AddStatement(new BoogieIfCmd(new BoogieIdentifierExpr(exceptionVarName), failCallStmtList, successCallStmtList)); } } }
private BoogieStmtList GenerateBody(List <BoogieVariable> inParams) { // // foreach contract C that is not Lib/VeriSol // if (DT[this] == C) // if C has a fallback f // call ret := fallBack_C(this=to, sender=from, msg.value) // else // assume msg.value == 0; // else // call fallBack_unknownType(from, to, msg.value) BoogieIfCmd ifCmd = null; Debug.Assert(context.ContractDefinitions.Count >= 1, "There should be at least one contract"); List <BoogieExpr> arguments = new List <BoogieExpr>() { new BoogieIdentifierExpr(inParams[1].Name), new BoogieIdentifierExpr(inParams[0].Name), new BoogieIdentifierExpr(inParams[2].Name) }; List <BoogieIdentifierExpr> outParams = new List <BoogieIdentifierExpr>(); BoogieStmtList noMatchCase = BoogieStmtList.MakeSingletonStmtList( new BoogieCallCmd("Fallback_UnknownType", arguments, outParams)); foreach (var contract in context.ContractDefinitions) { if (contract.ContractKind == EnumContractKind.LIBRARY) { continue; } FunctionDefinition function = context.ContractToFallbackMap.ContainsKey(contract) ? context.ContractToFallbackMap[contract] : null; BoogieExpr lhs = new BoogieMapSelect(new BoogieIdentifierExpr("DType"), new BoogieIdentifierExpr(inParams[1].Name)); BoogieExpr rhs = new BoogieIdentifierExpr(contract.Name); BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, lhs, rhs); BoogieStmtList thenBody = null; if (function != null) { string callee = TransUtils.GetCanonicalFunctionName(function, context); thenBody = BoogieStmtList.MakeSingletonStmtList(new BoogieCallCmd(callee, arguments, outParams)); } else { // No fallback means not payable (amount == 0) thenBody = BoogieStmtList.MakeSingletonStmtList( new BoogieAssumeCmd( new BoogieBinaryOperation( BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr(inParams[2].Name), new BoogieLiteralExpr(BigInteger.Zero))) ); } BoogieStmtList elseBody = ifCmd == null ? noMatchCase : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } return(BoogieStmtList.MakeSingletonStmtList(ifCmd)); }
private void generateRevertLogicForCmd(BoogieCmd cmd, BoogieStmtList parent, bool isFail, bool inHarness) { List <BoogieExpr> dupAndReplaceExprList(List <BoogieExpr> exprs) { return(exprs.Select(e => dupAndReplaceExpr(e, isFail, inHarness)).ToList()); } BoogieStmtList dupAndReplaceStmList(BoogieStmtList stmtList) { if (stmtList == null) { return(null); } BoogieStmtList newList = new BoogieStmtList(); stmtList.BigBlocks[0].SimpleCmds.ForEach(c => generateRevertLogicForCmd(c, newList, isFail, inHarness)); return(newList); } if (cmd is BoogieAssignCmd assignCmd) { parent.AddStatement(new BoogieAssignCmd(dupAndReplaceExpr(assignCmd.Lhs, isFail, inHarness), dupAndReplaceExpr(assignCmd.Rhs, isFail, inHarness))); } else if (cmd is BoogieCallCmd callCmd) { string calleeName = callCmd.Callee; bool emitCheckRevertLogic = false; if (!isHarnessProcudure(calleeName) && procsWiltImplNames.Contains(calleeName)) { if (!inHarness || !isPublic(proceduresInProgram[calleeName])) { calleeName = calleeName + (isFail ? "__fail" : "__success"); emitCheckRevertLogic = !inHarness; } } var newIns = callCmd.Ins != null?dupAndReplaceExprList(callCmd.Ins) : null; var newOuts = callCmd.Outs != null?callCmd.Outs.Select(e => (BoogieIdentifierExpr)dupAndReplaceExpr(e, isFail, inHarness)).ToList() : null; parent.AddStatement(new BoogieCallCmd(calleeName, newIns, newOuts)); if (emitCheckRevertLogic) { BoogieStmtList thenBody = new BoogieStmtList(); thenBody.AddStatement(new BoogieReturnCmd()); parent.AddStatement(new BoogieIfCmd(new BoogieIdentifierExpr("revert"), thenBody, null)); } } else if (cmd is BoogieAssertCmd assertCmd) { if (!isFail) { parent.AddStatement(new BoogieAssertCmd(dupAndReplaceExpr(assertCmd.Expr, false, inHarness), assertCmd.Attributes)); } } else if (cmd is BoogieAssumeCmd assumeCmd) { parent.AddStatement(new BoogieAssumeCmd(dupAndReplaceExpr(assumeCmd.Expr, isFail, inHarness))); } else if (cmd is BoogieLoopInvCmd loopInvCmd) { parent.AddStatement(new BoogieLoopInvCmd(dupAndReplaceExpr(loopInvCmd.Expr, isFail, inHarness))); } else if (cmd is BoogieReturnExprCmd returnExprCmd) { // This one does not seem to be used. parent.AddStatement(new BoogieReturnExprCmd(dupAndReplaceExpr(returnExprCmd.Expr, isFail, inHarness))); } else if (cmd is BoogieHavocCmd havocCmd) { parent.AddStatement(new BoogieHavocCmd(havocCmd.Vars.Select(id => (BoogieIdentifierExpr)dupAndReplaceExpr(id, isFail, inHarness)).ToList())); } else if (cmd is BoogieIfCmd ifCmd) { parent.AddStatement(new BoogieIfCmd(dupAndReplaceExpr(ifCmd.Guard, isFail, inHarness), dupAndReplaceStmList(ifCmd.ThenBody), dupAndReplaceStmList(ifCmd.ElseBody))); } else if (cmd is BoogieWhileCmd whileCmd) { var body = dupAndReplaceStmList(whileCmd.Body); BoogieStmtList invsAsStmtList = new BoogieStmtList(); whileCmd.Invariants.ForEach(i => generateRevertLogicForCmd(i, invsAsStmtList, isFail, inHarness)); List <BoogiePredicateCmd> invs = invsAsStmtList.BigBlocks[0].SimpleCmds.Select(c => (BoogiePredicateCmd)c).ToList(); parent.AddStatement(new BoogieWhileCmd(dupAndReplaceExpr(whileCmd.Guard, isFail, inHarness), body, invs)); } else { parent.AddStatement(cmd); } }
// generate a non-deterministic choice block to call every public visible functions except constructors private BoogieIfCmd GenerateChoiceBlock(ContractDefinition contract) { HashSet <FunctionDefinition> funcDefs = context.GetVisibleFunctionsByContract(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.IsConstructorForContract(contract.Name)) { continue; } if (funcDef.Visibility == EnumVisibility.PUBLIC || funcDef.Visibility == EnumVisibility.EXTERNAL) { publicFuncDefs.Add(funcDef); } } BoogieIfCmd ifCmd = null; for (int i = publicFuncDefs.Count - 1; i >= 0; --i) { BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("choice"), new BoogieLiteralExpr(i + 1)); BoogieStmtList thenBody = new BoogieStmtList(); FunctionDefinition funcDef = publicFuncDefs[i]; string callee = TransUtils.GetCanonicalFunctionName(funcDef, context); List <BoogieExpr> inputs = new List <BoogieExpr>() { new BoogieIdentifierExpr("this"), new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("msgvalue_MSG"), }; foreach (VariableDeclaration param in funcDef.Parameters.Parameters) { string name = TransUtils.GetCanonicalLocalVariableName(param); inputs.Add(new BoogieIdentifierExpr(name)); if (param.TypeName is ArrayTypeName array) { thenBody.AddStatement(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } } List <BoogieIdentifierExpr> outputs = new List <BoogieIdentifierExpr>(); var retParamCount = 0; foreach (VariableDeclaration param in funcDef.ReturnParameters.Parameters) { //string name = "__ret" + funcDef.Name; string name = $"__ret_{retParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = TransUtils.GetCanonicalLocalVariableName(param); } outputs.Add(new BoogieIdentifierExpr(name)); } BoogieCallCmd callCmd = new BoogieCallCmd(callee, inputs, outputs); thenBody.AddStatement(callCmd); BoogieStmtList elseBody = ifCmd == null ? null : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } return(ifCmd); }
private void GenerateCorralHarnessForContract(ContractDefinition contract) { string harnessName = "CorralEntry_" + contract.Name; if (context.TranslateFlags.CreateMainHarness && contract.Name.Equals(context.EntryPointContract)) { harnessName = "main"; } List <BoogieVariable> inParams = new List <BoogieVariable>(); List <BoogieVariable> outParams = new List <BoogieVariable>(); BoogieProcedure harness = new BoogieProcedure(harnessName, inParams, outParams); context.Program.AddDeclaration(harness); List <BoogieVariable> localVars = new List <BoogieVariable> { new BoogieLocalVariable(new BoogieTypedIdent("this", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgsender_MSG", BoogieType.Ref)), new BoogieLocalVariable(new BoogieTypedIdent("msgvalue_MSG", BoogieType.Int)), }; if (context.IsConstructorDefined(contract)) { FunctionDefinition ctor = context.GetConstructorByContract(contract); localVars.AddRange(GetParamsOfFunction(ctor)); } BoogieStmtList harnessBody = new BoogieStmtList(); //harnessBody.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr("this"), )); if (context.TranslateFlags.NoCustomTypes) { harnessBody.AddStatement((new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("null"), new BoogieLiteralExpr(0))))); } harnessBody.AddStatement(new BoogieCallCmd("FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr("this") })); harnessBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("now"), new BoogieLiteralExpr(0)))); harnessBody.AddStatement(GenerateDynamicTypeAssumes(contract)); if (!context.TranslateFlags.PrePostHarness) { GenerateConstructorCall(contract).ForEach(x => harnessBody.AddStatement(x)); } if (context.TranslateFlags.ModelReverts) { BoogieExpr assumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, new BoogieIdentifierExpr("revert")); if (context.TranslateFlags.InstrumentGas) { assumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, assumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } harnessBody.AddStatement(new BoogieAssumeCmd(assumePred)); } if (context.TranslateFlags.PrePostHarness) { harnessBody.AddStatement(GenerateCorralCall(contract)); BoogieStmtList body = new BoogieStmtList(); harnessBody.AddStatement(new BoogieWhileCmd(new BoogieLiteralExpr(true), body)); } else { harnessBody.AddStatement(GenerateCorralWhileLoop(contract)); } BoogieImplementation harnessImpl = new BoogieImplementation(harnessName, inParams, outParams, localVars, harnessBody); context.Program.AddDeclaration(harnessImpl); }
private BoogieImplementation CreateSendFail() { // send__fail(from: Ref, to: Ref, amt: uint) returns (success: boolean) // { // var __exception: bool; // havoc __exception; // // if(__exception) // { // //save current temps // if ((__tmp__Balance[from]) >= (amt)) { // call FallbackDispatch__fail(from, to, amt); // } // // success := false; // assume(__revert); // // // restore old temps // revert := false; // } // else { // if ((__tmp__Balance[from]) >= (amt)) { // call FallbackDispatch__fail(from, to, amt); // success := true; // } else { // success := false; // } // // assume(!(__revert)); // } // } List <BoogieVariable> inParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("from", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("to", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("amount", BoogieType.Int)) }; List <BoogieVariable> outParms = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("success", BoogieType.Bool)) }; List <BoogieVariable> locals = new List <BoogieVariable>() { new BoogieLocalVariable(new BoogieTypedIdent("__exception", BoogieType.Bool)) }; var fromId = new BoogieIdentifierExpr("from"); var toId = new BoogieIdentifierExpr("to"); var amtId = new BoogieIdentifierExpr("amount"); var successId = new BoogieIdentifierExpr("success"); var revertId = new BoogieIdentifierExpr("revert"); var exceptionId = new BoogieIdentifierExpr("__exception"); var body = new BoogieStmtList(); body.AddStatement(new BoogieHavocCmd(exceptionId)); var checkTmpBalGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), fromId), amtId); var callFailDispatch = new BoogieCallCmd("FallbackDispatch__fail", new List <BoogieExpr>() { fromId, toId, amtId }, null); var exceptionCase = new BoogieStmtList(); foreach (var shadowGlobalPair in shadowGlobals) { var shadowName = shadowGlobalPair.Value.Name; var tmpLocalName = "__snap_" + shadowName; locals.Add(new BoogieLocalVariable(new BoogieTypedIdent(tmpLocalName, shadowGlobalPair.Value.TypedIdent.Type))); exceptionCase.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(tmpLocalName), new BoogieIdentifierExpr(shadowName))); } BoogieStmtList exStmtList = new BoogieStmtList(); exStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var exBalFrom = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr(inParams[0].Name)); var exBalTo = new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), new BoogieIdentifierExpr(inParams[1].Name)); var exMsgVal = new BoogieIdentifierExpr(inParams[2].Name); //balance[msg.sender] = balance[msg.sender] - msg.value exStmtList.AddStatement(new BoogieAssignCmd(exBalFrom, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, exBalFrom, exMsgVal))); //balance[this] = balance[this] + msg.value exStmtList.AddStatement(new BoogieAssignCmd(exBalTo, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, exBalTo, exMsgVal))); exStmtList.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); exStmtList.AddStatement(callFailDispatch); exceptionCase.AddStatement(new BoogieIfCmd(checkTmpBalGuard, exStmtList, null)); exceptionCase.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))); BoogieExpr failAssumePred = revertId; if (context.TranslateFlags.InstrumentGas) { failAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.OR, failAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } exceptionCase.AddStatement(new BoogieAssumeCmd(failAssumePred)); foreach (var shadowGlobalPair in shadowGlobals) { var shadowName = shadowGlobalPair.Value.Name; var tmpLocalName = "__snap_" + shadowName; exceptionCase.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(shadowName), new BoogieIdentifierExpr(tmpLocalName))); } exceptionCase.AddStatement(new BoogieAssignCmd(revertId, new BoogieLiteralExpr(false))); var successCase = new BoogieStmtList(); var successDispatchCall = new BoogieStmtList(); successDispatchCall.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); //balance[msg.sender] = balance[msg.sender] - msg.value successDispatchCall.AddStatement(new BoogieAssignCmd(exBalFrom, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, exBalFrom, exMsgVal))); //balance[this] = balance[this] + msg.value successDispatchCall.AddStatement(new BoogieAssignCmd(exBalTo, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, exBalTo, exMsgVal))); successDispatchCall.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); successDispatchCall.AddStatement(callFailDispatch); successDispatchCall.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(true))); successCase.AddStatement(new BoogieIfCmd(checkTmpBalGuard, successDispatchCall, BoogieStmtList.MakeSingletonStmtList(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))))); BoogieExpr successAssumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, revertId); if (context.TranslateFlags.InstrumentGas) { successAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, successAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } successCase.AddStatement(new BoogieAssumeCmd(successAssumePred)); body.AddStatement(new BoogieIfCmd(exceptionId, exceptionCase, successCase)); return(new BoogieImplementation("send__fail", inParams, outParms, locals, body)); }
private BoogieStmtList GenerateBodyOfFallbackDispatch(List <BoogieVariable> inParams, string fbUnknownProcName) { // Perform the payable logic to transfer balance // // Fallback(from, to, amount) // // foreach contract C that is not Lib/VeriSol // if (DT[this] == C) // if C has a fallback f // call ret := fallBack_C(this=to, sender=from, msg.value) // else // assume msg.value == 0; // else // if stubModel == callback // call fallBack_unknownType(from, to, amout) //we switch the order of first two parameters to ease callbacks // else if stubmodel == havoc // havoc all global state, except local state of this contract // else // skip //default BoogieIfCmd ifCmd = null; Debug.Assert(context.ContractDefinitions.Count >= 1, "There should be at least one contract"); List <BoogieIdentifierExpr> outParams = new List <BoogieIdentifierExpr>(); List <BoogieExpr> unkwnFnArgs = new List <BoogieExpr>() { new BoogieIdentifierExpr(inParams[0].Name), new BoogieIdentifierExpr(inParams[1].Name), new BoogieIdentifierExpr(inParams[2].Name) }; // fbUnknown(from, to, amount) BoogieStmtList noMatchCase = BoogieStmtList.MakeSingletonStmtList( new BoogieCallCmd(fbUnknownProcName, unkwnFnArgs, outParams)); foreach (var contract in context.ContractDefinitions) { if (contract.ContractKind == EnumContractKind.LIBRARY) { continue; } FunctionDefinition function = context.ContractToFallbackMap.ContainsKey(contract) ? context.ContractToFallbackMap[contract] : null; BoogieExpr lhs = new BoogieMapSelect(new BoogieIdentifierExpr("DType"), new BoogieIdentifierExpr(inParams[1].Name)); BoogieExpr rhs = new BoogieIdentifierExpr(contract.Name); BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, lhs, rhs); BoogieStmtList thenBody = null; if (function != null) { List <BoogieExpr> arguments = new List <BoogieExpr>() { new BoogieIdentifierExpr(inParams[1].Name), new BoogieIdentifierExpr(inParams[0].Name), new BoogieIdentifierExpr(inParams[2].Name) }; string callee = TransUtils.GetCanonicalFunctionName(function, context); // to.fallback(from, amount), thus need to switch param0 and param1 thenBody = BoogieStmtList.MakeSingletonStmtList(new BoogieCallCmd(callee, arguments, outParams)); } else { // No fallback means not payable (amount == 0) thenBody = BoogieStmtList.MakeSingletonStmtList( new BoogieAssumeCmd( new BoogieBinaryOperation( BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr(inParams[2].Name), new BoogieLiteralExpr(BigInteger.Zero))) ); } BoogieStmtList elseBody = ifCmd == null ? noMatchCase : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } return(BoogieStmtList.MakeSingletonStmtList(ifCmd)); }
/// <summary> /// generate a non-deterministic choice block to call every public visible functions except constructors /// /// </summary> /// <param name="contracts"></param> /// <param name="context"></param> /// <param name="callBackTarget">If non-null, this will be the msg.sender for calling back into the contracts</param> /// <returns></returns> public static BoogieIfCmd GenerateChoiceBlock(List <ContractDefinition> contracts, TranslatorContext context, Tuple <string, string> callBackTarget = null) { BoogieIfCmd ifCmd = null; int j = 0; foreach (var contract in contracts) { if (contract.ContractKind != EnumContractKind.CONTRACT) { continue; } HashSet <FunctionDefinition> funcDefs = context.GetVisibleFunctionsByContract(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.IsConstructor) { continue; } if (funcDef.IsFallback) { continue; //let us not call fallback directly in harness } if (funcDef.Visibility == EnumVisibility.PUBLIC || funcDef.Visibility == EnumVisibility.EXTERNAL) { publicFuncDefs.Add(funcDef); } } for (int i = publicFuncDefs.Count - 1; i >= 0; --i) { j++; BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("choice"), new BoogieLiteralExpr(j)); BoogieStmtList thenBody = new BoogieStmtList(); FunctionDefinition funcDef = publicFuncDefs[i]; string callee = TransUtils.GetCanonicalFunctionName(funcDef, context); List <BoogieExpr> inputs = new List <BoogieExpr>() { // let us just call back into the calling contract callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item1) : new BoogieIdentifierExpr("this"), callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item2) : new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("msgvalue_MSG"), }; foreach (VariableDeclaration param in funcDef.Parameters.Parameters) { string name = TransUtils.GetCanonicalLocalVariableName(param); inputs.Add(new BoogieIdentifierExpr(name)); if (param.TypeName is ArrayTypeName array) { thenBody.AddStatement(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } } List <BoogieIdentifierExpr> outputs = new List <BoogieIdentifierExpr>(); var retParamCount = 0; foreach (VariableDeclaration param in funcDef.ReturnParameters.Parameters) { string name = $"__ret_{retParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = TransUtils.GetCanonicalLocalVariableName(param); } outputs.Add(new BoogieIdentifierExpr(name)); } if (context.TranslateFlags.InstrumentGas) { havocGas(thenBody); } BoogieCallCmd callCmd = new BoogieCallCmd(callee, inputs, outputs); thenBody.AddStatement(callCmd); BoogieStmtList elseBody = ifCmd == null ? null : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } } return(ifCmd); }
private BoogieImplementation CreateSendSucess() { // send__success(from: Ref, to: Ref, amt: uint) returns (success: boolean) // { // var __exception: bool; // havoc __exception; // // if(__exception) // { // //set tmps // if ((__tmp__Balance[from]) >= (amt)) { // call FallbackDispatch__fail(from, to, amt); // } // // success := false; // assume(__revert); // // revert := false; // } // else { // if ((Balance[from]) >= (amt)) { // call FallbackDispatch__success(from, to, amt); // success := true; // } else { // success := false; // } // // assume(!(__revert)); // } // } List <BoogieVariable> inParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("from", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("to", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("amount", BoogieType.Int)) }; List <BoogieVariable> outParms = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("success", BoogieType.Bool)) }; List <BoogieVariable> locals = new List <BoogieVariable>() { new BoogieLocalVariable(new BoogieTypedIdent("__exception", BoogieType.Bool)) }; var fromId = new BoogieIdentifierExpr("from"); var toId = new BoogieIdentifierExpr("to"); var amtId = new BoogieIdentifierExpr("amount"); var successId = new BoogieIdentifierExpr("success"); var revertId = new BoogieIdentifierExpr("revert"); var exceptionId = new BoogieIdentifierExpr("__exception"); BoogieStmtList body = new BoogieStmtList(); body.AddStatement(new BoogieHavocCmd(exceptionId)); BoogieStmtList exceptionCase = new BoogieStmtList(); foreach (var shadowGlobalPair in shadowGlobals) { string origVarName = shadowGlobalPair.Key; string shadowName = shadowGlobalPair.Value.Name; exceptionCase.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr(shadowName), new BoogieIdentifierExpr(origVarName))); } var checkTmpBalGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr(shadowGlobals["Balance"].Name), fromId), amtId); var callFailDispatch = new BoogieCallCmd("FallbackDispatch__fail", new List <BoogieExpr>() { fromId, toId, amtId }, null); exceptionCase.AddStatement(new BoogieIfCmd(checkTmpBalGuard, BoogieStmtList.MakeSingletonStmtList(callFailDispatch), null)); exceptionCase.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))); BoogieExpr failAssumePred = revertId; if (context.TranslateFlags.InstrumentGas) { failAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.OR, failAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } exceptionCase.AddStatement(new BoogieAssumeCmd(failAssumePred)); exceptionCase.AddStatement(new BoogieAssignCmd(revertId, new BoogieLiteralExpr(false))); var successCase = new BoogieStmtList(); var checkBalGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), fromId), amtId); var successCaseStmts = new BoogieStmtList(); var callSuccessDispatch = new BoogieCallCmd("FallbackDispatch__success", new List <BoogieExpr>() { fromId, toId, amtId }, null); successCaseStmts.AddStatement(callSuccessDispatch); successCaseStmts.AddStatement(new BoogieAssignCmd(successId, new BoogieLiteralExpr(true))); successCase.AddStatement(new BoogieIfCmd(checkBalGuard, successCaseStmts, BoogieStmtList.MakeSingletonStmtList(new BoogieAssignCmd(successId, new BoogieLiteralExpr(false))))); BoogieExpr successAssumePred = new BoogieUnaryOperation(BoogieUnaryOperation.Opcode.NOT, revertId); if (context.TranslateFlags.InstrumentGas) { successAssumePred = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, successAssumePred, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(0))); } successCase.AddStatement(new BoogieAssumeCmd(successAssumePred)); body.AddStatement(new BoogieIfCmd(exceptionId, exceptionCase, successCase)); return(new BoogieImplementation("send__success", inParams, outParms, locals, body)); }
private BoogieStmtList CreateBodyOfUnknownFallback(List <BoogieVariable> fbLocalVars, List <BoogieVariable> inParams) { Debug.Assert(context.TranslateFlags.ModelStubsAsSkips() || context.TranslateFlags.ModelStubsAsCallbacks() || context.TranslateFlags.ModelStubsAsMultipleCallbacks(), "CreateBodyOfUnknownFallback called in unexpected context"); var procBody = new BoogieStmtList(); /*procBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); * var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[0].Name)); * var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr(inParams[1].Name)); * var msgVal = new BoogieIdentifierExpr("amount"); * //assume Balance[msg.sender] >= msg.value * procBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); * //balance[from] = balance[from] - msg.value * procBody.AddStatement(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); * //balance[to] = balance[to] + msg.value * procBody.AddStatement(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); * procBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function END "));*/ BoogieStmtList body = procBody; if (context.TranslateFlags.ModelStubsAsCallbacks() || context.TranslateFlags.ModelStubsAsMultipleCallbacks()) { if (context.TranslateFlags.ModelReverts) { BoogieBinaryOperation revertGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("choice"), new BoogieLiteralExpr(BigInteger.Zero)); BoogieStmtList thenBody = new BoogieStmtList(); thenBody.AddStatement(new BoogieAssignCmd(new BoogieIdentifierExpr("revert"), new BoogieLiteralExpr(true))); thenBody.AddStatement(new BoogieReturnCmd()); BoogieIfCmd earlyExitCmd = new BoogieIfCmd(revertGuard, thenBody, null); body.AddStatement(earlyExitCmd); } if (context.TranslateFlags.InstrumentGas) { BoogieBinaryOperation gasGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.LT, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)); BoogieIfCmd earlyExitCmd = new BoogieIfCmd(gasGuard, BoogieStmtList.MakeSingletonStmtList(new BoogieReturnCmd()), null); body.AddStatement(earlyExitCmd); } } if (context.TranslateFlags.ModelStubsAsMultipleCallbacks()) { fbLocalVars.Add(new BoogieLocalVariable(new BoogieTypedIdent("iterate", BoogieType.Bool))); BoogieBinaryOperation gasGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("gas"), new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)); BoogieBinaryOperation guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.AND, new BoogieIdentifierExpr("iterate"), gasGuard); BoogieStmtList loopBody = new BoogieStmtList(); procBody.AddStatement(new BoogieWhileCmd(guard, loopBody, new List <BoogieExpr>())); body = loopBody; } if (context.TranslateFlags.ModelStubsAsCallbacks() || context.TranslateFlags.ModelStubsAsMultipleCallbacks()) { List <BoogieVariable> localVars = TransUtils.CollectLocalVars(context.ContractDefinitions.ToList(), context); fbLocalVars.AddRange(localVars); // if (*) fn1(from, *, ...) // we only redirect the calling contract, but the msg.sender need not be to, as it can call into anohter contract that calls // into from if (context.TranslateFlags.ModelStubsAsMultipleCallbacks()) { body.AppendStmtList(HavocLocals(localVars)); body.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr("iterate"))); } BoogieIfCmd typeIf = null; foreach (ContractDefinition curDef in context.ContractDefinitions.ToList()) { BoogieIfCmd reentrantCalls = TransUtils.GenerateChoiceBlock(new List <ContractDefinition>() { curDef }, context, false, Tuple.Create(inParams[0].Name, inParams[1].Name)); if (reentrantCalls == null) { continue; } BoogieExpr dtype = new BoogieMapSelect(new BoogieIdentifierExpr("DType"), new BoogieIdentifierExpr(inParams[0].Name)); BoogieBinaryOperation guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, dtype, new BoogieIdentifierExpr(curDef.Name)); typeIf = new BoogieIfCmd(guard, BoogieStmtList.MakeSingletonStmtList(reentrantCalls), typeIf == null ? null : BoogieStmtList.MakeSingletonStmtList(typeIf)); } /*BoogieIfCmd ifCmd = null; * * if (context.TranslateFlags.ModelReverts) * { * BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, * new BoogieIdentifierExpr("choice"), * new BoogieLiteralExpr(choices.Item2 + 1)); * * BoogieAssignCmd assign = new BoogieAssignCmd(new BoogieIdentifierExpr("revert"), new BoogieLiteralExpr(true)); * ifCmd = new BoogieIfCmd(guard, BoogieStmtList.MakeSingletonStmtList(assign), BoogieStmtList.MakeSingletonStmtList(choices.Item1)); * } * else * { * ifCmd = choices.Item1; * }*/ body.AddStatement(typeIf); } return(procBody); }
public void Generate() { List <BoogieVariable> inParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("from", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("to", BoogieType.Ref)), new BoogieFormalParam(new BoogieTypedIdent("amount", BoogieType.Int)) }; List <BoogieVariable> outParams = new List <BoogieVariable>(); List <BoogieAttribute> attributes = new List <BoogieAttribute>(); if (context.TranslateFlags.GenerateInlineAttributes) { attributes.Add(new BoogieAttribute("inline", 1)); } ; var procName = "FallbackDispatch"; BoogieProcedure procedure = new BoogieProcedure(procName, inParams, outParams, attributes); context.Program.AddDeclaration(procedure); List <BoogieVariable> localVars = new List <BoogieVariable>(); var fbUnknownProcName = "Fallback_UnknownType"; BoogieStmtList procBody = GenerateBodyOfFallbackDispatch(inParams, fbUnknownProcName); BoogieImplementation implementation = new BoogieImplementation(procName, inParams, outParams, localVars, procBody); context.Program.AddDeclaration(implementation); // let us havoc all the global variables when fallback_unknowntype is called var modSet = context.Program.Declarations.Where(x => x is BoogieGlobalVariable).Select(x => (BoogieGlobalVariable)x).ToList(); BoogieProcedure unknownFbProc = new BoogieProcedure(fbUnknownProcName, inParams, outParams, attributes); context.Program.AddDeclaration(unknownFbProc); // we need to create an implementation as Corral seem to ignore modifies on declarations // https://github.com/boogie-org/corral/issues/98 BoogieStmtList fbBody = new BoogieStmtList(); var fbLocalVars = new List <BoogieVariable>(); if (context.TranslateFlags.ModelStubsAsSkips() || context.TranslateFlags.ModelStubsAsCallbacks()) { fbBody.AppendStmtList(CreateBodyOfUnknownFallback(fbLocalVars, inParams)); } else { Debug.Assert(context.TranslateFlags.ModelStubsAsHavocs(), "Unknown option for modeling stubs"); foreach (var global in modSet) { fbBody.AddStatement(new BoogieHavocCmd(new BoogieIdentifierExpr(global.Name))); } } BoogieImplementation unknownFbImpl = new BoogieImplementation(fbUnknownProcName, inParams, outParams, fbLocalVars, fbBody); context.Program.AddDeclaration(unknownFbImpl); var sendProcName = "send"; var sendOutParams = new List <BoogieVariable>() { new BoogieFormalParam(new BoogieTypedIdent("success", BoogieType.Bool)) }; BoogieProcedure sendProc = new BoogieProcedure(sendProcName, inParams, sendOutParams, attributes); context.Program.AddDeclaration(sendProc); BoogieStmtList sendBody = CreateBodyOfSend(inParams, sendOutParams, procName); context.Program.AddDeclaration(new BoogieImplementation(sendProcName, inParams, sendOutParams, localVars, sendBody)); }
public static Tuple <BoogieIfCmd, int> GeneratePartialChoiceBlock(List <ContractDefinition> contracts, TranslatorContext context, BoogieExpr thisExpr, int startingPoint, bool canRevert, BoogieIfCmd alternatives = null, Tuple <string, string> callBackTarget = null) { BoogieIfCmd ifCmd = alternatives; int j = startingPoint; foreach (var contract in contracts) { if (contract.ContractKind != EnumContractKind.CONTRACT) { continue; } HashSet <FunctionDefinition> funcDefs = context.GetVisibleFunctionsByContract(contract); List <FunctionDefinition> publicFuncDefs = new List <FunctionDefinition>(); foreach (FunctionDefinition funcDef in funcDefs) { if (funcDef.IsConstructor) { continue; } if (funcDef.IsFallback) { continue; //let us not call fallback directly in harness } if (context.TranslateFlags.PerformFunctionSlice && !context.TranslateFlags.SliceFunctions.Contains(funcDef)) { continue; } if (funcDef.Visibility == EnumVisibility.PUBLIC || funcDef.Visibility == EnumVisibility.EXTERNAL) { publicFuncDefs.Add(funcDef); } } for (int i = publicFuncDefs.Count - 1; i >= 0; --i) { j++; BoogieExpr guard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("choice"), new BoogieLiteralExpr(j)); BoogieStmtList thenBody = new BoogieStmtList(); FunctionDefinition funcDef = publicFuncDefs[i]; string callee = TransUtils.GetCanonicalFunctionName(funcDef, context); List <BoogieExpr> inputs = new List <BoogieExpr>() { // let us just call back into the calling contract callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item1) : thisExpr, callBackTarget != null ? new BoogieIdentifierExpr(callBackTarget.Item2) : new BoogieIdentifierExpr("msgsender_MSG"), new BoogieIdentifierExpr("msgvalue_MSG"), }; var inpParamCount = 0; foreach (VariableDeclaration param in funcDef.Parameters.Parameters) { string name = $"__arg_{inpParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = TransUtils.GetCanonicalLocalVariableName(param, context); } BoogieIdentifierExpr boogieVar = new BoogieIdentifierExpr(name); inputs.Add(boogieVar); if (param.TypeName is ArrayTypeName array) { thenBody.AddStatement(new BoogieCallCmd( "FreshRefGenerator", new List <BoogieExpr>(), new List <BoogieIdentifierExpr>() { new BoogieIdentifierExpr(name) })); } thenBody.AppendStmtList(constrainVarValues(context, param, boogieVar)); } List <BoogieIdentifierExpr> outputs = new List <BoogieIdentifierExpr>(); var retParamCount = 0; foreach (VariableDeclaration param in funcDef.ReturnParameters.Parameters) { string name = $"__ret_{retParamCount++}_" + funcDef.Name; if (!string.IsNullOrEmpty(param.Name)) { name = TransUtils.GetCanonicalLocalVariableName(param, context); } outputs.Add(new BoogieIdentifierExpr(name)); } if (funcDef.StateMutability.Equals(EnumStateMutability.PAYABLE)) { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); thenBody.AddStatement(new BoogieAssumeCmd(assumeExpr)); if (!canRevert) { thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function START ")); var balnSender = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("msgsender_MSG")); var balnThis = new BoogieMapSelect(new BoogieIdentifierExpr("Balance"), new BoogieIdentifierExpr("this")); var msgVal = new BoogieIdentifierExpr("msgvalue_MSG"); //assume Balance[msg.sender] >= msg.value thenBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, balnSender, msgVal))); //balance[msg.sender] = balance[msg.sender] - msg.value thenBody.AddStatement(new BoogieAssignCmd(balnSender, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, balnSender, msgVal))); //balance[this] = balance[this] + msg.value thenBody.AddStatement(new BoogieAssignCmd(balnThis, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.ADD, balnThis, msgVal))); thenBody.AddStatement(new BoogieCommentCmd("---- Logic for payable function END ")); } } else { BoogieExpr assumeExpr = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.EQ, new BoogieIdentifierExpr("msgvalue_MSG"), new BoogieLiteralExpr(BigInteger.Zero)); thenBody.AddStatement(new BoogieAssumeCmd(assumeExpr)); } BoogieCallCmd callCmd = new BoogieCallCmd(callee, inputs, outputs); thenBody.AddStatement(callCmd); if (context.TranslateFlags.InstrumentGas) { var gasVar = new BoogieIdentifierExpr("gas"); BoogieBinaryOperation gasGuard = new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, gasVar, new BoogieLiteralExpr(BigInteger.Zero)); BoogieIfCmd ifExpr = new BoogieIfCmd(gasGuard, thenBody, null); thenBody = new BoogieStmtList(); //thenBody.AddStatement(new BoogieAssumeCmd(new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.GE, gasVar, new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)))); thenBody.AddStatement(new BoogieAssignCmd(gasVar, new BoogieBinaryOperation(BoogieBinaryOperation.Opcode.SUB, gasVar, new BoogieLiteralExpr(TranslatorContext.TX_GAS_COST)))); thenBody.AddStatement(ifExpr); } BoogieStmtList elseBody = ifCmd == null ? null : BoogieStmtList.MakeSingletonStmtList(ifCmd); ifCmd = new BoogieIfCmd(guard, thenBody, elseBody); } } return(new Tuple <BoogieIfCmd, int>(ifCmd, j)); }