@@ -47,6 +47,51 @@ impl AflppFuzzer {
4747 pull_corpus : PathBuf :: new ( ) ,
4848 }
4949 }
50+
51+ fn fuzzer_stats_path ( & self ) -> PathBuf {
52+ self . out_dir . join ( self . id . to_string ( ) ) . join ( "fuzzer_stats" )
53+ }
54+
55+ fn queue_dir ( & self ) -> PathBuf {
56+ self . out_dir . join ( self . id . to_string ( ) ) . join ( "queue" )
57+ }
58+
59+ fn stderr_log_path ( & self ) -> PathBuf {
60+ self . workspace . join ( format ! ( "aflpp_instance_{}.log" , self . id) )
61+ }
62+
63+ fn queue_seed_count ( & self ) -> Option < u64 > {
64+ let seed_count = std:: fs:: read_dir ( self . queue_dir ( ) )
65+ . ok ( ) ?
66+ . filter_map ( Result :: ok)
67+ . filter ( |entry| entry. path ( ) . is_file ( ) )
68+ . count ( ) as u64 ;
69+
70+ ( seed_count > 0 ) . then_some ( seed_count)
71+ }
72+
73+ fn dry_run_crash_seed_count ( & self ) -> Option < u64 > {
74+ if self . fuzzer_stats_path ( ) . exists ( ) {
75+ return None ;
76+ }
77+
78+ let log = std:: fs:: read_to_string ( self . stderr_log_path ( ) ) . ok ( ) ?;
79+ if !log. contains ( "We need at least one valid input seed that does not crash" ) {
80+ return None ;
81+ }
82+
83+ self . queue_seed_count ( )
84+ }
85+
86+ fn maybe_cleanup_stderr_log ( & self ) {
87+ if std:: env:: var ( "FUZZOR_AFL_DEBUG" ) . is_ok ( ) {
88+ return ;
89+ }
90+
91+ if self . fuzzer_stats_path ( ) . exists ( ) {
92+ let _ = std:: fs:: remove_file ( self . stderr_log_path ( ) ) ;
93+ }
94+ }
5095}
5196
5297#[ async_trait]
@@ -62,9 +107,9 @@ impl Fuzzer for AflppFuzzer {
62107 async fn get_stats ( & self ) -> FuzzerStats {
63108 let mut stats = FuzzerStats :: default ( ) ;
64109
65- if let Ok ( stat_file) =
66- std :: fs :: read_to_string ( self . out_dir . join ( self . id . to_string ( ) ) . join ( "fuzzer_stats" ) )
67- {
110+ if let Ok ( stat_file) = std :: fs :: read_to_string ( self . fuzzer_stats_path ( ) ) {
111+ self . maybe_cleanup_stderr_log ( ) ;
112+
68113 let mut afl_fuzzer_stats = HashMap :: new ( ) ;
69114 stat_file
70115 . lines ( )
@@ -107,14 +152,18 @@ impl Fuzzer for AflppFuzzer {
107152 . unwrap_or ( 0.0 ) ,
108153 ) ;
109154 }
155+ } else if let Some ( seed_count) = self . dry_run_crash_seed_count ( ) {
156+ // Report dry run seed crashes as solution candidates.
157+ stats. corpus_count = seed_count;
158+ stats. saved_crashes = seed_count;
110159 }
111160
112161 stats
113162 }
114163
115164 fn get_push_corpus ( & self ) -> Option < PathBuf > {
116165 if self . id == 0 {
117- Some ( self . out_dir . join ( self . id . to_string ( ) ) . join ( "queue" ) )
166+ Some ( self . queue_dir ( ) )
118167 } else {
119168 None
120169 }
@@ -135,6 +184,9 @@ impl Fuzzer for AflppFuzzer {
135184 if !ignore_hangs {
136185 solution_dirs. push ( self . out_dir . join ( self . id . to_string ( ) ) . join ( "hangs" ) ) ;
137186 }
187+ if self . dry_run_crash_seed_count ( ) . is_some ( ) {
188+ solution_dirs. push ( self . queue_dir ( ) ) ;
189+ }
138190 solution_dirs
139191 }
140192
@@ -199,14 +251,12 @@ impl Fuzzer for AflppFuzzer {
199251 command. envs ( & self . env ) ;
200252
201253 command. stdout ( Stdio :: null ( ) ) ;
254+ let log_path = self . stderr_log_path ( ) ;
255+ let log_file = std:: fs:: File :: create ( & log_path) . expect ( "Could not create AFL++ log file" ) ;
202256 if std:: env:: var ( "FUZZOR_AFL_DEBUG" ) . is_ok ( ) {
203- let log_path = self . workspace . join ( format ! ( "aflpp_instance_{}.log" , self . id) ) ;
204- let log_file =
205- std:: fs:: File :: create ( & log_path) . expect ( "Could not create AFL++ log file" ) ;
206- command. stderr ( Stdio :: from ( log_file) ) ;
207- } else {
208- command. stderr ( Stdio :: null ( ) ) ;
257+ log:: info!( "AFL++ instance {} stderr is logged to {:?}" , self . id, log_path) ;
209258 }
259+ command. stderr ( Stdio :: from ( log_file) ) ;
210260
211261 let host_env: HashMap < String , String > = std:: env:: vars ( ) . collect ( ) ;
212262 command. envs ( host_env) ;
0 commit comments