assert-type-assumptions (#23996)

This commit is contained in:
Jack May 2022-03-30 08:28:49 -07:00 committed by GitHub
parent 1fb82d7924
commit 37497657c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 174 additions and 8 deletions

1
Cargo.lock generated
View File

@ -5434,6 +5434,7 @@ dependencies = [
"lazy_static",
"libsecp256k1 0.6.0",
"log",
"memoffset",
"num-derive",
"num-traits",
"parking_lot 0.12.0",

View File

@ -3642,6 +3642,7 @@ dependencies = [
"lazy_static",
"libsecp256k1 0.6.0",
"log",
"memoffset",
"num-derive",
"num-traits",
"parking_lot",

View File

@ -4,7 +4,8 @@
extern crate solana_program;
use solana_program::{
account_info::AccountInfo, bpf_loader, entrypoint::ProgramResult, log::*, msg, pubkey::Pubkey,
account_info::AccountInfo, bpf_loader, entrypoint::ProgramResult, log::*, msg,
program::check_type_assumptions, pubkey::Pubkey,
};
#[derive(Debug, PartialEq)]
@ -70,6 +71,8 @@ pub fn process_instruction(
assert!(1.9986f64 < num && num < 2.0f64);
}
check_type_assumptions();
sol_log_compute_units();
Ok(())
}

View File

@ -1428,7 +1428,7 @@ fn assert_instruction_count() {
("sanity", 2378),
("sanity++", 2278),
("secp256k1_recover", 25383),
("sha", 1895),
("sha", 1355),
("struct_pass", 108),
("struct_ret", 122),
]);
@ -1448,9 +1448,9 @@ fn assert_instruction_count() {
("solana_bpf_rust_noop", 315),
("solana_bpf_rust_param_passing", 146),
("solana_bpf_rust_rand", 418),
("solana_bpf_rust_sanity", 9128),
("solana_bpf_rust_sanity", 52170),
("solana_bpf_rust_secp256k1_recover", 25707),
("solana_bpf_rust_sha", 27033),
("solana_bpf_rust_sha", 25338),
]);
}

View File

@ -3541,6 +3541,7 @@ mod tests {
bpf_loader,
fee_calculator::FeeCalculator,
hash::hashv,
program::check_type_assumptions,
sysvar::{clock::Clock, epoch_schedule::EpochSchedule, rent::Rent},
transaction_context::TransactionContext,
},
@ -4906,9 +4907,6 @@ mod tests {
#[test]
fn test_check_type_assumptions() {
// Code in this file assumes that u64 and usize are the same
assert_eq!(size_of::<u64>(), size_of::<usize>());
// Code in this file assumes that u8 is byte aligned
assert_eq!(1, align_of::<u8>());
check_type_assumptions();
}
}

View File

@ -21,6 +21,7 @@ bv = { version = "0.11.1", features = ["serde"] }
itertools = "0.10.1"
lazy_static = "1.4.0"
log = "0.4.14"
memoffset = "0.6"
num-derive = "0.3"
num-traits = "0.2"
rustversion = "1.0.3"

View File

@ -138,3 +138,165 @@ pub fn get_return_data() -> Option<(Pubkey, Vec<u8>)> {
#[cfg(not(target_arch = "bpf"))]
crate::program_stubs::sol_get_return_data()
}
#[allow(clippy::integer_arithmetic)]
pub fn check_type_assumptions() {
extern crate memoffset;
use {
crate::{clock::Epoch, instruction::AccountMeta},
memoffset::offset_of,
std::{
cell::RefCell,
mem::{align_of, size_of},
rc::Rc,
str::FromStr,
},
};
// Code in this file assumes that u64 and usize are the same
assert_eq!(size_of::<u64>(), size_of::<usize>());
// Code in this file assumes that u8 is byte aligned
assert_eq!(1, align_of::<u8>());
// Enforce Instruction layout
{
assert_eq!(size_of::<AccountMeta>(), 32 + 1 + 1);
let pubkey1 = Pubkey::from_str("J9PYCcoKusHyKRMXnBL17VTXC3MVETyqBG2KyLXVv6Ai").unwrap();
let pubkey2 = Pubkey::from_str("Hvy4GHgPToZNoENTKjC4mJqpzWWjgTwXrFufKfxYiKkV").unwrap();
let pubkey3 = Pubkey::from_str("JDMyRL8rCkae7maCSv47upNuBMFd3Mgos1fz2AvYzVzY").unwrap();
let account_meta1 = AccountMeta {
pubkey: pubkey2,
is_signer: true,
is_writable: false,
};
let account_meta2 = AccountMeta {
pubkey: pubkey3,
is_signer: false,
is_writable: true,
};
let data = vec![1, 2, 3, 4, 5];
let instruction = Instruction {
program_id: pubkey1,
accounts: vec![account_meta1.clone(), account_meta2.clone()],
data: data.clone(),
};
let instruction_addr = &instruction as *const _ as u64;
// program id
assert_eq!(offset_of!(Instruction, program_id), 48);
let pubkey_ptr = (instruction_addr + 48) as *const Pubkey;
unsafe {
assert_eq!(*pubkey_ptr, pubkey1);
}
// accounts
assert_eq!(offset_of!(Instruction, accounts), 0);
let accounts_ptr = (instruction_addr) as *const *const AccountMeta;
let accounts_cap = (instruction_addr + 8) as *const usize;
let accounts_len = (instruction_addr + 16) as *const usize;
unsafe {
assert_eq!(*accounts_cap, 2);
assert_eq!(*accounts_len, 2);
let account_meta_ptr = *accounts_ptr;
assert_eq!(*account_meta_ptr, account_meta1);
assert_eq!(*(account_meta_ptr.offset(1)), account_meta2);
}
// data
assert_eq!(offset_of!(Instruction, data), 24);
let data_ptr = (instruction_addr + 24) as *const *const [u8; 5];
let data_cap = (instruction_addr + 24 + 8) as *const usize;
let data_len = (instruction_addr + 24 + 16) as *const usize;
unsafe {
assert_eq!(*data_cap, 5);
assert_eq!(*data_len, 5);
let u8_ptr = *data_ptr;
assert_eq!(*u8_ptr, data[..]);
}
}
// Enforce AccountInfo layout
{
let key = Pubkey::from_str("6o8R9NsUxNskF1MfWM1f265y4w86JYbEwqCmTacdLkHp").unwrap();
let mut lamports = 31;
let mut data = vec![1, 2, 3, 4, 5];
let owner = Pubkey::from_str("2tjK4XyNU54XdN9jokx46QzLybbLVGwQQvTfhcuBXAjR").unwrap();
let account_info = AccountInfo {
key: &key,
is_signer: true,
is_writable: false,
lamports: Rc::new(RefCell::new(&mut lamports)),
data: Rc::new(RefCell::new(&mut data)),
owner: &owner,
executable: true,
rent_epoch: 42,
};
let account_info_addr = &account_info as *const _ as u64;
// key
assert_eq!(offset_of!(AccountInfo, key), 0);
let key_ptr = (account_info_addr) as *const &Pubkey;
unsafe {
assert_eq!(**key_ptr, key);
}
// is_signer
assert_eq!(offset_of!(AccountInfo, is_signer), 40);
let is_signer_ptr = (account_info_addr + 40) as *const bool;
unsafe {
assert!(*is_signer_ptr);
}
// is_writable
assert_eq!(offset_of!(AccountInfo, is_writable), 41);
let is_writable_ptr = (account_info_addr + 41) as *const bool;
unsafe {
assert!(!*is_writable_ptr);
}
// lamports
assert_eq!(offset_of!(AccountInfo, lamports), 8);
let lamports_ptr = (account_info_addr + 8) as *const Rc<RefCell<&mut u64>>;
unsafe {
assert_eq!(**(*lamports_ptr).as_ptr(), 31);
}
// data
assert_eq!(offset_of!(AccountInfo, data), 16);
let data_ptr = (account_info_addr + 16) as *const Rc<RefCell<&mut [u8]>>;
unsafe {
assert_eq!((*(*data_ptr).as_ptr())[..], data[..]);
}
// owner
assert_eq!(offset_of!(AccountInfo, owner), 24);
let owner_ptr = (account_info_addr + 24) as *const &Pubkey;
unsafe {
assert_eq!(**owner_ptr, owner);
}
// executable
assert_eq!(offset_of!(AccountInfo, executable), 42);
let executable_ptr = (account_info_addr + 42) as *const bool;
unsafe {
assert!(*executable_ptr);
}
// rent_epoch
assert_eq!(offset_of!(AccountInfo, rent_epoch), 32);
let renbt_epoch_ptr = (account_info_addr + 32) as *const Epoch;
unsafe {
assert_eq!(*renbt_epoch_ptr, 42);
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn test_check_type_assumptions() {
super::check_type_assumptions()
}
}