Skip to content

Commit 1854c9c

Browse files
riptlripatel-fd
authored andcommitted
solfuzz: recursive dir descent in C
1 parent 67b4300 commit 1854c9c

File tree

3 files changed

+192
-28
lines changed

3 files changed

+192
-28
lines changed

contrib/test/run_test_vectors.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,25 @@ else
4949
./$OBJDIR/bin/fd_wksp_ctl new run-test-vectors $PAGE_CNT $PAGE_SZ 0 0644 --log-path ''
5050
fi
5151

52-
SOL_COMPAT=( "$OBJDIR/unit-test/test_sol_compat" "--wksp" "$WKSP" )
52+
SOL_COMPAT=( "$OBJDIR/unit-test/test_sol_compat" "--wksp" "$WKSP" --tile-cpus "f,0-$(( $NUM_PROCESSES - 1 ))" )
5353

5454
export FD_LOG_PATH=$LOG_PATH/test_exec_block
55-
find dump/test-vectors/block/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]}
55+
${SOL_COMPAT[@]} dump/test-vectors/block/fixtures
5656

5757
export FD_LOG_PATH=$LOG_PATH/test_exec_syscall
58-
find dump/test-vectors/syscall/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]}
58+
${SOL_COMPAT[@]} dump/test-vectors/syscall/fixtures
5959

6060
export FD_LOG_PATH=$LOG_PATH/test_exec_interp
61-
find dump/test-vectors/vm_interp/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]}
61+
${SOL_COMPAT[@]} dump/test-vectors/vm_interp/fixtures
6262

6363
export FD_LOG_PATH=$LOG_PATH/test_exec_txn
64-
find dump/test-vectors/txn/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES ${SOL_COMPAT[@]}
64+
${SOL_COMPAT[@]} dump/test-vectors/txn/fixtures
6565

6666
zstd -df dump/test-vectors/elf_loader/fixtures/*.zst
6767
export FD_LOG_PATH=$LOG_PATH/test_elf_loader
68-
find dump/test-vectors/elf_loader/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]}
68+
${SOL_COMPAT[@]} dump/test-vectors/elf_loader/fixtures
6969

7070
export FD_LOG_PATH=$LOG_PATH/test_exec_instr
71-
find dump/test-vectors/instr/fixtures -type f -name '*.fix' | xargs -P $NUM_PROCESSES -n 1000 ${SOL_COMPAT[@]}
71+
${SOL_COMPAT[@]} dump/test-vectors/instr/fixtures
7272

7373
echo Test vectors success

src/flamenco/runtime/tests/fd_solfuzz.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ fd_solfuzz_runner_new( fd_wksp_t * wksp,
8383
void * funk_mem = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_footprint( txn_max, rec_max ), wksp_tag );
8484
void * spad_mem = fd_wksp_alloc_laddr( wksp, fd_spad_align(), fd_spad_footprint( spad_max ), wksp_tag );
8585
void * banks_mem = fd_wksp_alloc_laddr( wksp, fd_banks_align(), fd_banks_footprint( bank_max, fork_max ), wksp_tag );
86-
if( FD_UNLIKELY( !runner || !funk_mem || !spad_mem || !banks_mem ) ) goto bail1;
86+
if( FD_UNLIKELY( !runner ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(solfuzz_runner) failed" )); goto bail1; }
87+
if( FD_UNLIKELY( !funk_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(funk) failed" )); goto bail1; }
88+
if( FD_UNLIKELY( !spad_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(spad) failed (spad_max=%g)", (double)spad_max )); goto bail1; }
89+
if( FD_UNLIKELY( !banks_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(banks) failed (bank_max=%lu fork_max=%lu)", bank_max, fork_max )); goto bail1; }
8790

8891
/* Create objects */
8992
fd_memset( runner, 0, sizeof(fd_solfuzz_runner_t) );

src/flamenco/runtime/tests/test_sol_compat.c

Lines changed: 181 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
1+
#define _DEFAULT_SOURCE
12
#include "fd_solfuzz.h"
23
#include <errno.h>
4+
#include <dirent.h>
35
#include <fcntl.h>
46
#include <sys/types.h>
57
#include <sys/stat.h>
68
#include <unistd.h>
79
#include "../fd_runtime.h"
810
#include "../../../ballet/nanopb/pb_firedancer.h"
911

12+
static int fail_fast;
13+
static int error_occurred;
14+
1015
/* run_test runs a test.
1116
Return 1 on success, 0 on failure. */
1217
static int
13-
run_test( fd_solfuzz_runner_t * runner,
14-
char const * path ) {
18+
run_test1( fd_solfuzz_runner_t * runner,
19+
char const * path ) {
1520

1621
/* Read file content to memory */
1722

1823
int file = open( path, O_RDONLY );
24+
if( FD_UNLIKELY( file<0 ) ) {
25+
FD_LOG_WARNING(( "open(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) ));
26+
return 0;
27+
}
1928
struct stat st;
2029
if( FD_UNLIKELY( 0!=fstat( file, &st ) ) ) {
21-
FD_LOG_WARNING(( "fstat(%s): %s", path, fd_io_strerror( errno ) ));
30+
FD_LOG_WARNING(( "fstat(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) ));
2231
return 0;
2332
}
2433
ulong file_sz = (ulong)st.st_size;
@@ -53,6 +62,142 @@ run_test( fd_solfuzz_runner_t * runner,
5362
return ok;
5463
}
5564

65+
static int
66+
run_test( fd_solfuzz_runner_t * runner,
67+
char const * path ) {
68+
ulong frames_used_pre_test = runner->spad->frame_free;
69+
ulong mem_used_pre_test = runner->spad->mem_used;
70+
71+
fd_spad_push( runner->spad );
72+
int ok = !!run_test1( runner, path );
73+
fd_spad_pop( runner->spad );
74+
75+
ulong frames_used_post_test = runner->spad->frame_free;
76+
ulong mem_used_post_test = runner->spad->mem_used;
77+
78+
FD_TEST( frames_used_pre_test == frames_used_post_test );
79+
FD_TEST( mem_used_pre_test == mem_used_post_test );
80+
return ok;
81+
}
82+
83+
/* Recursive dir walk function, follows symlinks */
84+
85+
typedef int (* visit_path)( void * ctx, char const * path );
86+
87+
static int
88+
recursive_walk1( DIR * dir,
89+
char path[ PATH_MAX ],
90+
ulong path_len,
91+
visit_path visit,
92+
void * visit_ctx ) {
93+
struct dirent * entry;
94+
errno = 0;
95+
while(( entry = readdir( dir ) )) {
96+
path[ path_len ] = '\0';
97+
if( FD_LIKELY( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) ) continue;
98+
99+
ulong child_len = strlen( entry->d_name );
100+
if( FD_UNLIKELY( path_len+1+child_len+1>PATH_MAX ) ) {
101+
FD_LOG_WARNING(( "Ignoring overlong path name: %s/%s", path, entry->d_name ));
102+
continue;
103+
}
104+
105+
char * p = path+path_len;
106+
p = fd_cstr_append_char( p, '/' );
107+
p = fd_cstr_append_text( p, entry->d_name, child_len );
108+
fd_cstr_fini( p );
109+
ulong sub_path_len = (ulong)( p-path );
110+
111+
DIR * subdir = NULL;
112+
char * suffix;
113+
if( entry->d_type==DT_DIR ) {
114+
subdir = opendir( path );
115+
if( FD_UNLIKELY( !subdir ) ) {
116+
FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) ));
117+
continue;
118+
}
119+
as_dir:
120+
recursive_walk1( subdir, path, sub_path_len, visit, visit_ctx );
121+
closedir( subdir );
122+
} else if( entry->d_type==DT_REG ) {
123+
as_file:
124+
suffix = strstr( entry->d_name, ".fix" );
125+
if( !suffix || suffix[4]!='\0' ) continue;
126+
if( !visit( visit_ctx, path ) ) break;
127+
} else if( entry->d_type==DT_LNK ) {
128+
subdir = opendir( path );
129+
if( subdir ) {
130+
goto as_dir;
131+
} else {
132+
if( FD_UNLIKELY( errno!=ENOTDIR ) ) {
133+
FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) ));
134+
continue;
135+
}
136+
goto as_file;
137+
}
138+
}
139+
}
140+
return 1;
141+
}
142+
143+
static int
144+
recursive_walk( char const * path,
145+
visit_path visit,
146+
void * visit_ctx ) {
147+
char path1[ PATH_MAX ];
148+
ulong path_len = strlen( path );
149+
if( FD_UNLIKELY( path_len>=PATH_MAX ) ) {
150+
FD_LOG_WARNING(( "Ignoring overlong path name: %s", path ));
151+
return 0;
152+
}
153+
fd_cstr_fini( fd_cstr_append_text( fd_cstr_init( path1 ), path, path_len ) );
154+
DIR * root_dir = opendir( path1 );
155+
if( FD_UNLIKELY( !root_dir ) ) {
156+
FD_LOG_WARNING(( "opendir(%s) failed: (%i-%s)", path, errno, fd_io_strerror( errno ) ));
157+
return 0;
158+
}
159+
int ok = recursive_walk1( root_dir, path1, path_len, visit, visit_ctx );
160+
closedir( root_dir );
161+
return ok;
162+
}
163+
164+
/* Single-threaded mode: execute synchronously while walking dir */
165+
166+
static int
167+
visit_sync( void * ctx,
168+
char const * path ) {
169+
fd_solfuzz_runner_t * runner = ctx;
170+
int ok = run_test( runner, path );
171+
if( !ok ) {
172+
error_occurred = 1;
173+
if( fail_fast ) return 0;
174+
}
175+
return 1;
176+
}
177+
178+
static void
179+
run_single_threaded( fd_solfuzz_runner_t * runner,
180+
int argc,
181+
char ** argv ) {
182+
for( int j=1; j<argc; j++ ) {
183+
int ok = recursive_walk( argv[ j ], visit_sync, runner );
184+
if( !ok ) {
185+
FD_LOG_WARNING(( "Stopping early" ));
186+
}
187+
}
188+
}
189+
190+
/* Multi-threaded mode: fan out tasks to bank of tiles */
191+
192+
FD_FN_UNUSED static void
193+
run_multi_threaded( fd_solfuzz_runner_t ** runners,
194+
ulong worker_cnt,
195+
int argc,
196+
char ** argv ) {
197+
(void)runners; (void)worker_cnt; (void)argc; (void)argv;
198+
FD_LOG_WARNING(( "Multi-threaded mode not implemented yet" ));
199+
}
200+
56201
int
57202
main( int argc,
58203
char ** argv ) {
@@ -74,29 +219,45 @@ main( int argc,
74219
}
75220
if( FD_UNLIKELY( !wksp ) ) return 255;
76221

77-
fd_solfuzz_runner_t * runner = fd_solfuzz_runner_new( wksp, wksp_tag );
78-
FD_TEST( runner );
222+
/* Run strategy: If the application was launched with one tile
223+
(default), run everything on the current tile. If more than one
224+
tile is detected, use the first tile (recommended floating) to walk
225+
the file system, use all other tiles to execute fuzz vectors. */
226+
ulong worker_cnt = fd_tile_cnt();
227+
if( worker_cnt>1UL ) worker_cnt--;
79228

80-
ulong fail_cnt = 0UL;
81-
for( int j=1; j<argc; j++ ) {
82-
ulong frames_used_pre_test = runner->spad->frame_free;
83-
ulong mem_used_pre_test = runner->spad->mem_used;
84-
85-
fd_spad_push( runner->spad );
86-
fail_cnt += !run_test( runner, argv[j] );
87-
fd_spad_pop( runner->spad );
88-
89-
ulong frames_used_post_test = runner->spad->frame_free;
90-
ulong mem_used_post_test = runner->spad->mem_used;
229+
/* Allocate runners */
230+
int exit_code = 255;
231+
fd_solfuzz_runner_t ** runners = fd_wksp_alloc_laddr( wksp, alignof(void *), worker_cnt*sizeof(void *), 1UL );
232+
if( FD_UNLIKELY( !runners ) ) { FD_LOG_WARNING(( "init failed" )); goto exit; }
233+
fd_memset( runners, 0, worker_cnt*sizeof(void *) );
234+
for( ulong i=0UL; i<worker_cnt; i++ ) {
235+
runners[i] = fd_solfuzz_runner_new( wksp, wksp_tag );
236+
if( FD_UNLIKELY( !runners[i] ) ) { FD_LOG_WARNING(( "init failed (creating worker %lu)", i )); goto exit; }
237+
}
91238

92-
FD_TEST( frames_used_pre_test == frames_used_post_test );
93-
FD_TEST( mem_used_pre_test == mem_used_post_test );
239+
/* Run strategy */
240+
//if( fd_tile_cnt()==1 ) {
241+
run_single_threaded( runners[0], argc, argv );
242+
//} else {
243+
// run_multi_threaded( runners, worker_cnt, argc, argv );
244+
//}
245+
if( error_occurred ) {
246+
if( fail_fast ) exit_code = 255;
247+
else exit_code = 1;
248+
} else {
249+
exit_code = 0;
94250
}
95251

96-
fd_solfuzz_runner_delete( runner );
252+
exit:
253+
/* Undo all wksp allocs */
254+
for( ulong i=0UL; runners && i<worker_cnt; i++ ) {
255+
if( runners[i] ) fd_solfuzz_runner_delete( runners[i] );
256+
}
257+
fd_wksp_free_laddr( runners );
97258
if( wksp_name ) fd_wksp_detach( wksp );
98259
else fd_wksp_demand_paged_delete( wksp );
99260

100261
fd_halt();
101-
return fail_cnt>0UL;
262+
return exit_code;
102263
}

0 commit comments

Comments
 (0)