Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom compiler crash/panic handler #731

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 109 additions & 6 deletions effekt/jvm/src/main/scala/effekt/Driver.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import effekt.context.{ Context, IOModuleDB }
import kiama.output.PrettyPrinterTypes.Document
import kiama.parsing.ParseResult
import kiama.util.{ IO, Source }
import effekt.util.messages.{ BufferedMessaging, CompilerPanic, EffektError, EffektMessaging, FatalPhaseError }
import effekt.util.messages.{ BufferedMessaging, CompilerPanic, EffektError, EffektMessaging, FatalPhaseError, PlainTextError }
import effekt.util.paths.file
import effekt.util.{ AnsiColoredMessaging, MarkdownSource, getOrElseAborting }

Expand Down Expand Up @@ -88,11 +88,8 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
}
} catch {
case FatalPhaseError(msg) => context.report(msg)
case e @ CompilerPanic(msg) =>
context.report(msg)
e.getStackTrace.foreach { line =>
context.info(" at " + line)
}
case e @ CompilerPanic(msg) => generateCrashReport(e, context, config, msg)

// when in server-mode, do not crash but report the error to avoid
// restarting the server.
case e if config.server() =>
Expand All @@ -108,6 +105,112 @@ trait Driver extends kiama.util.Compiler[EffektConfig, EffektError] { outer =>
afterCompilation(source, config)(context)
}

def generateCrashReport(e: Throwable, context: Context, config: EffektConfig, msg:effekt. util. messages. EffektError): Unit = {
import java.nio.file.{Files, Paths}
import java.nio.charset.StandardCharsets

// Capture general information
val errorMessage = msg match {
case PlainTextError(content, _, _) => content
case _ => msg
}


val effektVersion = effekt.util.Version.effektVersion
val osInfoName = System.getProperty("os.name")
val osInfoArch = System.getProperty("os.arch")
val osInfoVersion = System.getProperty("os.version")

val javaInfoVersion = System.getProperty("java.version")
val javaInfoVendor = System.getProperty("java.vendor")
val javaInfoRuntime = System.getProperty("java.runtime.name")

val errorReport = "The compiler unexpectedly panicked. This is a compiler bug.\nPlease report it:"
val issueLink = "https://github.com/effekt-lang/effekt/issues/new?labels=bug"
val stringWriter = new java.io.StringWriter()
e.printStackTrace(new java.io.PrintWriter(stringWriter))
val stackTrace = stringWriter.toString

// Collect backend details (if applicable)
val backendInfoName = config.backend() match {
case Backend(name, _, _) => name
case null => "Backend-specific info Name not retrievable"
}

// Arguments passed to the compiler
val argsMarkdown = config.args.mkString("\n", "\n", "\n")

// Construct the report content
val reportContent =
s"""|# Effekt Compiler Crash Report
|
|**ERROR** : $errorMessage
|
|$errorReport
|[Submit an issue]($issueLink)
|
|### Compiler Information
|Effekt Version: $effektVersion \n
|Backend: $backendInfoName
|
|### System Information
|Operating System: $osInfoName \n Arch: $osInfoArch \n Version: $osInfoVersion
|
|JVM Version: $javaInfoVersion ($javaInfoVendor, $javaInfoRuntime)
|
|### Full Stack Trace
|```
|$stackTrace
|```
|
|### Arguments Passed to the Compiler
|```
|$argsMarkdown
|```
|""".stripMargin

// Write the report to a Markdown file
val outputPath = Paths.get(config.outputPath().getAbsolutePath)
val outputFile = outputPath.resolve("crash-report.md")
try {
Files.createDirectories(outputPath.getParent)
Files.write(outputFile, reportContent.getBytes(StandardCharsets.UTF_8))
//context.info(s"Crash report saved to: $outputPath")
} catch {
case ex: Exception =>
context.info("Failed to save crash report to file: " + ex.getMessage)
}

// Provide the report link in the user-visible output
val report =
s"""|=== Effekt Compiler Crash Report ===
|
|[Error] $errorMessage
|
|The compiler unexpectedly panicked. This is a compiler bug.
|Please report it: $issueLink
|
|Effekt Version: $effektVersion\n
|Backend used: $backendInfoName
|
|A detailed crash report has been written to:
|${outputPath.toAbsolutePath}
|
|Operating System: $osInfoName
|
|JVM Version: $javaInfoVersion
|
|Full Stack Trace:
|$stackTrace
|
|Arguments passed to the compiler:
|$argsMarkdown
|""".stripMargin

// Print the report to console
context.info(report)
}

/**
* Outputs the timing information captured in [[effekt.util.Timers]] by [[effekt.context.Context]]. Either a JSON file
* is written to disk or a plain text message is written to stdout.
Expand Down
Loading