From 733a7947d34d6624c0f2afacf519d42edc6fe89c Mon Sep 17 00:00:00 2001 From: Nicolas Stucki Date: Tue, 30 Jan 2024 08:24:04 +0100 Subject: [PATCH] Make tests resilient to exceptions thrown while reporting exceptions Part of #19542. We protect against the case where `Exception.getMessage` or `Exception.getStackTrace` throw an exception. [Cherry-picked b427ba660a43161b463a393e49b00e70fce82f58] --- .../dotty/tools/vulpix/ParallelTesting.scala | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala index 6636ce1895fb..74a148d8f734 100644 --- a/compiler/test/dotty/tools/vulpix/ParallelTesting.scala +++ b/compiler/test/dotty/tools/vulpix/ParallelTesting.scala @@ -290,15 +290,25 @@ trait ParallelTesting extends RunnerOrchestration { self => /** This callback is executed once the compilation of this test source finished */ private final def onComplete(testSource: TestSource, reportersOrCrash: Try[Seq[TestReporter]], logger: LoggedRunnable): Unit = - reportersOrCrash match { - case TryFailure(exn) => onFailure(testSource, Nil, logger, Some(s"Fatal compiler crash when compiling: ${testSource.title}:\n${exn.getMessage}${exn.getStackTrace.map("\n\tat " + _).mkString}")) - case TrySuccess(reporters) if !reporters.exists(_.skipped) => - maybeFailureMessage(testSource, reporters) match { - case Some(msg) => onFailure(testSource, reporters, logger, Option(msg).filter(_.nonEmpty)) - case None => onSuccess(testSource, reporters, logger) + try + reportersOrCrash match + case TryFailure(exn) => onFailure(testSource, Nil, logger, Some(s"Fatal compiler crash when compiling: ${testSource.title}:\n${exn.getMessage}${exn.getStackTrace.map("\n\tat " + _).mkString}")) + case TrySuccess(reporters) if !reporters.exists(_.skipped) => + maybeFailureMessage(testSource, reporters) match { + case Some(msg) => onFailure(testSource, reporters, logger, Option(msg).filter(_.nonEmpty)) + case None => onSuccess(testSource, reporters, logger) + } + case _ => + catch case ex: Throwable => + echo(s"Exception thrown onComplete (probably by a reporter) in $testSource: ${ex.getClass}") + Try(ex.printStackTrace()) + .recover{ _ => + val trace = ex.getStackTrace.map(_.toString) // compute this first in case getStackTrace throws an exception + echo(s"${ex.getClass.getName} message could not be printed due to an exception while computing the message.") + if trace.nonEmpty then trace.foreach(echo) else echo(s"${ex.getClass.getName} stack trace is empty.") } - case _ => - } + .getOrElse(echo(s"${ex.getClass.getName} stack trace could not be printed due to an exception while printing the stack trace.")) + failTestSource(testSource) /** * Based on the reporters obtained after the compilation, determines if this test has failed.