Catch panics that happen within repl step executions

Example session:

```
» 1 + 1
The Roc compiler had an internal error.
Please file a bug report at
    https://github.com/roc-lang/roc/issues/new
Please include the following data:

Error message: intentional panic
Stack backtrace:
   0: std::backtrace_rs::backtrace::libunwind::trace
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/../../backtrace/src/backtrace/libunwind.rs:104:5
   1: std::backtrace_rs::backtrace::trace_unsynchronized
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
   2: std::backtrace::Backtrace::create
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/backtrace.rs:331:13
   3: panic_hook
             at ./crates/repl_cli/src/lib.rs:52:41
   4: call<fn(&core::panic::panic_info::PanicInfo), (&core::panic::panic_info::PanicInfo)>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/ops/function.rs:79:5
   5: <alloc::boxed::Box<F,A> as core::ops::function::Fn<Args>>::call
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/alloc/src/boxed.rs:2029:9
   6: std::panicking::rust_panic_with_hook
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:785:13
   7: std::panicking::begin_panic_handler::{{closure}}
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:651:13
   8: std::sys_common::backtrace::__rust_end_short_backtrace
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/sys_common/backtrace.rs:171:18
   9: rust_begin_unwind
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:647:5
  10: core::panicking::panic_fmt
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/panicking.rs:72:14
  11: step
             at ./crates/repl_ui/src/repl_state.rs:66:9
  12: {closure#1}
             at ./crates/repl_cli/src/lib.rs:109:21
  13: call_once<roc_repl_cli::main::{closure_env#1}, ()>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/ops/function.rs:250:5
  14: call_once<roc_repl_ui::repl_state::ReplAction, roc_repl_cli::main::{closure_env#1}>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/panic/unwind_safe.rs:272:9
  15: do_call<core::panic::unwind_safe::AssertUnwindSafe<roc_repl_cli::main::{closure_env#1}>, roc_repl_ui::repl_state::ReplAction>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:554:40
  16: ___rust_try
  17: try<roc_repl_ui::repl_state::ReplAction, core::panic::unwind_safe::AssertUnwindSafe<roc_repl_cli::main::{closure_env#1}>>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:518:19
  18: catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<roc_repl_cli::main::{closure_env#1}>, roc_repl_ui::repl_state::ReplAction>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panic.rs:142:14
  19: main
             at ./crates/repl_cli/src/lib.rs:108:30
  20: main
             at ./crates/cli/src/main.rs:321:16
  21: call_once<fn() -> core::result::Result<(), std::io::error::Error>, ()>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/ops/function.rs:250:5
  22: __rust_begin_short_backtrace<fn() -> core::result::Result<(), std::io::error::Error>, core::result::Result<(), std::io::error::Error>>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/sys_common/backtrace.rs:155:18
  23: {closure#0}<core::result::Result<(), std::io::error::Error>>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/rt.rs:166:18
  24: core::ops::function::impls::<impl core::ops::function::FnOnce<A> for &F>::call_once
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/core/src/ops/function.rs:284:13
  25: std::panicking::try::do_call
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:554:40
  26: std::panicking::try
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:518:19
  27: std::panic::catch_unwind
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panic.rs:142:14
  28: std::rt::lang_start_internal::{{closure}}
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/rt.rs:148:48
  29: std::panicking::try::do_call
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:554:40
  30: std::panicking::try
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panicking.rs:518:19
  31: std::panic::catch_unwind
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panic.rs:142:14
  32: std::rt::lang_start_internal
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/rt.rs:148:20
  33: lang_start<core::result::Result<(), std::io::error::Error>>
             at /rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/rt.rs:165:17
  34: _main

Machine Target: MacArm64
```
This commit is contained in:
Ayaz Hafiz 2025-01-03 11:05:12 -05:00
parent 2263d8821a
commit a003a16979
No known key found for this signature in database
GPG key ID: 4EBD1C71C734E4D4

View file

@ -17,7 +17,11 @@ use rustyline::highlight::{Highlighter, PromptInfo};
use rustyline::validate::{self, ValidationContext, ValidationResult, Validator};
use rustyline::Config;
use rustyline_derive::{Completer, Helper, Hinter};
use std::any::Any;
use std::backtrace::Backtrace;
use std::borrow::Cow;
use std::panic::{AssertUnwindSafe, PanicInfo};
use std::sync::{Arc, Mutex, OnceLock};
use target_lexicon::Triple;
use crate::cli_gen::eval_llvm;
@ -37,10 +41,25 @@ pub struct ReplHelper {
state: ReplState,
}
static BACKTRACE: OnceLock<Arc<Mutex<Option<String>>>> = OnceLock::new();
fn init_backtrace_storage() {
BACKTRACE.get_or_init(|| Arc::new(Mutex::new(None)));
}
fn panic_hook(_: &PanicInfo) {
if let Some(storage) = BACKTRACE.get() {
*storage.lock().unwrap() = Some(Backtrace::force_capture().to_string());
}
}
pub fn main(has_color: bool, has_header: bool) -> i32 {
use rustyline::error::ReadlineError;
use rustyline::Editor;
init_backtrace_storage();
std::panic::set_hook(Box::new(panic_hook));
let strip_colors_if_necessary = |s: &str| {
if has_color {
s.to_string()
@ -85,7 +104,13 @@ pub fn main(has_color: bool, has_header: bool) -> i32 {
.state;
arena.reset();
match repl_state.step(&arena, line, target, DEFAULT_PALETTE) {
let action = std::panic::catch_unwind(AssertUnwindSafe(|| {
repl_state.step(&arena, line, target, DEFAULT_PALETTE)
}))
.unwrap_or_else(|e| notify_repl_panic(target, e));
match action {
ReplAction::Eval { opt_mono, problems } => {
let output = evaluate(opt_mono, problems, target);
// If there was no output, don't print a blank line!
@ -129,6 +154,37 @@ pub fn main(has_color: bool, has_header: bool) -> i32 {
}
}
fn notify_repl_panic(target: Target, e: Box<dyn Any + Send>) -> ReplAction<'static> {
let message = if let Some(s) = e.downcast_ref::<&str>() {
s.to_string()
} else if let Some(s) = e.downcast_ref::<String>() {
s.clone()
} else {
"Unknown error".to_string()
};
let backtrace = BACKTRACE
.get()
.and_then(|storage| storage.lock().unwrap().take())
.unwrap_or_else(|| "<Backtrace not found>".to_string());
println!(
"\
The Roc compiler had an internal error.
Please file a bug report at
https://github.com/roc-lang/roc/issues/new
Please include the following data:
Error message: {}
Stack backtrace:
{}
Machine Target: {:#?}
",
message, backtrace, target
);
ReplAction::Nothing
}
pub fn evaluate(
opt_mono: Option<MonomorphizedModule<'_>>,
problems: Problems,