public ExceptionHandlerScope(ExceptionHandlerContainerScope containingScope, ScopeType type, Microsoft.Cci.ITypeReference exceptionType)
            {
                Debug.Assert((type == ScopeType.Try) || (type == ScopeType.Catch) || (type == ScopeType.Filter) || (type == ScopeType.Finally) || (type == ScopeType.Fault));
                Debug.Assert((type == ScopeType.Catch) == (exceptionType != null));

                _containingScope = containingScope;
                _type            = type;
                _exceptionType   = exceptionType;
            }
예제 #2
0
        private static bool CanMoveLabelToAnotherHandler(ExceptionHandlerScope currentHandler,
                                                         ExceptionHandlerScope newHandler)
        {
            // Generally, assuming already valid code that contains "LABEL1: goto LABEL2"
            // we can substitute LABEL1 for LABEL2 so that the branches go directly to
            // the final destination.
            // Technically we can allow "moving" a label to any scope that contains the current one
            // However we should be careful with the cases when current label is protected by a
            // catch clause.
            //
            // [COMPAT]
            // If we move a label out of catch-protected try clause, we could be forcing JIT to inject
            // it back since, in the case of Thread.Abort, the re-throwing of the exception needs
            // to happen around this leave instruction which we would be removing.
            // In addition to just extra work on the JIT side, handling of this case appears to be
            // very delicate and there are known cases where JITs did not handle this particular
            // scenario correctly resulting in various violations of Thread.Abort behavior.
            // We cannot rely on these JIT issues being fixed in the end user environment.
            //
            // Considering that we are only winning a single LEAVE here, it seems reasonable to
            // just disallow labels to move outside of a catch-protected regions.

            // no handler means outermost scope (method level)
            if (newHandler == null && currentHandler.ContainingExceptionScope.FinallyOnly())
            {
                return(true);
            }

            // check if the target handler contains current handler.
            do
            {
                if (currentHandler == newHandler)
                {
                    return(true);
                }

                ExceptionHandlerContainerScope containerScope = currentHandler.ContainingExceptionScope;
                if (!containerScope.FinallyOnly())
                {
                    // this may move the label outside of catch-protected region
                    // we will disallow that.
                    return(false);
                }

                currentHandler = containerScope.ContainingHandler;
            } while (currentHandler != null);

            return(false);
        }
            internal bool FinallyOnly()
            {
                ExceptionHandlerContainerScope curScope = this;

                do
                {
                    ImmutableArray <ExceptionHandlerScope> .Builder handlers = curScope._handlers;
                    // handler[0] is always the try
                    // if we have a finally, then we do not have any catches and
                    // the finally is as handlers[1]
                    if (handlers.Count != 2 || handlers[1].Type != ScopeType.Finally)
                    {
                        return(false);
                    }

                    curScope = curScope._containingHandler?.ContainingExceptionScope;
                }while (curScope != null);

                return(true);
            }