LCOV - code coverage report
Current view: top level - flamenco/runtime/tests - fd_solfuzz.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 163 0.0 %
Date: 2026-10-18 04:43:39 Functions: 0 5 0.0 %

          Line data    Source code
       1             : /* fd_solfuzz.c contains support routines */
       2             : 
       3             : #define _GNU_SOURCE
       4             : #include "fd_solfuzz.h"
       5             : #include "../fd_bank.h"
       6             : #include "../fd_runtime_stack_tmpl.h"
       7             : #include "../fd_runtime.h"
       8             : #include "../../progcache/fd_progcache_admin.h"
       9             : #include <errno.h>
      10             : #include <sys/mman.h>
      11             : #include <unistd.h>
      12             : #include "../../../util/shmem/fd_shmem_private.h"
      13             : 
      14             : fd_wksp_t *
      15             : fd_wksp_demand_paged_new( char const * name,
      16             :                           uint         seed,
      17             :                           ulong        part_max,
      18           0 :                           ulong        data_max ) {
      19           0 :   ulong footprint = fd_wksp_footprint( part_max, data_max );
      20           0 :   if( FD_UNLIKELY( !footprint ) ) {
      21           0 :     FD_LOG_WARNING(( "invalid workspace params (part_max=%lu data_max=%lu)", part_max, data_max ));
      22           0 :     return NULL;
      23           0 :   }
      24             : 
      25             :   /* Round up footprint to nearest huge page size */
      26           0 :   footprint = fd_ulong_align_up( footprint, FD_SHMEM_HUGE_PAGE_SZ );
      27             : 
      28             :   /* Acquire anonymous demand-paged memory */
      29           0 :   void * mem;
      30           0 :   int    map_err = fd_shmem_private_map_rand( footprint, FD_SHMEM_HUGE_PAGE_SZ, FD_SHMEM_JOIN_MODE_READ_WRITE, &mem );
      31           0 :   if( FD_UNLIKELY( map_err ) ) {
      32           0 :     FD_LOG_WARNING(( "fd_shmem_private_map_rand() failed (%i-%s)", map_err, fd_io_strerror( map_err ) ));
      33           0 :     return NULL;
      34           0 :   }
      35             : 
      36             :   /* Indicate to kernel that hugepages are a fine backing store
      37             :      (Transparent Huge Pages) */
      38           0 :   if( FD_UNLIKELY( 0!=madvise( mem, footprint, MADV_HUGEPAGE ) ) ) {
      39           0 :     FD_LOG_WARNING(( "madvise() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      40           0 :     munmap( mem, footprint );
      41           0 :     return NULL;
      42           0 :   }
      43             : 
      44             :   /* Create workspace */
      45           0 :   fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) );
      46           0 :   if( FD_UNLIKELY( !wksp ) ) {
      47           0 :     FD_LOG_WARNING(( "fd_wksp_new() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
      48           0 :     munmap( mem, footprint );
      49           0 :     return NULL;
      50           0 :   }
      51             : 
      52             :   /* Register shared memory region */
      53           0 :   ulong fake_page_cnt = footprint>>FD_SHMEM_HUGE_LG_PAGE_SZ;
      54           0 :   int join_err = fd_shmem_join_anonymous(
      55           0 :       name,
      56           0 :       FD_SHMEM_JOIN_MODE_READ_WRITE,
      57           0 :       wksp,
      58           0 :       mem,
      59           0 :       FD_SHMEM_HUGE_PAGE_SZ,
      60           0 :       fake_page_cnt
      61           0 :   );
      62           0 :   if( FD_UNLIKELY( join_err ) ) {
      63           0 :     FD_LOG_WARNING(( "fd_shmem_join_anonymous() failed (%i-%s)", join_err, fd_io_strerror( join_err ) ));
      64           0 :     fd_wksp_delete( fd_wksp_leave( wksp ) );
      65           0 :     munmap( mem, footprint );
      66           0 :     return NULL;
      67           0 :   }
      68             : 
      69           0 :   return wksp;
      70           0 : }
      71             : 
      72             : void
      73           0 : fd_wksp_demand_paged_delete( fd_wksp_t * wksp ) {
      74           0 :   fd_shmem_leave_anonymous( wksp, NULL );
      75           0 :   FD_TEST( fd_wksp_delete( fd_wksp_leave( wksp ) ) );
      76           0 : }
      77             : 
      78             : fd_solfuzz_runner_t *
      79             : fd_solfuzz_runner_new( fd_wksp_t *                         wksp,
      80             :                        ulong                               wksp_tag,
      81           0 :                        fd_solfuzz_runner_options_t const * options ) {
      82             : 
      83           0 :   int stake_delegations_fd = -1;
      84             : 
      85             :   /* Allocate objects */
      86           0 :   ulong const txn_max  = 16UL;
      87           0 :   ulong const progcache_sz = fd_progcache_shmem_min_sz( txn_max );
      88           0 :   ulong const spad_max = 1750000000UL; /* 1.75GB: 128 accounts * ~10MB + 100MB execute_wrapper
      89             :                                           out buf + 64MB cmp_binary_strict scratch + headroom */
      90           0 :   ulong const bank_max = 2UL;
      91             : 
      92           0 :   ulong const max_accounts         = 1024UL;
      93           0 :   ulong const max_live_slots       = txn_max;
      94           0 :   ulong const writes_per_slot      = 1024UL;
      95           0 :   ulong const partition_cnt        = 8192UL;
      96           0 :   ulong const partition_sz         = (1UL<<30UL);
      97           0 :   ulong const cache_footprint      = (12UL<<30UL);
      98           0 :   ulong const cache_min_reserved   = fd_accdb_cache_min_reserved( 1 );
      99             : 
     100           0 :   ulong accdb_shmem_sz = fd_accdb_shmem_footprint( max_accounts, max_live_slots,
     101           0 :                                                    writes_per_slot, partition_cnt,
     102           0 :                                                    cache_footprint, cache_min_reserved, 1UL, 0UL );
     103           0 :   ulong accdb_join_sz  = fd_accdb_footprint( max_live_slots, 0 );
     104             : 
     105           0 :   fd_solfuzz_runner_t * runner       = fd_wksp_alloc_laddr( wksp, alignof(fd_solfuzz_runner_t), sizeof(fd_solfuzz_runner_t),                                 wksp_tag );
     106           0 :   void *                accdb_shmem  = fd_wksp_alloc_laddr( wksp, fd_accdb_shmem_align(),       accdb_shmem_sz,                                              wksp_tag );
     107           0 :   void *                accdb_join   = fd_wksp_alloc_laddr( wksp, fd_accdb_align(),             accdb_join_sz,                                               wksp_tag );
     108           0 :   void *                pcache_mem   = fd_wksp_alloc_laddr( wksp, fd_progcache_shmem_align(),   fd_progcache_shmem_footprint( txn_max, progcache_sz ),       wksp_tag );
     109           0 :   uchar *               scratch      = fd_wksp_alloc_laddr( wksp, FD_PROGCACHE_SCRATCH_ALIGN,   FD_PROGCACHE_SCRATCH_FOOTPRINT,                              wksp_tag );
     110           0 :   void *                spad_mem     = fd_wksp_alloc_laddr( wksp, fd_spad_align(),              fd_spad_footprint( spad_max ),                               wksp_tag );
     111           0 :   void *                banks_mem    = fd_wksp_alloc_laddr( wksp, fd_banks_align(),             fd_banks_footprint( bank_max, 8UL, 2048UL, 2048UL ), wksp_tag );
     112           0 :   if( FD_UNLIKELY( !runner       ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(solfuzz_runner) failed"                                            )); goto bail1; }
     113           0 :   if( FD_UNLIKELY( !accdb_shmem  ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(accdb_shmem) failed"                                               )); goto bail1; }
     114           0 :   if( FD_UNLIKELY( !accdb_join   ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(accdb_join) failed"                                                )); goto bail1; }
     115           0 :   if( FD_UNLIKELY( !pcache_mem   ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(pcache) failed"                                                    )); goto bail1; }
     116           0 :   if( FD_UNLIKELY( !scratch      ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(scratch) failed"                                                   )); goto bail1; }
     117           0 :   if( FD_UNLIKELY( !spad_mem     ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(spad) failed (spad_max=%g)", (double)spad_max                      )); goto bail1; }
     118           0 :   if( FD_UNLIKELY( !banks_mem    ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(banks) failed (bank_max=%lu)", bank_max                            )); goto bail1; }
     119             : 
     120             :   /* Create objects */
     121           0 :   fd_memset( runner, 0, sizeof(fd_solfuzz_runner_t) );
     122           0 :   runner->wksp     = wksp;
     123           0 :   runner->wksp_tag = wksp_tag;
     124             : 
     125             :   /* Create accdb backed by memfd */
     126           0 :   int accdb_fd = memfd_create( "accdb_fuzz", 0 );
     127           0 :   if( FD_UNLIKELY( accdb_fd<0 ) ) { FD_LOG_WARNING(( "memfd_create failed (%i-%s)", errno, fd_io_strerror( errno ) )); goto bail1; }
     128           0 :   stake_delegations_fd = memfd_create( "stake_delegations_fuzz", 0 );
     129           0 :   if( FD_UNLIKELY( stake_delegations_fd<0 ) ) { FD_LOG_WARNING(( "memfd_create failed (%i-%s)", errno, fd_io_strerror( errno ) )); goto bail1; }
     130           0 :   runner->stake_delegations_fd = stake_delegations_fd;
     131             : 
     132           0 :   fd_accdb_shmem_t * shmem = fd_accdb_shmem_join(
     133           0 :       fd_accdb_shmem_new( accdb_shmem, max_accounts, max_live_slots,
     134           0 :                           writes_per_slot, partition_cnt,
     135           0 :                           partition_sz, cache_footprint, cache_min_reserved, 1, 42UL, 1UL, 0UL ) );
     136           0 :   if( FD_UNLIKELY( !shmem ) ) goto bail1;
     137           0 :   fd_accdb_t * accdb = fd_accdb_join( fd_accdb_new( accdb_join, shmem, accdb_fd, 0UL, NULL, NULL, 0UL, 0 ) );
     138           0 :   if( FD_UNLIKELY( !accdb ) ) goto bail1;
     139           0 :   runner->accdb = accdb;
     140             : 
     141             :   /* Create root fork (sentinel parent) */
     142           0 :   runner->root_fork_id = fd_accdb_attach_child( accdb, (fd_accdb_fork_id_t){ .val=USHORT_MAX } );
     143             : 
     144           0 :   void * shpcache = fd_progcache_shmem_new( pcache_mem, wksp_tag, 1UL, txn_max, progcache_sz );
     145           0 :   if( FD_UNLIKELY( !shpcache ) ) goto bail2;
     146           0 :   if( FD_UNLIKELY( !fd_progcache_join( runner->progcache, pcache_mem, scratch, FD_PROGCACHE_SCRATCH_FOOTPRINT ) ) ) goto bail2;
     147             : 
     148           0 :   runner->runtime = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_t), sizeof(fd_runtime_t), wksp_tag );
     149           0 :   if( FD_UNLIKELY( !runner->runtime ) ) goto bail2;
     150           0 :   runner->runtime->accounts.executable_cnt = 0UL;
     151           0 :   runner->runtime->accounts.account_cnt    = 0UL;
     152           0 :   runner->runtime_stack = fd_wksp_alloc_laddr( wksp, fd_runtime_stack_align(), fd_runtime_stack_footprint( 2048UL, 2048UL, 2048UL ), wksp_tag );
     153           0 :   if( FD_UNLIKELY( !runner->runtime_stack ) ) goto bail2;
     154           0 :   if( FD_UNLIKELY( !fd_runtime_stack_join( fd_runtime_stack_new( runner->runtime_stack, 2048UL, 2048UL, 2048UL, 999UL ) ) ) ) goto bail2;
     155             : 
     156           0 :   runner->spad = fd_spad_join( fd_spad_new( spad_mem, spad_max ) );
     157           0 :   if( FD_UNLIKELY( !runner->spad ) ) goto bail2;
     158             :   /* Use 2048 for max_vote_accounts to match fd_banks_footprint above (avoids buffer overrun) */
     159           0 :   runner->banks = fd_banks_join( fd_banks_new( banks_mem, stake_delegations_fd, bank_max, 8UL, 2048UL, 32768UL, 2048UL, 0, 8888UL ) );
     160           0 :   if( FD_UNLIKELY( !runner->banks ) ) goto bail2;
     161           0 :   FD_TEST( fd_stake_delegations_join( fd_banks_stake_delegations_root_query( runner->banks ), stake_delegations_fd ) );
     162             : 
     163             :   /* Runtime block execution requires every non-genesis bank to have a
     164             :      parent.  Keep the root bank as that parent and run harnesses against
     165             :      its child. */
     166           0 :   fd_bank_t * root_bank = fd_banks_init_bank( runner->banks );
     167           0 :   if( FD_UNLIKELY( !root_bank ) ) goto bail2;
     168           0 :   runner->bank = fd_banks_new_bank( runner->banks, root_bank->idx, 0L, 0 );
     169           0 :   if( FD_UNLIKELY( !runner->bank ) ) goto bail2;
     170           0 :   runner->bank = fd_banks_clone_from_parent( runner->banks, runner->bank->idx );
     171           0 :   if( FD_UNLIKELY( !runner->bank ) ) goto bail2;
     172           0 :   runner->bank->f.slot = 0UL;
     173             : 
     174           0 :   runner->enable_vm_tracing = options->enable_vm_tracing;
     175           0 :   FD_TEST( runner->progcache->join->shmem );
     176             : 
     177           0 :   ulong tags[1] = { wksp_tag };
     178           0 :   fd_wksp_usage_t usage[1];
     179           0 :   fd_wksp_usage( wksp, tags, 1UL, usage );
     180           0 :   runner->wksp_baseline_used_sz = usage->used_sz;
     181             : 
     182           0 :   return runner;
     183             : 
     184           0 : bail2:
     185           0 :   if( runner->spad ) fd_spad_delete( fd_spad_leave( runner->spad ) );
     186           0 :   if( shpcache     ) fd_progcache_shmem_delete( shpcache );
     187           0 : bail1:
     188           0 :   if( stake_delegations_fd>=0 ) close( stake_delegations_fd );
     189           0 :   fd_wksp_free_laddr( scratch      );
     190           0 :   fd_wksp_free_laddr( pcache_mem   );
     191           0 :   fd_wksp_free_laddr( accdb_join   );
     192           0 :   fd_wksp_free_laddr( accdb_shmem  );
     193           0 :   fd_wksp_free_laddr( spad_mem     );
     194           0 :   fd_wksp_free_laddr( banks_mem    );
     195           0 :   fd_wksp_free_laddr( runner       );
     196           0 :   FD_LOG_WARNING(( "fd_solfuzz_runner_new failed" ));
     197           0 :   return NULL;
     198           0 : }
     199             : 
     200             : void
     201           0 : fd_solfuzz_runner_delete( fd_solfuzz_runner_t * runner ) {
     202             : 
     203             :   /* accdb cleanup is handled by the memfd close */
     204             :   /* TODO: proper accdb teardown if needed */
     205             : 
     206           0 :   fd_progcache_shmem_t * shpcache = NULL;
     207           0 :   fd_progcache_leave( runner->progcache, &shpcache );
     208             : 
     209           0 :   fd_wksp_free_laddr( fd_progcache_shmem_delete( shpcache ) );
     210           0 :   fd_wksp_free_laddr( fd_spad_delete( fd_spad_leave( runner->spad ) ) );
     211           0 :   FD_TEST( !close( runner->stake_delegations_fd ) );
     212           0 :   fd_wksp_free_laddr( runner->banks );
     213           0 :   fd_wksp_free_laddr( runner );
     214           0 : }
     215             : 
     216             : void
     217           0 : fd_solfuzz_runner_leak_check( fd_solfuzz_runner_t * runner ) {
     218           0 :   if( FD_UNLIKELY( fd_spad_frame_used( runner->spad ) ) ) {
     219           0 :     FD_LOG_CRIT(( "leaked spad frame" ));
     220           0 :   }
     221             : 
     222           0 :   if( FD_UNLIKELY( runner->progcache->join->shmem->txn.child_head_idx != UINT_MAX ) ) {
     223           0 :     FD_LOG_CRIT(( "leaked a txn in progcache" ));
     224           0 :   }
     225             : 
     226           0 :   ulong tags[1] = { runner->wksp_tag };
     227           0 :   fd_wksp_usage_t usage[1];
     228           0 :   fd_wksp_usage( runner->wksp, tags, 1UL, usage );
     229           0 :   if( FD_UNLIKELY( usage->used_sz != runner->wksp_baseline_used_sz ) ) {
     230           0 :     FD_LOG_CRIT(( "leaked wksp allocations: %lu bytes with tag %lu (baseline %lu bytes, delta %+ld)",
     231           0 :                   usage->used_sz, runner->wksp_tag,
     232           0 :                   runner->wksp_baseline_used_sz,
     233           0 :                   (long)usage->used_sz - (long)runner->wksp_baseline_used_sz ));
     234           0 :   }
     235           0 : }

Generated by: LCOV version 1.14