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