Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }
Exemple #3
0
        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));
        }