LCOV - code coverage report
Current view: top level - flamenco/vm/syscall - fd_vm_syscall_util.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 179 208 86.1 %
Date: 2026-10-22 18:10:43 Functions: 13 13 100.0 %

          Line data    Source code
       1             : #include "fd_vm_syscall.h"
       2             : 
       3             : #include "../../../ballet/base64/fd_base64.h"
       4             : #include "../../../ballet/utf8/fd_utf8.h"
       5             : 
       6             : int
       7             : fd_vm_syscall_abort( /**/            void *  _vm,
       8             :                      FD_PARAM_UNUSED ulong   r1,
       9             :                      FD_PARAM_UNUSED ulong   r2,
      10             :                      FD_PARAM_UNUSED ulong   r3,
      11             :                      FD_PARAM_UNUSED ulong   r4,
      12          33 :                      FD_PARAM_UNUSED ulong   r5 ) {
      13             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L630 */
      14          33 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      15          33 :   FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_ABORT );
      16          33 :   return FD_VM_SYSCALL_ERR_ABORT;
      17          33 : }
      18             : 
      19             : /* FD_TRANSLATE_STRING returns a read only pointer to the host address of
      20             :    a valid utf8 string, or it errors.
      21             : 
      22             :    Analogous of Agave's translate_string_and_do().
      23             :    https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L601
      24             : 
      25             :    As of v0.2.6, the only two usages are in syscall panic and syscall log. */
      26         512 : #define FD_TRANSLATE_STRING( vm, vaddr, msg_sz ) (__extension__({                          \
      27         512 :     char const * msg = FD_VM_MEM_SLICE_HADDR_LD( vm, vaddr, FD_VM_ALIGN_RUST_U8, msg_sz ); \
      28         512 :     if( FD_UNLIKELY( !fd_utf8_verify( msg, msg_sz ) ) ) {                                  \
      29           3 :       FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_INVALID_STRING );                   \
      30           3 :       return FD_VM_SYSCALL_ERR_INVALID_STRING;                                             \
      31           3 :     }                                                                                      \
      32         512 :     msg;                                                                                   \
      33         509 : }))
      34             : 
      35             : int
      36             : fd_vm_syscall_sol_panic( /**/            void *  _vm,
      37             :                          /**/            ulong   file_vaddr,
      38             :                          /**/            ulong   file_sz,
      39             :                          /**/            ulong   line,
      40             :                          /**/            ulong   column,
      41          21 :                          FD_PARAM_UNUSED ulong   r5 ) {
      42          21 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      43             : 
      44             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/mod.rs#L637
      45             : 
      46             :      Note: this syscall is not used by the Rust SDK, only by the C SDK.
      47             :      Rust transforms `panic!()` into a log, followed by an abort.
      48             :      It's unclear if this syscall actually makes any sense... */
      49          21 :   FD_VM_CU_UPDATE( vm, file_sz );
      50             : 
      51             :   /* Validate string */
      52          19 :   FD_TRANSLATE_STRING( vm, file_vaddr, file_sz );
      53             : 
      54             :   /* Note: we truncate the log, ignoring file, line, column.
      55             :      As mentioned above, it's unclear if anyone is even using this syscall,
      56             :      so dealing with the complexity of Agave's log is a waste of time. */
      57           0 :   (void)line;
      58          18 :   (void)column;
      59             : 
      60          18 :   FD_VM_ERR_FOR_LOG_SYSCALL( vm, FD_VM_SYSCALL_ERR_PANIC );
      61          18 :   return FD_VM_SYSCALL_ERR_PANIC;
      62          38 : }
      63             : 
      64             : int
      65             : fd_vm_syscall_sol_log( /**/            void *  _vm,
      66             :                        /**/            ulong   msg_vaddr,
      67             :                        /**/            ulong   msg_sz,
      68             :                        FD_PARAM_UNUSED ulong   r3,
      69             :                        FD_PARAM_UNUSED ulong   r4,
      70         503 :                        FD_PARAM_UNUSED ulong   r5 ) {
      71         503 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      72             : 
      73             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L5 */
      74             : 
      75         503 :   FD_VM_CU_UPDATE( vm, fd_ulong_max( msg_sz, FD_VM_SYSCALL_BASE_COST ) );
      76             : 
      77             :   /* Note: when msg_sz==0, msg can be undefined.
      78             :      fd_log_collector_program_log() handles it. */
      79         493 :   const char * buf = FD_TRANSLATE_STRING( vm, msg_vaddr, msg_sz );
      80           0 :   fd_log_collector_program_log( vm->instr_ctx, buf, msg_sz );
      81             : 
      82         491 :   vm->reg[0] = 0UL;
      83         491 :   return FD_VM_SUCCESS;
      84         986 : }
      85             : 
      86             : int
      87             : fd_vm_syscall_sol_log_64( void *  _vm,
      88             :                           ulong   r1,
      89             :                           ulong   r2,
      90             :                           ulong   r3,
      91             :                           ulong   r4,
      92         457 :                           ulong   r5 ) {
      93         457 :   fd_vm_t * vm = (fd_vm_t *)_vm;
      94             : 
      95             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L37 */
      96             : 
      97         457 :   FD_VM_CU_UPDATE( vm, FD_VM_LOG_64_UNITS );
      98             : 
      99             :   /* Max msg_sz: 46 - 15 + 16*5 = 111 < 127 => we can use printf */
     100           0 :   fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
     101         455 :     "Program log: 0x%lx, 0x%lx, 0x%lx, 0x%lx, 0x%lx", r1, r2, r3, r4, r5 );
     102             : 
     103         455 :   vm->reg[0] = 0UL;
     104         455 :   return FD_VM_SUCCESS;
     105         457 : }
     106             : 
     107             : int
     108             : fd_vm_syscall_sol_log_compute_units( /**/            void *  _vm,
     109             :                                      FD_PARAM_UNUSED ulong   r1,
     110             :                                      FD_PARAM_UNUSED ulong   r2,
     111             :                                      FD_PARAM_UNUSED ulong   r3,
     112             :                                      FD_PARAM_UNUSED ulong   r4,
     113         481 :                                      FD_PARAM_UNUSED ulong   r5 ) {
     114         481 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     115             : 
     116             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L60 */
     117             : 
     118         481 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     119             : 
     120             :   /* Max msg_sz: 40 - 3 + 20 = 57 < 127 => we can use printf */
     121           0 :   fd_log_collector_printf_dangerous_max_127( vm->instr_ctx,
     122         480 :     "Program consumption: %lu units remaining", vm->cu );
     123             : 
     124         480 :   vm->reg[0] = 0UL;
     125         480 :   return FD_VM_SUCCESS;
     126         481 : }
     127             : 
     128             : int
     129             : fd_vm_syscall_sol_log_pubkey( /**/            void *  _vm,
     130             :                               /**/            ulong   pubkey_vaddr,
     131             :                               FD_PARAM_UNUSED ulong   r2,
     132             :                               FD_PARAM_UNUSED ulong   r3,
     133             :                               FD_PARAM_UNUSED ulong   r4,
     134         141 :                               FD_PARAM_UNUSED ulong   r5 ) {
     135         141 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     136             : 
     137             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L84 */
     138             : 
     139         141 :   FD_VM_CU_UPDATE( vm, FD_VM_LOG_PUBKEY_UNITS );
     140             : 
     141         416 :   void const * pubkey = FD_VM_MEM_HADDR_LD( vm, pubkey_vaddr, FD_VM_ALIGN_RUST_PUBKEY, sizeof(fd_pubkey_t) );
     142             : 
     143           0 :   char msg[ FD_BASE58_ENCODED_32_SZ ]; ulong msg_sz;
     144         416 :   if( FD_UNLIKELY( fd_base58_encode_32( pubkey, &msg_sz, msg )==NULL ) ) {
     145           0 :     return FD_VM_SYSCALL_ERR_INVALID_STRING;
     146           0 :   }
     147             : 
     148         138 :   fd_log_collector_program_log( vm->instr_ctx, msg, msg_sz );
     149             : 
     150         138 :   vm->reg[0] = 0UL;
     151         138 :   return FD_VM_SUCCESS;
     152         416 : }
     153             : 
     154             : int
     155             : fd_vm_syscall_sol_log_data( /**/            void *  _vm,
     156             :                             /**/            ulong   slice_vaddr,
     157             :                             /**/            ulong   slice_cnt,
     158             :                             FD_PARAM_UNUSED ulong   r3,
     159             :                             FD_PARAM_UNUSED ulong   r4,
     160         169 :                             FD_PARAM_UNUSED ulong   r5 ) {
     161         169 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     162             : 
     163             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L109
     164             : 
     165             :      Note: this is implemented following Agave's perverse behavior.
     166             :      We need to loop the slice multiple times to match the exact error,
     167             :      first compute budget, then memory mapping.
     168             :      And finally, we can loop to log. */
     169             : 
     170             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L121 */
     171             : 
     172         169 :   FD_VM_CU_UPDATE( vm, FD_VM_SYSCALL_BASE_COST );
     173             : 
     174             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L123-L128 */
     175             : 
     176         336 :   fd_vm_vec_t const * slice = (fd_vm_vec_t const *)FD_VM_MEM_SLICE_HADDR_LD( vm, slice_vaddr, FD_VM_ALIGN_RUST_SLICE_U8_REF,
     177         336 :     fd_ulong_sat_mul( slice_cnt, sizeof(fd_vm_vec_t) ) );
     178             : 
     179             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L130-L135 */
     180             : 
     181         168 :   FD_VM_CU_UPDATE( vm, fd_ulong_sat_mul( FD_VM_SYSCALL_BASE_COST, slice_cnt ) );
     182             : 
     183             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L136-L141 */
     184             : 
     185        4704 :   for( ulong i=0UL; i<slice_cnt; i++ ) {
     186        4537 :     FD_VM_CU_UPDATE( vm, slice[i].len );
     187        4536 :   }
     188             : 
     189             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L145-L152 */
     190             : 
     191         167 :   ulong msg_sz = 14UL; /* "Program data: ", with space */
     192        4699 :   for( ulong i=0UL; i<slice_cnt; i++ ) {
     193        4533 :     ulong cur_len = slice[i].len;
     194             :     /* This fails the syscall in case of memory mapping issues */
     195        9065 :     FD_VM_MEM_SLICE_HADDR_LD( vm, slice[i].addr, FD_VM_ALIGN_RUST_U8, cur_len );
     196             :     /* Every buffer will be base64 encoded + space separated */
     197           0 :     msg_sz += (slice[i].len + 2)/3*4 + (i > 0);
     198        9065 :   }
     199             : 
     200             :   /* https://github.com/anza-xyz/agave/blob/v2.0.6/programs/bpf_loader/src/syscalls/logging.rs#L156 */
     201             : 
     202         166 :   fd_log_collector_t * log = vm->instr_ctx->runtime->log.log_collector;
     203         166 :   if( FD_LIKELY( log->disabled ) ) {
     204         166 :     vm->reg[0] = 0UL;
     205         166 :     return FD_VM_SUCCESS;
     206         166 :   }
     207             : 
     208           0 :   char msg[ FD_LOG_COLLECTOR_MAX ];
     209           0 :   ulong bytes_written = fd_log_collector_check_and_truncate( log, msg_sz );
     210           0 :   if( FD_LIKELY( bytes_written < ULONG_MAX ) ) {
     211           0 :     fd_memcpy( msg, "Program data: ", 14 );
     212           0 :     char * buf = msg + 14;
     213             : 
     214           0 :     for( ulong i=0UL; i<slice_cnt; i++ ) {
     215           0 :       ulong cur_len = slice[i].len;
     216           0 :       void const * bytes = FD_VM_MEM_SLICE_HADDR_LD( vm, slice[i].addr, FD_VM_ALIGN_RUST_U8, cur_len );
     217             : 
     218           0 :       if( i ) { *buf = ' '; ++buf; } /* skip first */
     219           0 :       buf += fd_base64_encode( buf, bytes, cur_len );
     220           0 :     }
     221           0 :     FD_TEST( (ulong)(buf-msg)==msg_sz );
     222             : 
     223           0 :     fd_log_collector_msg( vm->instr_ctx, msg, msg_sz );
     224           0 :   }
     225             : 
     226           0 :   vm->reg[0] = 0UL;
     227           0 :   return FD_VM_SUCCESS;
     228           0 : }
     229             : 
     230             : int
     231             : fd_vm_syscall_sol_alloc_free( /**/            void *  _vm,
     232             :                               /**/            ulong   sz,
     233             :                               /**/            ulong   free_vaddr,
     234             :                               FD_PARAM_UNUSED ulong   r3,
     235             :                               FD_PARAM_UNUSED ulong   r4,
     236         458 :                               FD_PARAM_UNUSED ulong   r5 ) {
     237         458 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     238             : 
     239             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L666 */
     240             : 
     241             :   /* This syscall is ... uh ... problematic.  But the community has
     242             :      already recognized this and deprecated it:
     243             : 
     244             :      https://github.com/solana-labs/solana/blob/v1.17.23/sdk/src/feature_set.rs#L846
     245             : 
     246             :      Unfortunately, old code never dies so, practically, this will need
     247             :      to be supported until the heat death of the universe.
     248             : 
     249             :      The most serious issue is that there is nothing to stop VM code
     250             :      making a decision based on the _location_ of the returned
     251             :      allocation.  If different validator implementations use different
     252             :      allocator algorithms, though each implementation would behave
     253             :      functionally correct in isolation, the VM code that uses it would
     254             :      actually break consensus.
     255             : 
     256             :      As a result, every validator needs to use a bit-for-bit identical
     257             :      allocation algorithm.  Fortunately, Solana is just using a basic
     258             :      bump allocator:
     259             : 
     260             :      https://github.com/solana-labs/solana/blob/v1.17.23/program-runtime/src/invoke_context.rs#L122-L148
     261             : 
     262             :      vm->heap_{sz,max} and the below replicate this exactly.
     263             : 
     264             :      Another major issue is that this alloc doesn't always conform
     265             :      typical malloc/free semantics (e.g. C/C++ requires malloc to have
     266             :      an alignment safe for primitive types ... 8 for the Solana machine
     267             :      model).  This is clearly to support backward compat with older VM
     268             :      code (though ideally a malloc syscall should have behaved like ...
     269             :      well ... malloc from day 1).  So the alignment behavior below is a
     270             :      bug-for-bug replication of that:
     271             : 
     272             :      https://github.com/solana-labs/solana/blob/v1.17.23/programs/bpf_loader/src/syscalls/mod.rs#L645-L681
     273             :      https://github.com/solana-labs/solana/blob/v1.17.23/sdk/program/src/entrypoint.rs#L265-L266
     274             : 
     275             :      More generally and already ranted about elsewhere, any code that
     276             :      uses malloc/free style dynamic allocation is inherently broken.  So
     277             :      this syscall should have never existed in the first place ... it
     278             :      just feeds the trolls.  The above is just additional implementation
     279             :      horror because people consistent think malloc/free is much simpler
     280             :      than it actually is.  This is also an example of how quickly
     281             :      mistakes fossilize and become a thorn-in-the-side forever.
     282             : 
     283             :      IMPORTANT SAFETY TIP!  heap_start must be non zero and both
     284             :      heap_start and heap_end should have an alignment of at least 8.
     285             :      This existing runtime policies around heap implicitly satisfy this.
     286             : 
     287             :      IMPORTANT SAFETY TIP!  The specification for Rust's align_offset
     288             :      doesn't seem to provide a strong guarantee that it will return the
     289             :      minimal positive offset necessary to align pointers.  It is
     290             :      possible for a "conforming" Rust compiler to break consensus by
     291             :      using a different align_offset implementation that aligned pointer
     292             :      between different compilations of the Solana validator and the
     293             :      below. */
     294             : 
     295             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L676-L680 */
     296             : 
     297         458 :   ulong align = fd_vm_is_check_align_enabled( vm ) ? 8UL : FD_VM_ALIGN_RUST_U8;
     298             : 
     299             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L684
     300             :      Nothing to do.
     301             :      TODO: unclear if it throw InstructionError::CallDepth
     302             :      https://github.com/anza-xyz/agave/blob/v2.0.8/program-runtime/src/invoke_context.rs#L662 */
     303             : 
     304             :   /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mod.rs#L685-L693 */
     305             : 
     306             :   /* Non-zero free address implies that this is a free() call.  Since
     307             :      this is a bump allocator, free is a no-op. */
     308         458 :   if( FD_UNLIKELY( free_vaddr ) ) {
     309           4 :     vm->reg[0] = 0UL;
     310           4 :     return FD_VM_SUCCESS;
     311           4 :   }
     312             : 
     313             : 
     314         454 :   ulong heap_sz    = fd_ulong_align_up( vm->heap_sz, align                           );
     315         454 :   ulong heap_vaddr = fd_ulong_sat_add ( heap_sz,     FD_VM_MEM_MAP_HEAP_REGION_START );
     316         454 :   /**/  heap_sz    = fd_ulong_sat_add ( heap_sz,     sz                              );
     317             : 
     318         454 :   if( FD_UNLIKELY( heap_sz > vm->heap_max ) ) { /* Not enough free memory */
     319          71 :     vm->reg[0] = 0UL;
     320          71 :     return FD_VM_SUCCESS;
     321          71 :   }
     322             : 
     323         383 :   vm->heap_sz = heap_sz;
     324             : 
     325         383 :   vm->reg[0] = heap_vaddr;
     326         383 :   return FD_VM_SUCCESS;
     327         454 : }
     328             : 
     329             : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L145 */
     330             : int
     331             : fd_vm_memmove( fd_vm_t * vm,
     332             :                ulong     dst_vaddr,
     333             :                ulong     src_vaddr,
     334        1791 :                ulong     sz ) {
     335        1791 :   if( FD_UNLIKELY( !sz ) ) {
     336          11 :     return FD_VM_SUCCESS;
     337          11 :   }
     338             : 
     339             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L188-L192 */
     340        1780 :   fd_vm_haddr_query_t dst_ref_mut_query = {
     341        1780 :     .vaddr    = dst_vaddr,
     342        1780 :     .align    = FD_VM_ALIGN_RUST_U8,
     343        1780 :     .sz       = sz,
     344        1780 :     .is_slice = 1,
     345        1780 :   };
     346             : 
     347        1780 :   fd_vm_haddr_query_t * queries[] = { &dst_ref_mut_query };
     348        1780 :   FD_VM_TRANSLATE_MUT( vm, queries );
     349             : 
     350        1754 :   void const * src = FD_VM_MEM_HADDR_LD( vm, src_vaddr, FD_VM_ALIGN_RUST_U8, sz );
     351           0 :   memmove( dst_ref_mut_query.haddr, src, sz );
     352             : 
     353        1720 :   return FD_VM_SUCCESS;
     354        3474 : }
     355             : 
     356             : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L41 */
     357             : int
     358             : fd_vm_syscall_sol_memmove( /**/            void *  _vm,
     359             :                            /**/            ulong   dst_vaddr,
     360             :                            /**/            ulong   src_vaddr,
     361             :                            /**/            ulong   sz,
     362             :                            FD_PARAM_UNUSED ulong   r4,
     363         193 :                            FD_PARAM_UNUSED ulong   r5 ) {
     364         193 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     365             : 
     366         193 :   FD_VM_CU_MEM_OP_UPDATE( vm, sz );
     367             : 
     368           0 :   vm->reg[0] = 0UL;
     369             : 
     370             :   /* No overlap check for memmove. */
     371         193 :   return fd_vm_memmove( vm, dst_vaddr, src_vaddr, sz );
     372         193 : }
     373             : 
     374             : /* https://github.com/anza-xyz/agave/blob/v2.0.8/programs/bpf_loader/src/syscalls/mem_ops.rs#L18 */
     375             : int
     376             : fd_vm_syscall_sol_memcpy( /**/            void *  _vm,
     377             :                           /**/            ulong   dst_vaddr,
     378             :                           /**/            ulong   src_vaddr,
     379             :                           /**/            ulong   sz,
     380             :                           FD_PARAM_UNUSED ulong   r4,
     381        1605 :                           FD_PARAM_UNUSED ulong   r5 ) {
     382        1605 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     383             : 
     384        1605 :   FD_VM_CU_MEM_OP_UPDATE( vm, sz );
     385             : 
     386           0 :   vm->reg[0] = 0UL;
     387             : 
     388             :   /* Exact same as memmove, except also check overlap.
     389             :      https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L45 */
     390        1604 :   FD_VM_MEM_CHECK_NON_OVERLAPPING( vm, src_vaddr, sz, dst_vaddr, sz );
     391             : 
     392        1598 :   return fd_vm_memmove( vm, dst_vaddr, src_vaddr, sz );
     393        1604 : }
     394             : 
     395             : int
     396             : fd_vm_syscall_sol_memcmp( /**/            void *  _vm,
     397             :                           /**/            ulong   m0_vaddr,
     398             :                           /**/            ulong   m1_vaddr,
     399             :                           /**/            ulong   sz,
     400             :                           /**/            ulong   out_vaddr,
     401        1653 :                           FD_PARAM_UNUSED ulong   r5 ) {
     402        1653 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     403        1653 :   vm->reg[0] = 0UL;
     404             : 
     405             :   /* https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L84 */
     406             : 
     407        1653 :   FD_VM_CU_MEM_OP_UPDATE( vm, sz );
     408             : 
     409             :   /* Note: though this behaves like a normal C-style memcmp, we can't
     410             :      use the compilers / libc memcmp directly because the specification
     411             :      doesn't provide strong enough guarantees about the return value (it
     412             :      only promises the sign). */
     413             : 
     414        3301 :   uchar const * m0 = (uchar const *)FD_VM_MEM_SLICE_HADDR_LD( vm, m0_vaddr, FD_VM_ALIGN_RUST_U8, sz );
     415        3295 :   uchar const * m1 = (uchar const *)FD_VM_MEM_SLICE_HADDR_LD( vm, m1_vaddr, FD_VM_ALIGN_RUST_U8, sz );
     416             : 
     417             :   /* Silly that this doesn't use r0 to return ... slower, more edge
     418             :      case, different from libc style memcmp, harder to callers to use,
     419             :      etc ... probably too late to do anything about it now ... sigh */
     420             : 
     421             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L121-L125 */
     422           0 :   fd_vm_haddr_query_t cmp_result_ref_mut_query = {
     423        3295 :     .vaddr    = out_vaddr,
     424        3295 :     .align    = FD_VM_ALIGN_RUST_I32,
     425        3295 :     .sz       = 4UL,
     426        3295 :     .is_slice = 0,
     427        3295 :   };
     428             : 
     429        3295 :   fd_vm_haddr_query_t * queries[] = { &cmp_result_ref_mut_query };
     430        3295 :   FD_VM_TRANSLATE_MUT( vm, queries );
     431             : 
     432             :   /* Aliased slices are equal. */
     433             : 
     434        1646 :   if( FD_UNLIKELY( m0==m1 ) ) {
     435           7 :     FD_STORE( uint, cmp_result_ref_mut_query.haddr, 0U );
     436           7 :     return FD_VM_SUCCESS;
     437           7 :   }
     438             : 
     439             :   /* Find the difference searching by blocks, then words, then bytes, this way
     440             :      the search is vectorized.
     441             :      BLK is 256 because at -O3 gcc unrolls smaller blocks into scalar code instead.
     442             : 
     443             :      Alternative considered:
     444             : 
     445             :      for( ; i+64UL<=sz; i+=64UL )
     446             :        if( FD_UNLIKELY( wwv_ne( wwv_ldu( m0+i ), wwv_ldu( m1+i ) ) ) ) break;
     447             : 
     448             :      it's more readable but requires more combinations (AVX512, AVX2, ARM in future...),
     449             :      this is a single version that should apply to all. */
     450             : 
     451        4943 : #define BLK (256UL)
     452             : 
     453        1639 :   int   out = 0;
     454        1639 :   ulong i   = 0UL;
     455        1674 :   for( ; i+BLK<=sz; i+=BLK ) {
     456          98 :     ulong d = 0UL;
     457        3234 :     for( ulong k=0UL; k<BLK; k+=8UL ) {
     458        3136 :       d |= fd_ulong_load_8( m0+i+k ) ^ fd_ulong_load_8( m1+i+k );
     459        3136 :     }
     460          98 :     if( FD_UNLIKELY( d ) ) {
     461          63 :       break;
     462          63 :     }
     463          98 :   }
     464        5748 :   for( ; i+8UL<=sz; i+=8UL ) {
     465        4875 :     if( FD_UNLIKELY( fd_ulong_load_8( m0+i )!=fd_ulong_load_8( m1+i ) ) ) {
     466         766 :       break;
     467         766 :     }
     468        4875 :   }
     469        2384 :   for( ; i<sz; i++ ) {
     470        1511 :     int i0 = (int)m0[i];
     471        1511 :     int i1 = (int)m1[i];
     472        1511 :     if( i0!=i1 ) {
     473         766 :       out = i0 - i1;
     474         766 :       break;
     475         766 :     }
     476        1511 :   }
     477             : 
     478        1639 : #undef BLK
     479             : 
     480        1639 :   FD_STORE( uint, cmp_result_ref_mut_query.haddr, (uint)out );
     481             : 
     482        1639 :   return FD_VM_SUCCESS;
     483        1646 : }
     484             : 
     485             : int
     486             : fd_vm_syscall_sol_memset( /**/            void *  _vm,
     487             :                           /**/            ulong   dst_vaddr,
     488             :                           /**/            ulong   c,
     489             :                           /**/            ulong   sz,
     490             :                           FD_PARAM_UNUSED ulong   r4,
     491         299 :                           FD_PARAM_UNUSED ulong   r5 ) {
     492         299 :   fd_vm_t * vm = (fd_vm_t *)_vm;
     493         299 :   vm->reg[0] = 0UL;
     494             : 
     495             :   /* https://github.com/anza-xyz/agave/blob/v2.2.17/programs/bpf_loader/src/syscalls/mem_ops.rs#L142 */
     496             : 
     497         299 :   FD_VM_CU_MEM_OP_UPDATE( vm, sz );
     498             : 
     499         299 :   if( FD_UNLIKELY( !sz ) ) {
     500           1 :     return FD_VM_SUCCESS;
     501           1 :   }
     502             : 
     503         298 :   int b = (int)(c & 255UL);
     504             : 
     505             :   /* https://github.com/anza-xyz/agave/blob/v2.3.1/programs/bpf_loader/src/syscalls/mem_ops.rs#L155-L159 */
     506         298 :   fd_vm_haddr_query_t haddr_query = {
     507         298 :     .vaddr    = dst_vaddr,
     508         298 :     .align    = FD_VM_ALIGN_RUST_U8,
     509         298 :     .sz       = sz,
     510         298 :     .is_slice = 1,
     511         298 :   };
     512             : 
     513         298 :   fd_vm_haddr_query_t * queries[] = { &haddr_query };
     514         298 :   FD_VM_TRANSLATE_MUT( vm, queries );
     515         279 :   fd_memset( haddr_query.haddr, b, sz );
     516             : 
     517         279 :   return FD_VM_SUCCESS;
     518         298 : }

Generated by: LCOV version 1.14