@@ -90,11 +90,13 @@ const BOUNDARIES: [i64; 13] = [
9090
9191fn boundary_int ( rng : & mut Rng ) -> i64 { BOUNDARIES [ rng. usize_in ( BOUNDARIES . len ( ) ) ] }
9292
93+ /* 25% boundary values; rest are full-range random i64 */
9394fn rand_int ( rng : & mut Rng ) -> String {
9495 if rng. usize_in ( 4 ) == 0 { boundary_int ( rng) . to_string ( ) }
9596 else { ( rng. next ( ) as i64 ) . to_string ( ) }
9697}
9798
99+ /* Picks one of ten mutation strategies at uniform random */
98100fn mutate ( src : & str , corpus : & [ String ] , rng : & mut Rng ) -> String {
99101 match rng. usize_in ( 10 ) {
100102 0 => byte_flip ( src, rng) ,
@@ -119,12 +121,14 @@ fn byte_flip(src: &str, rng: &mut Rng) -> String {
119121 String :: from_utf8_lossy ( & bytes) . into_owned ( )
120122}
121123
124+ /* Splits into lines, applies f in place, rejoins; shared by drop/duplicate */
122125fn with_lines ( src : & str , f : impl FnOnce ( & mut Vec < & str > ) ) -> String {
123126 let mut lines: Vec < & str > = src. lines ( ) . collect ( ) ;
124127 f ( & mut lines) ;
125128 lines. join ( "\n " )
126129}
127130
131+ /* Injects a keyword snippet at a random line; exercises keywords in unexpected positions */
128132fn insert_keyword ( src : & str , rng : & mut Rng ) -> String {
129133 let kw = rand_keyword ( rng) ;
130134 let name = rand_name ( rng) ;
@@ -153,6 +157,7 @@ fn duplicate_line(src: &str, rng: &mut Rng) -> String {
153157 with_lines ( src, |lines| { let idx = rng. usize_in ( lines. len ( ) ) ; lines. insert ( idx, lines[ idx] ) ; } )
154158}
155159
160+ /* Cross-seeds two corpus entries to produce novel program shapes */
156161fn splice ( src : & str , corpus : & [ String ] , rng : & mut Rng ) -> String {
157162 if corpus. is_empty ( ) { return src. to_string ( ) ; }
158163 let other = & corpus[ rng. usize_in ( corpus. len ( ) ) ] ;
@@ -165,6 +170,7 @@ fn splice(src: &str, corpus: &[String], rng: &mut Rng) -> String {
165170 out. join ( "\n " )
166171}
167172
173+ /* Replaces the first numeric literal with a NaN-box boundary value */
168174fn inject_boundary ( src : & str , rng : & mut Rng ) -> String {
169175 let boundary = boundary_int ( rng) . to_string ( ) ;
170176 let bytes = src. as_bytes ( ) ;
@@ -220,6 +226,7 @@ fn indent_bomb(rng: &mut Rng) -> String {
220226 out
221227}
222228
229+ /* Injects a comment line to exercise lexer comment skipping */
223230fn add_comment ( src : & str , rng : & mut Rng ) -> String {
224231 let comment = format ! ( "# {}" , rand_int( rng) ) ;
225232 let mut lines: Vec < & str > = src. lines ( ) . collect ( ) ;
@@ -278,10 +285,11 @@ impl Perf {
278285
279286enum Outcome { Crash , ParseErr , VmErr , Timeout , Clean ( u128 , Duration , Duration , Duration ) }
280287
288+ /* Runs lex→parse→VM in an isolated thread; catches panics and enforces VM_TIMEOUT */
281289fn run_once ( src : & str ) -> Outcome {
282290 let src = if src. len ( ) > MAX_LEN { src[ ..MAX_LEN ] . to_string ( ) } else { src. to_string ( ) } ;
283291 let ( tx, rx) = mpsc:: channel ( ) ;
284- thread:: spawn ( move || {
292+ thread:: Builder :: new ( ) . stack_size ( 8 * 1024 * 1024 ) . spawn ( move || {
285293 let outcome = match panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
286294 let t0 = Instant :: now ( ) ;
287295 let ( tokens, _) = lex ( & src) ;
@@ -309,6 +317,7 @@ fn run_once(src: &str) -> Outcome {
309317 rx. recv_timeout ( VM_TIMEOUT ) . unwrap_or ( Outcome :: Timeout )
310318}
311319
320+ /* Coverage-guided seed pool; retains inputs that reach new opcodes */
312321struct Corpus { entries : Vec < String > , seen : u128 }
313322
314323impl Corpus {
@@ -324,6 +333,7 @@ impl Corpus {
324333 }
325334}
326335
336+ /* Run counters and start time for the periodic progress display */
327337struct Stats { iters : u64 , crashes : u64 , adds : u64 , timeouts : u64 , start : Instant }
328338
329339impl Stats {
0 commit comments