diff --git a/src/linker/Linker.Steps/BaseStep.cs b/src/linker/Linker.Steps/BaseStep.cs index 2e9ff9ae2b97..7bf5b4bf26b2 100644 --- a/src/linker/Linker.Steps/BaseStep.cs +++ b/src/linker/Linker.Steps/BaseStep.cs @@ -29,7 +29,6 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // -using System; using System.Diagnostics; using Mono.Cecil; @@ -68,11 +67,7 @@ public void Process (LinkContext context) Process (); foreach (AssemblyDefinition assembly in context.GetAssemblies ()) { - try { - ProcessAssembly (assembly); - } catch (Exception e) { - throw new InternalErrorException ($"Step '{GetType ().Name}' failed when processing assembly '{assembly.FullName}'.", e); - } + ProcessAssembly (assembly); } EndProcess (); diff --git a/src/linker/Linker.Steps/MarkStep.cs b/src/linker/Linker.Steps/MarkStep.cs index c3def477d5c4..d5417a66b614 100644 --- a/src/linker/Linker.Steps/MarkStep.cs +++ b/src/linker/Linker.Steps/MarkStep.cs @@ -554,12 +554,7 @@ void ProcessQueue () { while (!QueueIsEmpty ()) { (MethodDefinition method, DependencyInfo reason, MessageOrigin origin) = _methods.Dequeue (); - try { - ProcessMethod (method, reason, origin); - } catch (Exception e) when (!(e is LinkerFatalErrorException)) { - throw new LinkerFatalErrorException ( - MessageContainer.CreateErrorMessage (origin, DiagnosticId.CouldNotFindMethodInAssembly, method.GetDisplayName (), method.Module.Name), e); - } + ProcessMethod (method, reason, origin); } } diff --git a/src/linker/Linker.Steps/OutputStep.cs b/src/linker/Linker.Steps/OutputStep.cs index 730e85f24bd3..590d498ece2c 100644 --- a/src/linker/Linker.Steps/OutputStep.cs +++ b/src/linker/Linker.Steps/OutputStep.cs @@ -133,6 +133,7 @@ protected virtual void WriteAssembly (AssemblyDefinition assembly, string direct try { assembly.Write (outputName, writerParameters); } catch (Exception e) { + // We should be okay catching everything here, assembly.Write is all in Cecil and most of the state necessary to debug will be captured in assembly throw new LinkerFatalErrorException (MessageContainer.CreateErrorMessage (null, DiagnosticId.FailedToWriteOutput, outputName), e); } } diff --git a/src/linker/Linker/Driver.cs b/src/linker/Linker/Driver.cs index 8655280416e0..d0729df5f686 100644 --- a/src/linker/Linker/Driver.cs +++ b/src/linker/Linker/Driver.cs @@ -93,7 +93,7 @@ public static bool ProcessResponseFile (string[] args, out Queue result) string responseFileName = arg.Substring (1); using (var responseFileText = new StreamReader (responseFileName)) ParseResponseFile (responseFileText, result); - } catch (Exception e) { + } catch (Exception e) when (e is IOException or ObjectDisposedException) { Console.Error.WriteLine ("Cannot read response file due to '{0}'", e.Message); return false; } @@ -767,7 +767,7 @@ protected int SetupContext (ILogger? customLogger = null) // to the error code. // May propagate exceptions, which will result in the process getting an // exit code determined by dotnet. - public int Run (ILogger? customLogger = null, bool throwOnFatalLinkerException = false) + public int Run (ILogger? customLogger = null) { int setupStatus = SetupContext (customLogger); if (setupStatus > 0) @@ -780,29 +780,37 @@ public int Run (ILogger? customLogger = null, bool throwOnFatalLinkerException = try { p.Process (Context); - } catch (LinkerFatalErrorException lex) { + } catch (Exception e) when (LogFatalError (e)) { + // Unreachable + throw; + } + + Context.FlushCachedWarnings (); + Context.Tracer.Finish (); + return Context.ErrorsCount > 0 ? 1 : 0; + } + + /// + /// This method is called in the exception filter for unexpected exceptions. + /// Prints error messages and returns false to avoid catching in the exception filter. + /// + bool LogFatalError (Exception e) + { + switch (e) { + case LinkerFatalErrorException lex: Context.LogMessage (lex.MessageContainer); - Console.Error.WriteLine (lex.ToString ()); Debug.Assert (lex.MessageContainer.Category == MessageCategory.Error); Debug.Assert (lex.MessageContainer.Code != null); Debug.Assert (lex.MessageContainer.Code.Value != 0); - if (throwOnFatalLinkerException) - throw; - return lex.MessageContainer.Code ?? 1; - } catch (ResolutionException e) { - Context.LogError (null, DiagnosticId.FailedToResolveMetadataElement, e.Message); - } catch (Exception) { - // Unhandled exceptions are usually linker bugs. Ask the user to report it. + break; + case ResolutionException re: + Context.LogError (null, DiagnosticId.FailedToResolveMetadataElement, re.Message); + break; + default: Context.LogError (null, DiagnosticId.LinkerUnexpectedError); - // Don't swallow the exception and exit code - rethrow it and let the surrounding tooling decide what to do. - // The stack trace will go to stderr, and the MSBuild task will surface it with High importance. - throw; - } finally { - Context.FlushCachedWarnings (); - Context.Tracer.Finish (); + break; } - - return Context.ErrorsCount > 0 ? 1 : 0; + return false; } partial void PreProcessPipeline (Pipeline pipeline); diff --git a/src/tlens/TLens/Runner.cs b/src/tlens/TLens/Runner.cs index cce51a61727a..65679fa92f53 100644 --- a/src/tlens/TLens/Runner.cs +++ b/src/tlens/TLens/Runner.cs @@ -32,11 +32,7 @@ public void Process (List assemblies) bool first = true; foreach (var a in analyzers) { foreach (var assembly in assemblies) { - try { - a.ProcessAssembly (assembly); - } catch (Exception e) { - throw new ApplicationException ($"Internal error when analyzing '{assembly.FullName}' assembly with '{a.GetType ()}'", e); - } + a.ProcessAssembly (assembly); } if (!first) diff --git a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs index 859bfb22a6e0..963c6a479560 100644 --- a/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs +++ b/test/Mono.Linker.Tests/TestCasesRunner/LinkerDriver.cs @@ -28,7 +28,7 @@ public virtual void Link (string[] args, LinkerCustomizations customizations, IL { Driver.ProcessResponseFile (args, out var queue); using (var driver = new TestDriver (queue, customizations)) { - driver.Run (logger, throwOnFatalLinkerException: true); + driver.Run (logger); } } }