Safe Panic Handling in Rust: The Graceful Recovery System
Rust's panic system is powerful, but uncontrolled panics can lead to application crashes. This challenge focuses on building a simple, safe panic recovery system that allows a program to attempt graceful recovery after a panic, logging the error and potentially continuing execution instead of abruptly terminating. This is crucial for building robust and resilient applications, especially in long-running processes or embedded systems.
Problem Description
You are tasked with creating a module named panic_handler that provides a safe and configurable panic handler for Rust programs. The module should:
- Intercept Panics: Replace the default panic handler with a custom handler defined within the
panic_handlermodule. - Log Panic Information: When a panic occurs, the handler should log the panic message and backtrace to a designated output (e.g.,
stderr). The logging mechanism should be configurable (see "Configuration" below). - Attempt Recovery (Optional): After logging, the handler should attempt a recovery action. For this challenge, the recovery action is simply to print a message indicating recovery was attempted. This can be extended in future implementations.
- Unwind (or Abort): After logging and attempting recovery, the handler should either unwind the stack (allowing the program to continue execution if possible) or abort (terminating the program immediately). The choice between unwinding and aborting should be configurable.
- Configuration: The panic handler should be configurable via a struct
PanicConfigwith the following fields:log_panic: A boolean indicating whether to log the panic information. Defaults totrue.attempt_recovery: A boolean indicating whether to attempt recovery. Defaults totrue.unwind_on_panic: A boolean indicating whether to unwind the stack after logging and recovery. Defaults totrue.
Key Requirements:
- The panic handler must be thread-safe.
- The panic handler must not itself panic.
- The panic handler must be configurable at runtime.
- The logging mechanism should be abstract enough to allow for different logging implementations (e.g., writing to a file, sending to a remote server). For this challenge, simply printing to
stderris sufficient. - The code must adhere to Rust's safety rules.
Expected Behavior:
When a panic occurs, the program should:
- Call the configured panic handler.
- If
log_panicis true, log the panic message and backtrace tostderr. - If
attempt_recoveryis true, print a message indicating recovery was attempted. - If
unwind_on_panicis true, unwind the stack. Otherwise, abort the program.
Edge Cases to Consider:
- Panics occurring in threads other than the main thread.
- Panics occurring during initialization.
- The panic handler itself encountering an error (though it should be designed to avoid this).
Examples
Example 1:
Input: A program panics with the message "Division by zero!".
Output:
[01:23:45] Panic: Division by zero!
[01:23:45] Backtrace: ... (backtrace information)
[01:23:45] Recovery attempt initiated.
Explanation: The panic is logged to stderr, a recovery attempt message is printed, and the program unwinds (if `unwind_on_panic` is true).
Example 2:
Input: A program panics with the message "Out of memory!". `PanicConfig` is set to `log_panic = false`, `attempt_recovery = false`, and `unwind_on_panic = false`.
Output:
(Program aborts immediately with no output)
Explanation: Because logging and recovery are disabled, and unwinding is also disabled, the program immediately aborts.
Example 3: (Edge Case)
Input: A panic occurs in a separate thread.
Output:
[01:23:45] Panic: Thread panic message
[01:23:45] Backtrace: ... (backtrace information)
[01:23:45] Recovery attempt initiated.
Explanation: The panic handler correctly intercepts and handles the panic from the separate thread, logging and attempting recovery as configured.
Constraints
- The
panic_handlermodule must be self-contained and reusable. - The logging mechanism should be simple (printing to
stderris sufficient). - The recovery action is limited to printing a message.
- The code must compile and run without warnings.
- The solution should be less than 100 lines of code.
Notes
- Consider using the
std::panic::panic_handlerfunction to replace the default panic handler. - The
std::backtracemodule can be used to obtain backtrace information. - Think about how to make the logging mechanism more flexible for future extensions.
- Focus on safety and correctness. Avoid any unsafe code unless absolutely necessary, and if so, document it thoroughly.
- The goal is to demonstrate a safe and configurable panic handling mechanism, not to create a production-ready panic recovery system.