Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

### Features

- ts: Re-implement `verifiedBuild` using the OtterSec registry (`verify.osec.io`), replacing the defunct `apr.dev` API ([#4522](https://github.com/solana-foundation/anchor/pull/4522)).

Check warning on line 15 in CHANGELOG.md

View workflow job for this annotation

GitHub Actions / spellcheck

Unknown word (osec)
- ts: Add `decodeIdlAccountRaw` ([#4375](https://github.com/solana-foundation/anchor/pull/4375)).
- cli: Add `--stdout` flag to the `expand` command ([#4400](https://github.com/solana-foundation/anchor/pull/4400)).
- client: Add versioned tx support ([#4207](https://github.com/solana-foundation/anchor/pull/4207)).
Expand All @@ -30,6 +30,7 @@

### Fixes

- lang: Shorten invariant lifetimes during `Context` creation ([#4363](https://github.com/solana-foundation/anchor/pull/4363)).
- ts: Guard recursive IDL layouts against stack overflows while preserving supported recursive types ([#4604](https://github.com/solana-foundation/anchor/pull/4604)).
- idl: Bump version to 0.1.3 ([#4453](https://github.com/solana-foundation/anchor/pull/4453)).
- lang: Migrate `anchor-syn` from syn 1.x to syn 2.0, allowing use of modern Rust syntax ([#4523](https://github.com/solana-foundation/anchor/issues/4523)).
Expand Down
44 changes: 44 additions & 0 deletions lang/syn/src/codegen/accounts/__shorten_invariant_lifetime.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use {
super::{generics, ParsedGenerics},
crate::AccountsStruct,
quote::quote,
};

pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
let name = &accs.ident;
let ParsedGenerics {
combined_generics,
trait_generics: _,
struct_generics,
where_clause,
} = generics(accs);

let shorten_invariant_lifetime = if accs.generics.lt_token.is_some() {
Comment thread
jamie-osec marked this conversation as resolved.
let non_lifetime_generics = struct_generics
.iter()
.skip_while(|g| matches!(g, syn::GenericParam::Lifetime(_)))
.fold(quote! {}, |acc, g| quote! { #acc, #g });
quote! {
pub unsafe fn __shorten_invariant_lifetime<'__a, '__info: '__a>(
Comment thread
jamie-osec marked this conversation as resolved.
value: &'__a mut #name<'__info #non_lifetime_generics>,
) -> &'__a mut #name<'__a #non_lifetime_generics> {
unsafe { ::core::mem::transmute(value) }
}
}
} else {
quote! {
pub fn __shorten_invariant_lifetime(value: &mut Self) -> &mut Self {
value
}
}
};

quote! {
#[automatically_derived]
impl<#combined_generics> #name<#struct_generics> #where_clause {
#[doc(hidden)]
#[inline(always)]
#shorten_invariant_lifetime
}
}
}
3 changes: 3 additions & 0 deletions lang/syn/src/codegen/accounts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use {

pub mod __client_accounts;
pub mod __cpi_client_accounts;
mod __shorten_invariant_lifetime;
mod bumps;
mod constraints;
mod duplicate_mutable_account_keys;
Expand All @@ -24,6 +25,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
let impl_to_account_metas = to_account_metas::generate(accs);
let impl_exit = exit::generate(accs);
let impl_dup_mutable_keys = duplicate_mutable_account_keys::generate(accs);
let impl_shorten_invariant_lifetime = __shorten_invariant_lifetime::generate(accs);
let bumps_struct = bumps::generate(accs);

let program_id = quote! {
Expand All @@ -45,6 +47,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
#impl_to_account_metas
#impl_exit
#impl_dup_mutable_keys
#impl_shorten_invariant_lifetime
#bumps_struct

#__client_accounts_mod
Expand Down
35 changes: 19 additions & 16 deletions lang/syn/src/codegen/program/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,35 +133,38 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
&mut __reallocs,
)?;

unsafe fn __shrink_lifetime<'from, 'to, T>(value: &'from mut T) -> &'to mut T {
#[inline(always)]
unsafe fn __shorten_invariant_lifetime_remaining_accounts<'a, 'info: 'a>(
value: &'a [AccountInfo<'info>],
) -> &'a [AccountInfo<'a>] {
unsafe { ::core::mem::transmute(value) }
}

// Invoke user defined handler.
let result = #program_name::#ix_method_name(
anchor_lang::context::Context::new(
__program_id,
// SAFETY: `__shrink_lifetime` is used to *shrink* the lifetime of
// the inner `AccountInfo` from `'info` to the local function lifetime.
// No lifetime is extended by this operation.
// The lifetime is not shrunk automatically as `RefCell` causes `AccountInfo`
// SAFETY: `__shorten_invariant_lifetime` functions are used to *shrink*
// the lifetime of the inner `AccountInfo`s from `'info` to the local
// function's lifetime. No lifetime is extended by this operation. The
// lifetime is not shrunk automatically as `RefCell` causes `AccountInfo`
// to be invariant.
//
// This is sound provided the following invariants hold:
// (1) The `'info` lifetime strictly outlives the local function
// lifetime; therefore, the transmuted references cannot outlive
// their backing data.
// (2) `AccountInfo` does not implement custom `Drop` logic and does not
// rely on its lifetime parameter during destruction.
// (3) The `Context` value is dropped before the `__accounts` reference
// is dropped or otherwise accessed, preventing any use-after-scope.
//
// * The `'info` lifetime strictly outlives the local function lifetime;
// therefore, the transmuted references cannot outlive their backing
// data.
// * `AccountInfo` does not implement custom `Drop` logic and does not
// rely on its lifetime parameter during destruction.
// * The `Context` value is dropped before the `__accounts` reference
// is dropped or otherwise accessed, preventing any use-after-scope.
//
// This lifetime narrowing is required to conform to the `Context`
// struct's single-lifetime parameterization, which uses a single
// lifetime to keep the API simple and ergonomic.
unsafe {
__shrink_lifetime(&mut __accounts)
},
__remaining_accounts,
unsafe { #accounts_struct_name::__shorten_invariant_lifetime(&mut __accounts) },
unsafe { __shorten_invariant_lifetime_remaining_accounts(__remaining_accounts) },
__bumps,
),
#(#ix_arg_names),*
Expand Down
Loading