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>() { 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); }
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 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)); }