LCOV - code coverage report
Current view: top level - ballet/reedsol - fuzz_reedsol.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 6 6 100.0 %
Date: 2024-11-13 11:58:15 Functions: 1 1 100.0 %

          Line data    Source code
       1             : #if !FD_HAS_HOSTED
       2             : #error "This target requires FD_HAS_HOSTED"
       3             : #endif
       4             : 
       5             : #include <stdio.h>
       6             : #include <stdlib.h>
       7             : 
       8             : #include "../../util/fd_util.h"
       9             : #include "../../util/sanitize/fd_fuzz.h"
      10             : #include "fd_reedsol.h"
      11             : 
      12             : int
      13             : LLVMFuzzerInitialize( int  *   argc,
      14          18 :                       char *** argv ) {
      15             :   /* Set up shell without signal handlers */
      16          18 :   putenv( "FD_LOG_BACKTRACE=0" );
      17          18 :   fd_boot( argc, argv );
      18          18 :   atexit( fd_halt );
      19          18 :   return 0;
      20          18 : }
      21             : 
      22             : #define SHRED_SZ_MIN ( 32UL )
      23             : #define SHRED_SZ_MAX ( 63UL )
      24             : 
      25             : struct reedsol_test {
      26             :   ulong shred_sz;
      27             :   ulong data_shred_cnt;
      28             :   ulong parity_shred_cnt;
      29             :   ulong erased_shred_cnt;
      30             :   ulong corrupt_shred_idx;
      31             :   uchar data[ ];
      32             : };
      33             : typedef struct reedsol_test reedsol_test_t;
      34             : 
      35             : int
      36             : LLVMFuzzerTestOneInput( uchar const * data,
      37             :                         ulong         size ) {
      38             :   if( FD_UNLIKELY( size<sizeof( reedsol_test_t ) ) ) return -1;
      39             :   reedsol_test_t const * test = ( reedsol_test_t const * ) data;
      40             : 
      41             :   fd_rng_t _rng[1];
      42             :   fd_rng_t * rng = fd_rng_join( fd_rng_new( _rng, 0U, 0UL ) );
      43             : 
      44             :   uchar mem[ FD_REEDSOL_FOOTPRINT ] __attribute__((aligned(FD_REEDSOL_ALIGN)));
      45             : 
      46             :   uchar const * data_shreds = test->data;
      47             :   uchar parity_shreds[ SHRED_SZ_MAX * FD_REEDSOL_PARITY_SHREDS_MAX ];
      48             :   uchar recovered_shreds[ SHRED_SZ_MAX * ( FD_REEDSOL_PARITY_SHREDS_MAX+1UL ) ];
      49             :   
      50             :   uchar const * d[ FD_REEDSOL_DATA_SHREDS_MAX   ];
      51             :   uchar *       p[ FD_REEDSOL_PARITY_SHREDS_MAX ];
      52             :   uchar *       r[ FD_REEDSOL_PARITY_SHREDS_MAX+1UL ];
      53             :   uchar const * erased_truth[ FD_REEDSOL_PARITY_SHREDS_MAX+1UL ];
      54             : 
      55             :   ulong shred_sz = SHRED_SZ_MIN + test->shred_sz % ( SHRED_SZ_MAX-SHRED_SZ_MIN+1UL );
      56             :   ulong d_cnt = test->data_shred_cnt % FD_REEDSOL_DATA_SHREDS_MAX + 1UL;
      57             :   ulong p_cnt = test->parity_shred_cnt % FD_REEDSOL_PARITY_SHREDS_MAX + 1UL;
      58             :   ulong e_cnt = test->erased_shred_cnt % ( p_cnt+2UL );
      59             :   ulong corrupt_idx = test->corrupt_shred_idx % ( d_cnt+p_cnt );
      60             : 
      61             :   if( FD_UNLIKELY( size < sizeof( reedsol_test_t ) + shred_sz*d_cnt ) ) return -1;
      62             : 
      63             :   for( ulong i=0UL; i<d_cnt; i++ )  d[ i ] = data_shreds + shred_sz*i;
      64             :   for( ulong i=0UL; i<p_cnt; i++ )  p[ i ] = parity_shreds + shred_sz*i;
      65             :   for( ulong i=0UL; i<e_cnt; i++ )  r[ i ] = recovered_shreds + shred_sz*i;
      66             : 
      67             :   fd_reedsol_t * rs = fd_reedsol_encode_init( mem, shred_sz );
      68             :   for( ulong i=0UL; i<d_cnt; i++ ) fd_reedsol_encode_add_data_shred(   rs, d[ i ] );
      69             :   for( ulong i=0UL; i<p_cnt; i++ ) fd_reedsol_encode_add_parity_shred( rs, p[ i ] );
      70             :   fd_reedsol_encode_fini( rs );
      71             : 
      72             :   /* Use reservoir sampling to select exactly e_cnt of the shreds
      73             :      to erased */
      74             :   ulong erased_cnt = 0UL;
      75             :   rs = fd_reedsol_recover_init( mem, shred_sz );
      76             :   for( ulong i=0UL; i<d_cnt; i++ ) {
      77             :     /* Erase with probability:
      78             :        (e_cnt - erased_cnt)/(d_cnt + p_cnt - i) */
      79             :     if( fd_rng_ulong_roll( rng, d_cnt+p_cnt-i ) < (e_cnt-erased_cnt) ) {
      80             :       erased_truth[ erased_cnt ] = d[ i ];
      81             :       fd_reedsol_recover_add_erased_shred(    rs, 1, r[ erased_cnt++ ] );
      82             :     } else fd_reedsol_recover_add_rcvd_shred( rs, 1, d[ i ] );
      83             :   }
      84             :   for( ulong i=0UL; i<p_cnt; i++ ) {
      85             :     if( fd_rng_ulong_roll( rng, p_cnt-i ) < (e_cnt-erased_cnt) ) {
      86             :       erased_truth[ erased_cnt ] = p[ i ];
      87             :       fd_reedsol_recover_add_erased_shred(    rs, 0, r[ erased_cnt++ ] );
      88             :     } else fd_reedsol_recover_add_rcvd_shred( rs, 0, p[ i ] );
      89             :   }
      90             : 
      91             :   if( FD_UNLIKELY( erased_cnt!=e_cnt ) ) {
      92             :      /* If this fails, the test is wrong. */
      93             :      __builtin_trap();
      94             :   }
      95             :   int retval = fd_reedsol_recover_fini( rs );
      96             : 
      97             :   if( FD_UNLIKELY( e_cnt>p_cnt ) ) {
      98             :     if( FD_UNLIKELY( retval!=FD_REEDSOL_ERR_PARTIAL ) ) {
      99             :       __builtin_trap();
     100             :     }
     101             :   } else {
     102             :     if( FD_UNLIKELY( FD_REEDSOL_SUCCESS!=retval ) ) {
     103             :       __builtin_trap();
     104             :     }
     105             : 
     106             :     for( ulong i=0UL; i<e_cnt; i++ ) {
     107             :       if( FD_UNLIKELY( memcmp( erased_truth[ i ], r[ i ], shred_sz ) ) ) {
     108             :         __builtin_trap();
     109             :       }
     110             :     }
     111             :   }
     112             : 
     113             :   /* Corrupt one shred and make sure it gets caught */
     114             :   uchar corrupt_shred[ SHRED_SZ_MAX ];
     115             :   ulong byte_idx = fd_rng_ulong_roll( rng, shred_sz );
     116             :   if( corrupt_idx<d_cnt ) {
     117             :     fd_memcpy( corrupt_shred, d[ corrupt_idx ], shred_sz );
     118             :     corrupt_shred[ byte_idx ] ^= (uchar)1;
     119             :     d[ corrupt_idx ] = &corrupt_shred[0];
     120             :   } else p[ corrupt_idx-d_cnt ][ byte_idx ] ^= (uchar)1;
     121             : 
     122             :   rs = fd_reedsol_recover_init( mem, shred_sz );
     123             :   for( ulong i=0UL; i<d_cnt; i++ ) fd_reedsol_recover_add_rcvd_shred( rs, 1, d[ i ] );
     124             :   for( ulong i=0UL; i<p_cnt; i++ ) fd_reedsol_recover_add_rcvd_shred( rs, 0, p[ i ] );
     125             : 
     126             :   if( FD_UNLIKELY( FD_REEDSOL_ERR_CORRUPT!=fd_reedsol_recover_fini( rs ) ) ) {
     127             :     __builtin_trap();
     128             :   }
     129             : 
     130             :   if( corrupt_idx<d_cnt )  d[ corrupt_idx       ]              = data_shreds + shred_sz*corrupt_idx;
     131             :   else                     p[ corrupt_idx-d_cnt ][ byte_idx ] ^= (uchar)1;
     132             : 
     133             :   fd_rng_delete( fd_rng_leave( rng ) );
     134             :   FD_FUZZ_MUST_BE_COVERED;
     135             :   return 0;
     136             : }

Generated by: LCOV version 1.14