LCOV - code coverage report
Current view: top level - util/spad - fd_spad.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 64 138 46.4 %
Date: 2025-03-20 12:08:36 Functions: 11 27 40.7 %

          Line data    Source code
       1             : #include "fd_spad.h"
       2             : #include "../log/fd_log.h"
       3             : 
       4             : int
       5      187479 : fd_spad_verify( fd_spad_t const * spad ) {
       6             : 
       7      749916 : # define TEST(c) do { if( FD_UNLIKELY( !(c) ) ) { FD_LOG_WARNING(( "FAIL: %s", #c )); return -1; } } while(0)
       8             : 
       9             :   /* Test spad is a current local join */
      10             : 
      11      187479 :   TEST( spad!=NULL );
      12      187479 :   TEST( spad->magic==FD_SPAD_MAGIC );
      13             : 
      14             :   /* Extract the metadata */
      15             : 
      16      187479 :   ulong frame_free = spad->frame_free; TEST( frame_free<=FD_SPAD_FRAME_MAX );
      17      187479 :   ulong mem_used   = spad->mem_used;   TEST( mem_used  <=spad->mem_max     );
      18             : 
      19             :   /* If there are no frames, there should be no memory used.  Otherwise,
      20             :      make sure the mem_used and frames are properly ordered starting
      21             :      from 0. */
      22             : 
      23      187479 :   if( frame_free==FD_SPAD_FRAME_MAX ) FD_TEST( !mem_used );
      24      168108 :   else {
      25      168108 :     FD_TEST( mem_used >= spad->off[ frame_free ] );
      26     1589046 :     for( ulong idx=frame_free; idx<FD_SPAD_FRAME_MAX-1UL; idx++ ) FD_TEST( spad->off[ idx ]>=spad->off[ idx+1UL ] );
      27      168108 :     FD_TEST( !spad->off[ FD_SPAD_FRAME_MAX-1UL] );
      28      168108 :   }
      29             : 
      30      187479 : # undef TEST
      31             : 
      32      187479 :   return 0;
      33      187479 : }
      34             : 
      35             : /* Debug fn definitions */
      36             : #if (FD_HAS_DEEPASAN || FD_HAS_MSAN)
      37             : #define SELECT_DEBUG_IMPL(fn) fn##_sanitizer_impl
      38             : #else
      39    10988106 : #define SELECT_DEBUG_IMPL(fn) fn##_impl
      40             : #endif
      41             : 
      42             : void
      43           0 : fd_spad_reset_debug( fd_spad_t * spad ) {
      44           0 :   SELECT_DEBUG_IMPL(fd_spad_reset)(spad);
      45           0 : }
      46             : 
      47             : void *
      48           0 : fd_spad_delete_debug( void * shspad ) {
      49           0 :   return SELECT_DEBUG_IMPL(fd_spad_delete)(shspad);
      50           0 : }
      51             : 
      52             : ulong
      53             : fd_spad_alloc_max_debug( fd_spad_t const * spad,
      54     2606853 :                          ulong             align ) {
      55     2606853 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad )               ) ) FD_LOG_CRIT(( "not in a frame" ));
      56     2606853 :   if( FD_UNLIKELY( (!!align) & (!fd_ulong_is_pow2( align ) ) ) ) FD_LOG_CRIT(( "bad align"      ));
      57     2606853 :   return SELECT_DEBUG_IMPL(fd_spad_alloc_max)( spad, align );
      58     2606853 : }
      59             : 
      60             : void *
      61           6 : fd_spad_frame_lo_debug( fd_spad_t * spad ) {
      62           6 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad ) ) ) FD_LOG_CRIT(( "not in a frame" ));
      63           6 :   return SELECT_DEBUG_IMPL(fd_spad_frame_lo)( spad );
      64           6 : }
      65             : 
      66             : void *
      67           3 : fd_spad_frame_hi_debug( fd_spad_t * spad ) {
      68           3 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad ) ) ) FD_LOG_CRIT(( "not in a frame" ));
      69           3 :   return SELECT_DEBUG_IMPL(fd_spad_frame_hi)( spad );
      70           3 : }
      71             : 
      72             : void
      73     1629213 : fd_spad_push_debug( fd_spad_t * spad ) {
      74     1629213 :   if( FD_UNLIKELY( !fd_spad_frame_free( spad ) ) ) FD_LOG_CRIT(( "too many frames" ));
      75     1629213 :   SELECT_DEBUG_IMPL(fd_spad_push)( spad );
      76     1629213 : }
      77             : 
      78             : void
      79       41097 : fd_spad_pop_debug( fd_spad_t * spad ) {
      80       41097 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad ) ) ) FD_LOG_CRIT(( "not in a frame" ));
      81       41097 :   SELECT_DEBUG_IMPL(fd_spad_pop)( spad );
      82       41097 : }
      83             : 
      84             : void *
      85             : fd_spad_alloc_debug( fd_spad_t * spad,
      86             :                      ulong       align,
      87     1120002 :                      ulong       sz ) {
      88     1120002 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad )               ) ) FD_LOG_CRIT(( "not in a frame"  ));
      89     1120002 :   if( FD_UNLIKELY( (!!align) & (!fd_ulong_is_pow2( align ) ) ) ) FD_LOG_CRIT(( "bad align"       ));
      90     1120002 :   if( FD_UNLIKELY( fd_spad_alloc_max( spad, align )<sz       ) ) FD_LOG_CRIT(( "bad sz"          ));
      91     1120002 :   return SELECT_DEBUG_IMPL(fd_spad_alloc)( spad, align, sz );
      92     1120002 : }
      93             : 
      94             : void
      95             : fd_spad_trim_debug( fd_spad_t * spad,
      96     2237808 :                     void *      hi ) {
      97     2237808 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad )                 ) ) FD_LOG_CRIT(( "not in a frame"    ));
      98     2237808 :   if( FD_UNLIKELY( ((ulong)fd_spad_frame_lo( spad ))>(ulong)hi ) ) FD_LOG_CRIT(( "hi below frame_lo" ));
      99     2237808 :   if( FD_UNLIKELY( ((ulong)fd_spad_frame_hi( spad ))<(ulong)hi ) ) FD_LOG_CRIT(( "hi above frame_hi" ));
     100     2237808 :   SELECT_DEBUG_IMPL(fd_spad_trim)( spad, hi );
     101     2237808 : }
     102             : 
     103             : void *
     104             : fd_spad_prepare_debug( fd_spad_t * spad,
     105             :                        ulong       align,
     106     1676562 :                        ulong       max ) {
     107     1676562 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad )               ) ) FD_LOG_CRIT(( "not in a frame" ));
     108     1676562 :   if( FD_UNLIKELY( (!!align) & (!fd_ulong_is_pow2( align ) ) ) ) FD_LOG_CRIT(( "bad align"      ));
     109     1676562 :   if( FD_UNLIKELY( fd_spad_alloc_max( spad, align )<max      ) ) FD_LOG_CRIT(( "bad max of %lu", max        ));
     110     1676562 :   return SELECT_DEBUG_IMPL(fd_spad_prepare)( spad, align, max );
     111     1676562 : }
     112             : 
     113             : void
     114      558702 : fd_spad_cancel_debug( fd_spad_t * spad ) {
     115      558702 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad ) ) ) FD_LOG_CRIT(( "not in a frame" ));
     116             :   /* FIXME: check if in prepare?  needs extra state and a lot of extra
     117             :      tracking that state */
     118      558702 :   SELECT_DEBUG_IMPL(fd_spad_cancel)( spad );
     119      558702 : }
     120             : 
     121             : void
     122             : fd_spad_publish_debug( fd_spad_t * spad,
     123     1117860 :                        ulong       sz ) {
     124     1117860 :   if( FD_UNLIKELY( !fd_spad_frame_used( spad )       ) ) FD_LOG_CRIT(( "not in a frame" ));
     125     1117860 :   if( FD_UNLIKELY( fd_spad_alloc_max( spad, 1UL )<sz ) ) FD_LOG_CRIT(( "bad sz"         ));
     126             :   /* FIXME: check if in prepare?  needs extra state and a lot of extra
     127             :      tracking that state */
     128     1117860 :   SELECT_DEBUG_IMPL(fd_spad_publish)( spad, sz );
     129     1117860 : }
     130             : 
     131             : #undef SELECT_DEBUG_IMPL
     132             : 
     133             : /* Sanitizer impl fn definitions
     134             :    Note that these definitions assume either FD_HAS_DEEPASAN and/or FD_HAS_MSAN is active. */
     135             : void
     136           0 : fd_spad_reset_sanitizer_impl( fd_spad_t * spad ) {
     137           0 :   fd_spad_reset_impl( spad );
     138             : 
     139             :   /* poison the entire spad memory region */
     140           0 :   fd_asan_poison( (void*)(fd_ulong_align_up((ulong)fd_spad_private_mem( spad ), FD_ASAN_ALIGN )), spad->mem_max );
     141           0 :   fd_msan_poison( (void*)(fd_ulong_align_up((ulong)fd_spad_private_mem( spad ), FD_MSAN_ALIGN )), spad->mem_max );
     142           0 : }
     143             : 
     144             : void *
     145           0 : fd_spad_delete_sanitizer_impl( void * shspad ) {
     146           0 :   void * deleted_shspad = fd_spad_delete_impl( shspad );
     147             : 
     148           0 :   if( deleted_shspad ) {
     149           0 :     fd_spad_t * spad = (fd_spad_t *)shspad;
     150             : 
     151             :     /* unpoison the entire spad memory region upon deletion */
     152           0 :     fd_asan_unpoison( (void*)(fd_ulong_align_up( (ulong)fd_spad_private_mem( spad ), FD_ASAN_ALIGN )), spad->mem_max );
     153           0 :     fd_msan_unpoison( (void*)(fd_ulong_align_up( (ulong)fd_spad_private_mem( spad ), FD_MSAN_ALIGN )), spad->mem_max );
     154           0 :   }
     155             : 
     156           0 :   return deleted_shspad;
     157           0 : }
     158             : 
     159             : ulong
     160             : fd_spad_alloc_max_sanitizer_impl( fd_spad_t const * spad,
     161           0 :                                   ulong             align ) {
     162             :   /* enforce a minimum alignment of FD_ASAN_ALIGN or FD_MSAN_ALIGN when running ASAN or MSAN respectively */
     163             : #if FD_HAS_DEEPASAN
     164             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_ASAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     165             : #elif FD_HAS_MSAN
     166             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_MSAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     167             : #endif
     168             : 
     169           0 :   return fd_spad_alloc_max_impl( spad, align );
     170           0 : }
     171             : 
     172             : void *
     173           0 : fd_spad_frame_lo_sanitizer_impl( fd_spad_t * spad ) {
     174           0 :   return fd_spad_frame_lo_impl( spad );
     175           0 : }
     176             : 
     177             : void *
     178           0 : fd_spad_frame_hi_sanitizer_impl( fd_spad_t * spad ) {
     179           0 :   return fd_spad_frame_hi_impl( spad );
     180           0 : }
     181             : 
     182             : void
     183           0 : fd_spad_push_sanitizer_impl( fd_spad_t * spad ) {
     184           0 :   fd_spad_push_impl( spad );
     185             : 
     186             :   /* poison the remaining free memory to cancel any in-progress prepare */
     187           0 :   fd_asan_poison( (void*)(fd_ulong_align_up( (ulong)(fd_spad_private_mem( spad ) + spad->mem_used), FD_ASAN_ALIGN )), spad->mem_max - spad->mem_used );
     188           0 : }
     189             : 
     190             : void
     191           0 : fd_spad_pop_sanitizer_impl( fd_spad_t * spad ) {
     192           0 :   fd_spad_pop_impl( spad );
     193             : 
     194             :   /* poison the entire memory region from mem_used to mem_max */
     195           0 :   fd_asan_poison( (void*)(fd_ulong_align_up( (ulong)(fd_spad_private_mem( spad ) + spad->mem_used), FD_ASAN_ALIGN )), spad->mem_max - spad->mem_used );
     196           0 :   fd_msan_poison( (void*)(fd_ulong_align_up( (ulong)(fd_spad_private_mem( spad ) + spad->mem_used), FD_MSAN_ALIGN )), spad->mem_max - spad->mem_used );
     197           0 : }
     198             : 
     199             : void *
     200             : fd_spad_alloc_sanitizer_impl( fd_spad_t * spad,
     201             :                               ulong       align,
     202           0 :                               ulong       sz ) {
     203             :   /* enforce a minimum alignment of FD_ASAN_ALIGN or FD_MSAN_ALIGN when running ASAN or MSAN respectively */
     204             : #if FD_HAS_DEEPASAN
     205             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_ASAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     206             : #elif FD_HAS_MSAN
     207             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_MSAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     208             : #endif
     209             : 
     210           0 :   void * buf = fd_spad_alloc_impl( spad, align, sz );
     211             : 
     212             :   /* first poison from buf to mem_max to cancel any in-progress prepare.
     213             :      buf is guaranteed to be an 8-byte aligned adddress */
     214           0 :   ulong remaining_memory = (ulong)(fd_spad_private_mem( spad ) + spad->mem_max) - (ulong)buf;
     215           0 :   fd_asan_poison( buf, remaining_memory );
     216             : 
     217             :   /* unpoison the allocated region */
     218           0 :   fd_asan_unpoison( buf, sz );
     219           0 :   fd_msan_unpoison( buf, sz );
     220             : 
     221           0 :   return buf;
     222           0 : }
     223             : 
     224             : void
     225             : fd_spad_trim_sanitizer_impl( fd_spad_t * spad,
     226           0 :                              void *      hi ) {
     227           0 :   fd_spad_trim_impl( spad, hi );
     228             : 
     229             :   /* at this point, mem_used is set to hi - fd_spad_private_mem(spad) */
     230             : #if FD_HAS_DEEPASAN
     231             :   /* Trim can be called at any time to set frame_hi.
     232             :      After trim is called, the memory from hi to mem_max should be poisoned
     233             :      and any valid allocations from frame_lo to the new frame_hi should
     234             :      remain unpoisoned. */
     235             :   ulong hi_aligned_dn = fd_ulong_align_dn( (ulong)hi, FD_ASAN_ALIGN );
     236             :   /* check whether hi_aligned_dn falls in a valid allocation */
     237             :   int in_allocation = !fd_asan_test( (void*)hi_aligned_dn );
     238             :   /* poison from hi_aligned_dn to mem_max */
     239             :   ulong region_sz = (ulong)( fd_spad_private_mem( spad ) + spad->mem_max ) - hi_aligned_dn;
     240             :   fd_asan_poison( (void*)hi_aligned_dn, region_sz );
     241             : 
     242             :   /* unpoison a correction region if hi_aligned_dn was in a valid allocation */
     243             :   if ( in_allocation ) {
     244             :     ulong correction_sz = (ulong)hi - hi_aligned_dn;
     245             :     fd_asan_unpoison( (void*)hi_aligned_dn, correction_sz );
     246             :   }
     247             : #endif
     248             : 
     249             :   /* poison from the next 4-byte aligned address to mem_max */
     250           0 :   fd_msan_poison( (void*)(fd_ulong_align_up( (ulong)hi, FD_MSAN_ALIGN )), spad->mem_max - spad->mem_used );
     251           0 : }
     252             : 
     253             : void *
     254             : fd_spad_prepare_sanitizer_impl( fd_spad_t * spad,
     255             :                                 ulong       align,
     256           0 :                                 ulong       max ) {
     257             :   /* enforce a minimum alignment of FD_ASAN_ALIGN or FD_MSAN_ALIGN when running ASAN or MSAN respectively */
     258             : #if FD_HAS_DEEPASAN
     259             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_ASAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     260             : #elif FD_HAS_MSAN
     261             :   align = fd_ulong_if( align>0UL, fd_ulong_max( align, FD_MSAN_ALIGN ), FD_SPAD_ALLOC_ALIGN_DEFAULT ); /* typically compile time */
     262             : #endif
     263             : 
     264           0 :   void * buf = fd_spad_prepare_impl( spad, align, max );
     265             : 
     266             :   /* unpoison memory starting at buf, which is guaranteed to be 8 byte aligned */
     267           0 :   fd_asan_unpoison( buf,  spad->mem_max - spad->mem_used );
     268           0 :   return buf;
     269           0 : }
     270             : 
     271             : void
     272           0 : fd_spad_cancel_sanitizer_impl( fd_spad_t * spad ) {
     273           0 :   fd_spad_cancel_impl( spad );
     274             : 
     275             :   /* poison the entire memory region from mem_used to mem_max to cancel any in-progress prepares */
     276           0 :   fd_asan_poison( (void*)(fd_spad_private_mem( spad ) + spad->mem_used), spad->mem_max - spad->mem_used );
     277           0 : }
     278             : 
     279             : void
     280             : fd_spad_publish_sanitizer_impl( fd_spad_t * spad,
     281           0 :                                 ulong       sz ) {
     282             :   /* save the pointer to the start of the allocated buffer */
     283           0 :   ulong   off = spad->mem_used;
     284           0 :   uchar * buf = fd_spad_private_mem( spad ) + off;
     285             : 
     286           0 :   fd_spad_publish_impl( spad, sz );
     287             : 
     288             :   /* first poison from buf to mem_max to cancel the in-progress prepare */
     289           0 :   fd_asan_poison( (void*)buf, spad->mem_max - off );
     290             : 
     291             :   /* unpoison the allocated region, which is guaranteed to start at an 8-byte aligned address */
     292           0 :   fd_asan_unpoison( (void*)buf, sz );
     293           0 :   fd_msan_unpoison( (void*)buf, sz );
     294           0 : }
     295             : 
     296             : /* fd_valloc virtual function table for spad */
     297             : static void *
     298             : fd_spad_valloc_malloc( void * _self,
     299             :                        ulong  align,
     300           0 :                        ulong  sz ) {
     301           0 :   fd_spad_t * spad = _self;
     302           0 :   return fd_spad_alloc( spad, align, sz );
     303           0 : }
     304             : 
     305             : static void
     306             : fd_spad_valloc_free( void * _self,
     307           0 :                      void * _addr ) {
     308           0 :   (void)_self; (void)_addr;
     309           0 : }
     310             : 
     311             : const fd_valloc_vtable_t
     312             : fd_spad_vtable = {
     313             :   .malloc = fd_spad_valloc_malloc,
     314             :   .free   = fd_spad_valloc_free
     315             : };

Generated by: LCOV version 1.14