provide full Rust panic messages in BPF and add memory optimizations (#13455)
This commit is contained in:
parent
c644b05c54
commit
461ae40eea
|
@ -270,6 +270,65 @@ info!(&format!("Some varialbe: {:?}", variable));
|
|||
The [debugging](debugging.md#logging) section has more information about working
|
||||
with program logs.
|
||||
|
||||
## Panicking
|
||||
|
||||
Rust's `panic!`, `assert!`, and internal panic results are printed to the
|
||||
[program logs](debugging.md#logging) by default.
|
||||
|
||||
```
|
||||
INFO solana_runtime::message_processor] Finalized account CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ
|
||||
INFO solana_runtime::message_processor] Call BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ
|
||||
INFO solana_runtime::message_processor] Program log: Panicked at: 'assertion failed: `(left == right)`
|
||||
left: `1`,
|
||||
right: `2`', rust/panic/src/lib.rs:22:5
|
||||
INFO solana_runtime::message_processor] BPF program consumed 5453 of 200000 units
|
||||
INFO solana_runtime::message_processor] BPF program CGLhHSuWsp1gT4B7MY2KACqp9RUwQRhcUFfVSuxpSajZ failed: BPF program panicked
|
||||
```
|
||||
|
||||
### Custom Panic Handler
|
||||
|
||||
Programs can override the default panic handler by providing their own
|
||||
implementation.
|
||||
|
||||
First define the `custom-panic` feature in the program's `Cargo.toml`
|
||||
|
||||
```toml
|
||||
[features]
|
||||
default = ["custom-panic"]
|
||||
custom-panic = []
|
||||
```
|
||||
|
||||
Then provide a custom implementation of the panic handler:
|
||||
|
||||
```rust
|
||||
#[cfg(all(feature = "custom-panic", target_arch = "bpf"))]
|
||||
#[no_mangle]
|
||||
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
|
||||
solana_program::info!("program custom panic enabled");
|
||||
solana_program::info!(&format!("{}", info));
|
||||
}
|
||||
```
|
||||
|
||||
In the above snippit, the default implementation is shown, but developers may
|
||||
replace that with something that better suits their needs.
|
||||
|
||||
One of the side effects of supporting full panic messages by default is that
|
||||
programs incur the cost of pulling in more of Rust's `libstd` implementation
|
||||
into program's shared object. Typical programs will already be pulling in a
|
||||
fair amount of `libstd` and may not notice much of an increase in the shared
|
||||
object size. But programs that explicitly attempt to be very small by avoiding
|
||||
`libstd` may take a significant impact (~25kb). To eliminate that impact,
|
||||
programs can provide their own custom panic handler with an empty
|
||||
implementation.
|
||||
|
||||
```rust
|
||||
#[cfg(all(feature = "custom-panic", target_arch = "bpf"))]
|
||||
#[no_mangle]
|
||||
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
|
||||
// Do nothing to save space
|
||||
}
|
||||
```
|
||||
|
||||
## Compute Budget
|
||||
|
||||
Use the system call
|
||||
|
|
|
@ -11,6 +11,10 @@ edition = "2018"
|
|||
[dependencies]
|
||||
solana-program = { path = "../../../../sdk/program", version = "1.5.0" }
|
||||
|
||||
[features]
|
||||
default = ["custom-panic"]
|
||||
custom-panic = []
|
||||
|
||||
[lib]
|
||||
name = "solana_bpf_rust_panic"
|
||||
crate-type = ["cdylib"]
|
||||
|
|
|
@ -1,8 +1,24 @@
|
|||
//! @brief Example Rust-based BPF program that panics
|
||||
|
||||
extern crate solana_program;
|
||||
|
||||
#[cfg(all(feature = "custom-panic", target_arch = "bpf"))]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entrypoint(_input: *mut u8) -> u64 {
|
||||
panic!();
|
||||
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
|
||||
// Note: Full panic reporting is included here for testing purposes
|
||||
solana_program::info!("program custom panic enabled");
|
||||
solana_program::info!(&format!("{}", info));
|
||||
}
|
||||
|
||||
extern crate solana_program;
|
||||
use solana_program::{
|
||||
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, pubkey::Pubkey,
|
||||
};
|
||||
|
||||
entrypoint!(process_instruction);
|
||||
fn process_instruction(
|
||||
_program_id: &Pubkey,
|
||||
_accounts: &[AccountInfo],
|
||||
_instruction_data: &[u8],
|
||||
) -> ProgramResult {
|
||||
assert_eq!(1, 2);
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -533,11 +533,7 @@ fn test_program_bpf_invoke() {
|
|||
&[TEST_SUCCESS, bump_seed1, bump_seed2, bump_seed3],
|
||||
account_metas.clone(),
|
||||
);
|
||||
let noop_instruction = Instruction::new(
|
||||
noop_program_id,
|
||||
&(),
|
||||
vec![]
|
||||
);
|
||||
let noop_instruction = Instruction::new(noop_program_id, &(), vec![]);
|
||||
let message = Message::new(&[instruction, noop_instruction], Some(&mint_pubkey));
|
||||
let tx = Transaction::new(
|
||||
&[
|
||||
|
@ -763,8 +759,8 @@ fn assert_instruction_count() {
|
|||
("multiple_static", 8),
|
||||
("noop", 57),
|
||||
("relative_call", 10),
|
||||
("sanity", 1140),
|
||||
("sanity++", 1140),
|
||||
("sanity", 176),
|
||||
("sanity++", 176),
|
||||
("struct_pass", 8),
|
||||
("struct_ret", 22),
|
||||
]);
|
||||
|
@ -772,16 +768,16 @@ fn assert_instruction_count() {
|
|||
#[cfg(feature = "bpf_rust")]
|
||||
{
|
||||
programs.extend_from_slice(&[
|
||||
("solana_bpf_rust_128bit", 543),
|
||||
("solana_bpf_rust_alloc", 19082),
|
||||
("solana_bpf_rust_128bit", 572),
|
||||
("solana_bpf_rust_alloc", 12777),
|
||||
("solana_bpf_rust_dep_crate", 2),
|
||||
("solana_bpf_rust_external_spend", 538),
|
||||
("solana_bpf_rust_iter", 723),
|
||||
("solana_bpf_rust_many_args", 231),
|
||||
("solana_bpf_rust_iter", 724),
|
||||
("solana_bpf_rust_many_args", 237),
|
||||
("solana_bpf_rust_noop", 488),
|
||||
("solana_bpf_rust_param_passing", 46),
|
||||
("solana_bpf_rust_param_passing", 48),
|
||||
("solana_bpf_rust_ristretto", 19399),
|
||||
("solana_bpf_rust_sanity", 1965),
|
||||
("solana_bpf_rust_sanity", 894),
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ use thiserror::Error as ThisError;
|
|||
pub enum SyscallError {
|
||||
#[error("{0}: {1:?}")]
|
||||
InvalidString(Utf8Error, Vec<u8>),
|
||||
#[error("BPF program called abort()!")]
|
||||
#[error("BPF program panicked")]
|
||||
Abort,
|
||||
#[error("BPF program Panicked in {0} at {1}:{2}")]
|
||||
Panic(String, u64, u64),
|
||||
|
|
|
@ -174,7 +174,7 @@ if [[ ! -e rust-bpf-$machine-$version.md || ! -e rust-bpf-$machine ]]; then
|
|||
fi
|
||||
|
||||
# Install Rust-BPF Sysroot sources
|
||||
version=v0.12
|
||||
version=v0.13
|
||||
if [[ ! -e rust-bpf-sysroot-$version.md || ! -e rust-bpf-sysroot ]]; then
|
||||
(
|
||||
set -e
|
||||
|
|
|
@ -45,13 +45,31 @@ pub const HEAP_LENGTH: usize = 32 * 1024;
|
|||
#[macro_export]
|
||||
macro_rules! entrypoint {
|
||||
($process_instruction:ident) => {
|
||||
#[cfg(all(not(feature = "custom-heap"), not(test)))]
|
||||
/// A program can provide their own custom heap implementation by adding
|
||||
/// a `custom-heap` feature to `Cargo.toml` and implementing their own
|
||||
/// `global_allocator`.
|
||||
#[cfg(all(not(feature = "custom-heap"), target_arch = "bpf"))]
|
||||
#[global_allocator]
|
||||
static A: $crate::entrypoint::BumpAllocator = $crate::entrypoint::BumpAllocator {
|
||||
start: $crate::entrypoint::HEAP_START_ADDRESS,
|
||||
len: $crate::entrypoint::HEAP_LENGTH,
|
||||
};
|
||||
|
||||
/// A program can provide their own custom panic implementation by
|
||||
/// adding a `custom-panic` feature to `Cargo.toml` and implementing
|
||||
/// their own `custom_panic`.
|
||||
///
|
||||
/// A good way to reduce the final size of the program is to provide a
|
||||
/// `custom_panic` implementation that does nothing. Doing so will cut
|
||||
/// ~25kb from a noop program. That number goes down the more the
|
||||
/// programs pulls in Rust's libstd for other purposes.
|
||||
#[cfg(all(not(feature = "custom-panic"), target_arch = "bpf"))]
|
||||
#[no_mangle]
|
||||
fn custom_panic(info: &core::panic::PanicInfo<'_>) {
|
||||
// Full panic reporting
|
||||
$crate::info!(&format!("{}", info));
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn entrypoint(input: *mut u8) -> u64 {
|
||||
|
|
Loading…
Reference in New Issue