LCOV - code coverage report
Current view: top level - util/sanitize - fd_fuzz_stub.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 32 82 39.0 %
Date: 2025-07-01 05:00:49 Functions: 2 4 50.0 %

          Line data    Source code
       1             : #include "fd_fuzz.h"
       2             : #include "../fd_util.h"
       3             : 
       4             : #include <errno.h>
       5             : #include <dirent.h>
       6             : #include <fcntl.h>
       7             : #include <stdlib.h>
       8             : #include <stdio.h>
       9             : #include <sys/stat.h>
      10             : #include <sys/types.h>
      11             : #include <unistd.h>
      12             : 
      13             : /* fd_fuzz_stub.c is a stub fuzz harness for build targets without an
      14             :    actual fuzz engine.  This harness mocks the libFuzzer command-line
      15             :    and can regression test against existing input files.  It cannot,
      16             :    however, do any actual fuzz exploration. */
      17             : 
      18             : static int
      19           0 : i_am_a_stub( void ) {
      20           0 :   fputs( "FAIL: No fuzz engine.\n"
      21           0 :          "\n"
      22           0 :          "This fuzz target was compiled without a fuzz engine.\n"
      23           0 :          "You can still re-run individual test cases like so:\n"
      24           0 :          "  <prog> path/to/file1 path/to/file2 ...\n"
      25           0 :          "\n"
      26           0 :          "Hint: Compile with CC=clang EXTRAS=fuzz to build with the libFuzzer engine.\n",
      27           0 :          stderr );
      28           0 :   return 1;
      29           0 : }
      30             : 
      31             : extern int
      32             : LLVMFuzzerInitialize( int  *   argc,
      33             :                       char *** argv );
      34             : 
      35             : extern int
      36             : LLVMFuzzerTestOneInput( uchar const * data,
      37             :                         ulong         data_sz );
      38             : 
      39             : __attribute__((weak))
      40             : ulong
      41             : LLVMFuzzerMutate( uchar * data,
      42             :                   ulong   data_sz,
      43           0 :                   ulong   max_sz ) {
      44           0 :   (void)data; (void)data_sz; (void)max_sz;
      45           0 :   return 0UL;
      46           0 : }
      47             : 
      48             : static int
      49        3369 : execute( int file ) {
      50        3369 :   struct stat st;
      51        3369 :   if( FD_UNLIKELY( 0!=fstat( file, &st ) ) ) {
      52           0 :     FD_LOG_ERR(( "fstat(%d) failed (%d-%s)", file, errno, fd_io_strerror( errno ) ));
      53           0 :     return errno;
      54           0 :   }
      55        3369 :   if( st.st_mode & S_IFDIR ) return EISDIR;
      56        3369 :   if( !( st.st_mode & S_IFREG ) ) return EBADF;
      57             : 
      58        3369 :   ulong file_sz = (ulong)st.st_size;
      59             : 
      60        3369 :   uchar * buf = malloc( file_sz );
      61        3369 :   if( !buf ) {
      62           0 :     FD_LOG_ERR(( "FAIL: Out of memory (failed to malloc %lu bytes)", file_sz ));
      63           0 :   }
      64             : 
      65        3369 :   ulong actual_read_sz;
      66        3369 :   int read_err = fd_io_read( file, buf, file_sz, file_sz, &actual_read_sz );
      67        3369 :   if( FD_UNLIKELY( read_err ) ) {
      68           0 :     FD_LOG_ERR(( "fd_io_read(%d,%lu) failed (%d-%s)", file, file_sz, errno, fd_io_strerror( errno ) ));
      69           0 :     return 1;
      70           0 :   }
      71             : 
      72        3369 :   LLVMFuzzerTestOneInput( buf, actual_read_sz );
      73        3369 :   free( buf );
      74        3369 :   return 0;
      75        3369 : }
      76             : 
      77             : int
      78             : main( int     argc,
      79          18 :       char ** argv ) {
      80             :   /* fd_boot is typically called by the target, so we don't call it here. */
      81             : 
      82          18 :   if( argc<=1 ) return i_am_a_stub();
      83             : 
      84          18 :   LLVMFuzzerInitialize( &argc, &argv );
      85             : 
      86        3441 :   for( int i=1; i<argc; i++ ) {
      87        3423 :     if( argv[i][0] == '-' ) continue;
      88             : 
      89        3369 :     int file0 = open( argv[i], O_RDONLY );
      90        3369 :     if( FD_UNLIKELY( file0<0 ) ) {
      91           0 :       FD_LOG_ERR(( "open(%s) failed (%d-%s)", argv[i], errno, fd_io_strerror( errno ) ));
      92           0 :     }
      93             : 
      94        3369 :     int err = execute( file0 );
      95        3369 :     if( err==EISDIR ) {
      96             : 
      97           0 :       DIR * dir = fdopendir( file0 );
      98           0 :       if( FD_UNLIKELY( !dir ) ) {
      99           0 :         FD_LOG_ERR(( "fdopendir(%d) failed (%d-%s)", file0, errno, fd_io_strerror( errno ) ));
     100           0 :       }
     101           0 :       for(;;) {
     102           0 :         errno = 0;
     103           0 :         struct dirent * ent = readdir( dir );
     104           0 :         if( !ent ) {
     105           0 :           if( FD_UNLIKELY( errno ) ) {
     106           0 :             FD_LOG_ERR(( "readdir(%d) failed (%d-%s)", file0, errno, fd_io_strerror( errno ) ));
     107           0 :           }
     108           0 :           break;
     109           0 :         }
     110           0 :         int file1 = openat( file0, ent->d_name, O_RDONLY );
     111           0 :         if( FD_UNLIKELY( file1<0 ) ) {
     112           0 :           FD_LOG_ERR(( "openat(%s/%s) failed (%d-%s)", argv[i], ent->d_name, errno, fd_io_strerror( errno ) ));
     113           0 :         }
     114           0 :         if( 0==execute( file1 ) ) {
     115           0 :           fprintf( stderr, "Executed %s/%s\n", argv[i], ent->d_name );
     116           0 :         }
     117           0 :         close( file1 );
     118           0 :       }
     119           0 :       closedir( dir );
     120           0 :       continue;
     121             : 
     122        3369 :     } else if( FD_UNLIKELY( err ) ) {
     123             : 
     124           0 :       fprintf( stderr, "Failed to execute %s", argv[i] );
     125             : 
     126        3369 :     } else {
     127             : 
     128        3369 :       fprintf( stderr, "Executed %s\n", argv[i] );
     129             : 
     130        3369 :     }
     131             : 
     132        3369 :     close( file0 );
     133        3369 :   }
     134             : 
     135          18 :   return 0;
     136          18 : }

Generated by: LCOV version 1.14