@@ -158,13 +158,31 @@ pub trait SysvarSerialize:
158158 }
159159}
160160
161- /// Implements the [`Sysvar::get`] method for both SBF and host targets .
161+ /// Helper for conditional bool validation. Expands to a check or nothing .
162162#[ macro_export]
163- macro_rules! impl_sysvar_get {
163+ #[ doc( hidden) ]
164+ macro_rules! __maybe_check_final_bool {
165+ ( true , $var_addr: ident, $length: ident) => {
166+ let bool_byte = * $var_addr. add( $length - 1 ) ;
167+ if bool_byte > 1 {
168+ return Err ( $crate:: __private:: ProgramError :: InvalidAccountData ) ;
169+ }
170+ } ;
171+ ( false , $var_addr: ident, $length: ident) => { } ;
172+ }
173+
174+ /// Internal macro that implements [`Sysvar::get`] with optional bool validation.
175+ ///
176+ /// Not intended for direct use. Use [`impl_sysvar_get`] or
177+ /// [`impl_sysvar_get_check_final_bool`] instead.
178+ #[ macro_export]
179+ #[ doc( hidden) ]
180+ macro_rules! __impl_sysvar_get_internal {
164181 // DEPRECATED: This variant is only for the deprecated Fees sysvar and should be
165182 // removed once Fees is no longer in use. It uses the old-style direct syscall
166183 // approach instead of the new sol_get_sysvar syscall.
167- ( $syscall_name: ident) => {
184+ // The check_final_bool parameter is ignored for this deprecated path.
185+ ( $syscall_name: ident, $_check_final_bool: tt) => {
168186 fn get( ) -> Result <Self , $crate:: __private:: ProgramError > {
169187 let mut var = Self :: default ( ) ;
170188 let var_addr = & mut var as * mut _ as * mut u8 ;
@@ -185,7 +203,8 @@ macro_rules! impl_sysvar_get {
185203 // (size - padding bytes) and zeros the padding to avoid undefined behavior.
186204 // Only supports sysvars where padding is at the end of the layout. Caller
187205 // must supply the correct number of padding bytes.
188- ( $sysvar_id: expr, $padding: literal) => {
206+ // If check_final_bool is true, validates that the final byte is 0x00 or 0x01.
207+ ( $sysvar_id: expr, $padding: literal, $check_final_bool: tt) => {
189208 fn get( ) -> Result <Self , $crate:: __private:: ProgramError > {
190209 let mut var = core:: mem:: MaybeUninit :: <Self >:: uninit( ) ;
191210 let var_addr = var. as_mut_ptr( ) as * mut u8 ;
@@ -201,6 +220,7 @@ macro_rules! impl_sysvar_get {
201220 // SAFETY: All bytes now initialized: syscall filled data
202221 // bytes and we zeroed padding.
203222 unsafe {
223+ $crate:: __maybe_check_final_bool!( $check_final_bool, var_addr, length) ;
204224 var_addr. add( length) . write_bytes( 0 , $padding) ;
205225 Ok ( var. assume_init( ) )
206226 }
@@ -211,8 +231,46 @@ macro_rules! impl_sysvar_get {
211231 }
212232 } ;
213233 // Variant for sysvars without padding (struct size matches bincode size).
234+ ( $sysvar_id: expr, $check_final_bool: tt) => {
235+ $crate:: __impl_sysvar_get_internal!( $sysvar_id, 0 , $check_final_bool) ;
236+ } ;
237+ }
238+
239+ /// Implements the [`Sysvar::get`] method for both SBF and host targets.
240+ #[ macro_export]
241+ macro_rules! impl_sysvar_get {
242+ // DEPRECATED: This variant is only for the deprecated Fees sysvar.
243+ ( $syscall_name: ident) => {
244+ $crate:: __impl_sysvar_get_internal!( $syscall_name, false ) ;
245+ } ;
246+ // Variant for sysvars with padding at the end.
247+ ( $sysvar_id: expr, $padding: literal) => {
248+ $crate:: __impl_sysvar_get_internal!( $sysvar_id, $padding, false ) ;
249+ } ;
250+ // Variant for sysvars without padding.
251+ ( $sysvar_id: expr) => {
252+ $crate:: __impl_sysvar_get_internal!( $sysvar_id, 0 , false ) ;
253+ } ;
254+ }
255+
256+ /// Implements the [`Sysvar::get`] method with validation that the final byte is a valid bool.
257+ ///
258+ /// This is the same as [`impl_sysvar_get`] but additionally validates that the last byte
259+ /// of the loaded data is either 0x00 or 0x01.
260+ #[ cfg( not( target_os = "solana" ) ) ]
261+ #[ macro_export]
262+ macro_rules! impl_sysvar_get_check_final_bool {
263+ // DEPRECATED: This variant is only for the deprecated Fees sysvar.
264+ ( $syscall_name: ident) => {
265+ $crate:: __impl_sysvar_get_internal!( $syscall_name, true ) ;
266+ } ;
267+ // Variant for sysvars with padding at the end.
268+ ( $sysvar_id: expr, $padding: literal) => {
269+ $crate:: __impl_sysvar_get_internal!( $sysvar_id, $padding, true ) ;
270+ } ;
271+ // Variant for sysvars without padding.
214272 ( $sysvar_id: expr) => {
215- $crate:: impl_sysvar_get !( $sysvar_id, 0 ) ;
273+ $crate:: __impl_sysvar_get_internal !( $sysvar_id, 0 , true ) ;
216274 } ;
217275}
218276
0 commit comments