Пример #1
0
        internal Dictionary <MethodDefinition, StateRange> finallyMethodToStateRange;        // used only for IteratorDispose

        /// <summary>
        /// Initializes the state range logic:
        /// Clears 'ranges' and sets 'ranges[entryPoint]' to the full range (int.MinValue to int.MaxValue)
        /// </summary>
        public StateRangeAnalysis(ILNode entryPoint, StateRangeAnalysisMode mode, FieldDefinition stateField, ILVariable cachedStateVar = null)
        {
            this.mode       = mode;
            this.stateField = stateField;
            if (mode == StateRangeAnalysisMode.IteratorDispose)
            {
                finallyMethodToStateRange = new Dictionary <MethodDefinition, StateRange>();
            }

            ranges             = new DefaultDictionary <ILNode, StateRange>(n => new StateRange());
            ranges[entryPoint] = new StateRange(int.MinValue, int.MaxValue);
            evalContext        = new SymbolicEvaluationContext(stateField);
            if (cachedStateVar != null)
            {
                evalContext.AddStateVariable(cachedStateVar);
            }
        }
        public int AssignStateRanges(List <ILNode> body, int bodyLength)
        {
            if (bodyLength == 0)
            {
                return(0);
            }
            for (int i = 0; i < bodyLength; i++)
            {
                StateRange nodeRange = ranges[body[i]];
                nodeRange.Simplify();

                ILLabel label = body[i] as ILLabel;
                if (label != null)
                {
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    continue;
                }

                ILTryCatchBlock tryFinally = body[i] as ILTryCatchBlock;
                if (tryFinally != null)
                {
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        if (tryFinally.CatchBlocks.Count != 0 || tryFinally.FaultBlock != null || tryFinally.FinallyBlock == null)
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        ranges[tryFinally.TryBlock].UnionWith(nodeRange);
                        if (tryFinally.TryBlock.Body.Count != 0)
                        {
                            ranges[tryFinally.TryBlock.Body[0]].UnionWith(nodeRange);
                            AssignStateRanges(tryFinally.TryBlock.Body, tryFinally.TryBlock.Body.Count);
                        }
                        continue;
                    }
                    else if (mode == StateRangeAnalysisMode.AsyncMoveNext)
                    {
                        return(i);
                    }
                    else
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                }

                ILExpression expr = body[i] as ILExpression;
                if (expr == null)
                {
                    throw new SymbolicAnalysisFailedException();
                }
                switch (expr.Code)
                {
                case ILCode.Switch:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
                    if (val.Type != SymbolicValueType.State)
                    {
                        goto default;
                    }
                    ILLabel[] targetLabels = (ILLabel[])expr.Operand;
                    for (int j = 0; j < targetLabels.Length; j++)
                    {
                        int state = j - val.Constant;
                        ranges[targetLabels[j]].UnionWith(nodeRange, state, state);
                    }
                    StateRange nextRange = ranges[body[i + 1]];
                    nextRange.UnionWith(nodeRange, int.MinValue, -1 - val.Constant);
                    nextRange.UnionWith(nodeRange, targetLabels.Length - val.Constant, int.MaxValue);
                    break;
                }

                case ILCode.Br:
                case ILCode.Leave:
                    ranges[(ILLabel)expr.Operand].UnionWith(nodeRange);
                    break;

                case ILCode.Brtrue:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
                    if (val.Type == SymbolicValueType.StateEquals)
                    {
                        ranges[(ILLabel)expr.Operand].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange nextRange = ranges[body[i + 1]];
                        nextRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        nextRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                        break;
                    }
                    else if (val.Type == SymbolicValueType.StateInEquals)
                    {
                        ranges[body[i + 1]].UnionWith(nodeRange, val.Constant, val.Constant);
                        StateRange targetRange = ranges[(ILLabel)expr.Operand];
                        targetRange.UnionWith(nodeRange, int.MinValue, val.Constant - 1);
                        targetRange.UnionWith(nodeRange, val.Constant + 1, int.MaxValue);
                        break;
                    }
                    else
                    {
                        goto default;
                    }
                }

                case ILCode.Nop:
                    ranges[body[i + 1]].UnionWith(nodeRange);
                    break;

                case ILCode.Ret:
                    break;

                case ILCode.Stloc:
                {
                    SymbolicValue val = evalContext.Eval(expr.Arguments[0]);
                    if (val.Type == SymbolicValueType.State && val.Constant == 0)
                    {
                        evalContext.AddStateVariable((ILVariable)expr.Operand);
                        goto case ILCode.Nop;
                    }
                    else
                    {
                        goto default;
                    }
                }

                case ILCode.Call:
                    // in some cases (e.g. foreach over array) the C# compiler produces a finally method outside of try-finally blocks
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        MethodDefinition mdef = (expr.Operand as MethodReference).ResolveWithinSameModule();
                        if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
                        {
                            throw new SymbolicAnalysisFailedException();
                        }
                        finallyMethodToStateInterval.Add(mdef, nodeRange.ToEnclosingInterval());
                        break;
                    }
                    else
                    {
                        goto default;
                    }

                default:
                    if (mode == StateRangeAnalysisMode.IteratorDispose)
                    {
                        throw new SymbolicAnalysisFailedException();
                    }
                    else
                    {
                        return(i);
                    }
                }
            }
            return(bodyLength);
        }