parent
1fa31c9410
commit
9f6496d38a
|
@ -67,7 +67,7 @@ fn main() {
|
|||
.expect("Unable to create BPF install directory")
|
||||
.success());
|
||||
|
||||
let rust_programs = ["alloc", "iter", "noop"];
|
||||
let rust_programs = ["alloc", "iter", "noop", "panic"];
|
||||
for program in rust_programs.iter() {
|
||||
println!(
|
||||
"cargo:warning=(not a warning) Building Rust-based BPF programs: solana_bpf_rust_{}",
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins"
|
||||
features = ["c", "mem"]
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
//! @brief Example Rust-based BPF program that prints out the parameters passed to it
|
||||
|
||||
//! @brief Example Rust-based BPF program that test dynamic memory allocation
|
||||
#![no_std]
|
||||
|
||||
#[macro_use]
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins"
|
||||
features = ["c", "mem"]
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! @brief Example Rust-based BPF program that prints out the parameters passed to it
|
||||
//! @brief Example Rust-based BPF program tests loop iteration
|
||||
|
||||
#![no_std]
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins"
|
||||
features = ["c", "mem"]
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
/target/
|
||||
|
||||
Cargo.lock
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
# Note: This crate must be built using build.sh
|
||||
|
||||
[package]
|
||||
name = "solana-bpf-rust-panic"
|
||||
version = "0.15.0"
|
||||
description = "Solana BPF iter program written in Rust"
|
||||
authors = ["Solana Maintainers <maintainers@solana.com>"]
|
||||
repository = "https://github.com/solana-labs/solana"
|
||||
license = "Apache-2.0"
|
||||
homepage = "https://solana.com/"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
solana-sdk-bpf-utils = { path = "../../../../sdk/bpf/rust-utils", version = "0.16.0" }
|
||||
|
||||
[workspace]
|
||||
members = []
|
||||
|
||||
[lib]
|
||||
name = "solana_bpf_rust_panic"
|
||||
crate-type = ["cdylib"]
|
|
@ -0,0 +1,6 @@
|
|||
[dependencies.compiler_builtins]
|
||||
path = "../../../../sdk/bpf/rust-bpf-sysroot/src/compiler-builtins"
|
||||
features = ["c", "mem"]
|
||||
|
||||
[target.bpfel-unknown-unknown.dependencies]
|
||||
alloc = { path = "../../../../sdk/bpf/rust-bpf-sysroot/src/liballoc" }
|
|
@ -0,0 +1,10 @@
|
|||
//! @brief Example Rust-based BPF program that panics
|
||||
|
||||
#![no_std]
|
||||
|
||||
extern crate solana_sdk_bpf_utils;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn entrypoint(_input: *mut u8) -> bool {
|
||||
panic!();
|
||||
}
|
|
@ -41,15 +41,15 @@ mod bpf {
|
|||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
|
||||
let (genesis_block, alice_keypair) = create_genesis_block(50);
|
||||
let (genesis_block, mint_keypair) = create_genesis_block(50);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
// Call user program
|
||||
let program_id = load_program(&bank_client, &alice_keypair, &bpf_loader::id(), elf);
|
||||
let instruction = create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
|
||||
let program_id = load_program(&bank_client, &mint_keypair, &bpf_loader::id(), elf);
|
||||
let instruction = create_invoke_instruction(mint_keypair.pubkey(), program_id, &1u8);
|
||||
bank_client
|
||||
.send_instruction(&alice_keypair, instruction)
|
||||
.send_instruction(&mint_keypair, instruction)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
|
@ -72,23 +72,23 @@ mod bpf {
|
|||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
|
||||
let (genesis_block, alice_keypair) = create_genesis_block(50);
|
||||
let (genesis_block, mint_keypair) = create_genesis_block(50);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
let loader_pubkey = load_program(
|
||||
&bank_client,
|
||||
&alice_keypair,
|
||||
&mint_keypair,
|
||||
&native_loader::id(),
|
||||
"solana_bpf_loader".as_bytes().to_vec(),
|
||||
);
|
||||
|
||||
// Call user program
|
||||
let program_id = load_program(&bank_client, &alice_keypair, &loader_pubkey, elf);
|
||||
let program_id = load_program(&bank_client, &mint_keypair, &loader_pubkey, elf);
|
||||
let instruction =
|
||||
create_invoke_instruction(alice_keypair.pubkey(), program_id, &1u8);
|
||||
create_invoke_instruction(mint_keypair.pubkey(), program_id, &1u8);
|
||||
bank_client
|
||||
.send_instruction(&alice_keypair, instruction)
|
||||
.send_instruction(&mint_keypair, instruction)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -107,38 +107,42 @@ mod bpf {
|
|||
solana_logger::setup();
|
||||
|
||||
let programs = [
|
||||
"solana_bpf_rust_alloc",
|
||||
"solana_bpf_rust_iter",
|
||||
"solana_bpf_rust_noop",
|
||||
("solana_bpf_rust_alloc", true),
|
||||
("solana_bpf_rust_iter", true),
|
||||
("solana_bpf_rust_noop", true),
|
||||
("solana_bpf_rust_panic", false),
|
||||
];
|
||||
for program in programs.iter() {
|
||||
let filename = create_bpf_path(program);
|
||||
println!("Test program: {:?} from {:?}", program, filename);
|
||||
let filename = create_bpf_path(program.0);
|
||||
println!("Test program: {:?} from {:?}", program.0, filename);
|
||||
let mut file = File::open(filename).unwrap();
|
||||
let mut elf = Vec::new();
|
||||
file.read_to_end(&mut elf).unwrap();
|
||||
|
||||
let (genesis_block, alice_keypair) = create_genesis_block(50);
|
||||
let (genesis_block, mint_keypair) = create_genesis_block(50);
|
||||
let bank = Bank::new(&genesis_block);
|
||||
let bank_client = BankClient::new(bank);
|
||||
|
||||
let loader_pubkey = load_program(
|
||||
&bank_client,
|
||||
&alice_keypair,
|
||||
&mint_keypair,
|
||||
&native_loader::id(),
|
||||
"solana_bpf_loader".as_bytes().to_vec(),
|
||||
);
|
||||
|
||||
// Call user program
|
||||
let program_id = load_program(&bank_client, &alice_keypair, &loader_pubkey, elf);
|
||||
let program_id = load_program(&bank_client, &mint_keypair, &loader_pubkey, elf);
|
||||
let account_metas = vec![
|
||||
AccountMeta::new(alice_keypair.pubkey(), true),
|
||||
AccountMeta::new(mint_keypair.pubkey(), true),
|
||||
AccountMeta::new(Keypair::new().pubkey(), false),
|
||||
];
|
||||
let instruction = Instruction::new(program_id, &1u8, account_metas);
|
||||
bank_client
|
||||
.send_instruction(&alice_keypair, instruction)
|
||||
.unwrap();
|
||||
let result = bank_client.send_instruction(&mint_keypair, instruction);
|
||||
if program.1 {
|
||||
assert!(result.is_ok());
|
||||
} else {
|
||||
assert!(result.is_err());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,31 @@ use allocator_bump::BPFAllocator;
|
|||
/// are expected to enforce this
|
||||
const DEFAULT_HEAP_SIZE: usize = 32 * 1024;
|
||||
|
||||
/// Verifies a string passed out of the program
|
||||
fn verify_string(addr: u64, ro_regions: &[MemoryRegion]) -> Result<(()), Error> {
|
||||
for region in ro_regions.iter() {
|
||||
if region.addr <= addr && (addr as u64) < region.addr + region.len {
|
||||
let c_buf: *const c_char = addr as *const c_char;
|
||||
let max_size = region.addr + region.len - addr;
|
||||
unsafe {
|
||||
for i in 0..max_size {
|
||||
if std::ptr::read(c_buf.offset(i as isize)) == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(Error::new(ErrorKind::Other, "Error, Unterminated string"));
|
||||
}
|
||||
}
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Error: Load segfault, bad string pointer",
|
||||
))
|
||||
}
|
||||
|
||||
/// Abort helper functions, called when the BPF program calls `abort()`
|
||||
/// The verify function returns an error which will cause the BPF program
|
||||
/// to be halted immediately
|
||||
pub fn helper_abort_verify(
|
||||
_arg1: u64,
|
||||
_arg2: u64,
|
||||
|
@ -69,16 +93,29 @@ pub fn helper_abort(
|
|||
/// The verify function returns an error which will cause the BPF program
|
||||
/// to be halted immediately
|
||||
pub fn helper_sol_panic_verify(
|
||||
_arg1: u64,
|
||||
_arg2: u64,
|
||||
_arg3: u64,
|
||||
file: u64,
|
||||
line: u64,
|
||||
column: u64,
|
||||
_arg4: u64,
|
||||
_arg5: u64,
|
||||
_context: &mut Option<Box<Any + 'static>>,
|
||||
_ro_regions: &[MemoryRegion],
|
||||
ro_regions: &[MemoryRegion],
|
||||
_rw_regions: &[MemoryRegion],
|
||||
) -> Result<(()), Error> {
|
||||
Err(Error::new(ErrorKind::Other, "Error: BPF program Panic!"))
|
||||
if verify_string(file, ro_regions).is_ok() {
|
||||
let c_buf: *const c_char = file as *const c_char;
|
||||
let c_str: &CStr = unsafe { CStr::from_ptr(c_buf) };
|
||||
if let Ok(slice) = c_str.to_str() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
format!(
|
||||
"Error: BPF program Panicked at {}, {}:{}",
|
||||
slice, line, column
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
Err(Error::new(ErrorKind::Other, "Error: BPF program Panicked"))
|
||||
}
|
||||
pub fn helper_sol_panic(
|
||||
_arg1: u64,
|
||||
|
@ -105,24 +142,7 @@ pub fn helper_sol_log_verify(
|
|||
ro_regions: &[MemoryRegion],
|
||||
_rw_regions: &[MemoryRegion],
|
||||
) -> Result<(()), Error> {
|
||||
for region in ro_regions.iter() {
|
||||
if region.addr <= addr && (addr as u64) < region.addr + region.len {
|
||||
let c_buf: *const c_char = addr as *const c_char;
|
||||
let max_size = region.addr + region.len - addr;
|
||||
unsafe {
|
||||
for i in 0..max_size {
|
||||
if std::ptr::read(c_buf.offset(i as isize)) == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
return Err(Error::new(ErrorKind::Other, "Error, Unterminated string"));
|
||||
}
|
||||
}
|
||||
Err(Error::new(
|
||||
ErrorKind::Other,
|
||||
"Error: Load segfault, bad string pointer",
|
||||
))
|
||||
verify_string(addr, ro_regions)
|
||||
}
|
||||
pub fn helper_sol_log(
|
||||
addr: u64,
|
||||
|
|
|
@ -1,36 +1,32 @@
|
|||
//! @brief Solana Rust-based BPF program panic handling
|
||||
|
||||
use crate::log::*;
|
||||
use core::fmt::{self, Write};
|
||||
use core::panic::PanicInfo;
|
||||
|
||||
#[cfg(not(test))]
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo) -> ! {
|
||||
sol_log("Panic!");
|
||||
// TODO crashes! sol_log(_info.payload().downcast_ref::<&str>().unwrap());
|
||||
if let Some(location) = info.location() {
|
||||
if !location.file().is_empty() {
|
||||
// TODO location.file() returns empty str, if we get here its been fixed
|
||||
sol_log(location.file());
|
||||
sol_log("location.file() is fixed!!");
|
||||
match info.location() {
|
||||
Some(location) => {
|
||||
let mut file: [u8; 128] = [0; 128];
|
||||
for (i, c) in location.file().as_bytes().iter().enumerate() {
|
||||
if i >= 126 {
|
||||
break;
|
||||
}
|
||||
file[i] = *c;
|
||||
}
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
sol_panic_(
|
||||
file.as_ptr(),
|
||||
u64::from(location.line()),
|
||||
u64::from(location.column()),
|
||||
);
|
||||
}
|
||||
}
|
||||
sol_log_64(
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
u64::from(location.line()),
|
||||
u64::from(location.column()),
|
||||
);
|
||||
} else {
|
||||
sol_log("Panic!, but could not get location information");
|
||||
}
|
||||
unsafe {
|
||||
sol_panic_();
|
||||
None => unsafe { sol_panic_(0 as *const u8, 0, 0) },
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
pub fn sol_panic_() -> !;
|
||||
pub fn sol_panic_(message: *const u8, line: u64, column: u64) -> !;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue