@@ -3,11 +3,11 @@ package fuzzing
3
3
import (
4
4
"fmt"
5
5
"math/big"
6
+ "math/rand"
6
7
7
8
"github.com/crytic/medusa/fuzzing/calls"
8
9
"github.com/crytic/medusa/fuzzing/contracts"
9
10
"github.com/crytic/medusa/fuzzing/valuegeneration"
10
- "github.com/crytic/medusa/utils"
11
11
"github.com/crytic/medusa/utils/randomutils"
12
12
)
13
13
@@ -186,6 +186,18 @@ func NewCallSequenceGenerator(worker *FuzzerWorker, config *CallSequenceGenerato
186
186
},
187
187
new (big.Int ).SetUint64 (config .RandomMutatedInterleaveAtRandomWeight ),
188
188
),
189
+ randomutils .NewWeightedRandomChoice (CallSequenceGeneratorMutationStrategy {
190
+ CallSequenceGeneratorFunc : callSeqSwapRandomElement ,
191
+ PrefetchModifyCallFunc : nil ,
192
+ },
193
+ new (big.Int ).SetUint64 (config .RandomMutatedInterleaveAtRandomWeight ),
194
+ ),
195
+ randomutils .NewWeightedRandomChoice (CallSequenceGeneratorMutationStrategy {
196
+ CallSequenceGeneratorFunc : callSeqDeleteRandomElement ,
197
+ PrefetchModifyCallFunc : nil ,
198
+ },
199
+ new (big.Int ).SetUint64 (config .RandomMutatedInterleaveAtRandomWeight ),
200
+ ),
189
201
)
190
202
191
203
return generator
@@ -352,6 +364,24 @@ func (g *CallSequenceGenerator) generateNewElement() (*calls.CallSequenceElement
352
364
return calls .NewCallSequenceElement (selectedMethod .Contract , msg , blockNumberDelay , blockTimestampDelay ), nil
353
365
}
354
366
367
+ func callSeqSwapRandomElement (sequenceGenerator * CallSequenceGenerator , sequence calls.CallSequence ) error {
368
+ // Swap the element
369
+ swappedSequence := swapRandList (sequence )
370
+
371
+ copy (sequence , swappedSequence )
372
+
373
+ return nil
374
+ }
375
+
376
+ func callSeqDeleteRandomElement (sequenceGenerator * CallSequenceGenerator , sequence calls.CallSequence ) error {
377
+ // Delete the element
378
+ deletedSequence := deleteRandList (sequence )
379
+
380
+ copy (sequence , deletedSequence )
381
+
382
+ return nil
383
+ }
384
+
355
385
// callSeqGenFuncCorpusHead is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a sequence
356
386
// whose head is based off of an existing corpus call sequence.
357
387
// Returns an error if one occurs.
@@ -362,9 +392,10 @@ func callSeqGenFuncCorpusHead(sequenceGenerator *CallSequenceGenerator, sequence
362
392
return fmt .Errorf ("could not obtain corpus call sequence for head mutation: %v" , err )
363
393
}
364
394
365
- // Determine the length of the slice to be copied in the head.
366
- maxLength := utils .Min (len (sequence ), len (corpusSequence ))
367
- copy (sequence , corpusSequence [:maxLength ])
395
+ // Append the new calls to the end of the corpus sequence
396
+ spliced := append (corpusSequence , sequence ... )
397
+
398
+ copy (sequence , spliced )
368
399
369
400
return nil
370
401
}
@@ -379,10 +410,10 @@ func callSeqGenFuncCorpusTail(sequenceGenerator *CallSequenceGenerator, sequence
379
410
return fmt .Errorf ("could not obtain corpus call sequence for tail mutation: %v" , err )
380
411
}
381
412
382
- // Determine a random position to slice the call sequence.
383
- maxLength := utils . Min ( len ( sequence ), len ( corpusSequence ) )
384
- targetLength := sequenceGenerator . worker . randomProvider . Intn ( maxLength ) + 1
385
- copy (sequence [ len ( sequence ) - targetLength :], corpusSequence [ len ( corpusSequence ) - targetLength :] )
413
+ // Prepend the new calls to the start of the corpus sequence
414
+ spliced := append ( sequence , corpusSequence ... )
415
+
416
+ copy (sequence , spliced )
386
417
387
418
return nil
388
419
}
@@ -394,19 +425,12 @@ func callSeqGenFuncExpansion(sequenceGenerator *CallSequenceGenerator, sequence
394
425
395
426
// Get item to expand
396
427
randIndex := sequenceGenerator .worker .randomProvider .Intn (len (sequence ))
397
- duplicatedElement := sequence [randIndex ]
398
-
399
- // Perform N rounds of expansion
400
- for i := 0 ; i < rounds ; i ++ {
401
- randIndex += i
402
- if randIndex < len (sequence ) {
403
- // Insert
404
- sequence = append (sequence [:randIndex ], append ([]* calls.CallSequenceElement {duplicatedElement }, sequence [randIndex :]... )... )
405
- } else {
406
- // Extend
407
- sequence = append (sequence , duplicatedElement )
408
- }
409
- }
428
+
429
+ // Expand the sequence
430
+ expandedSequence := expandAt (sequence , randIndex , rounds )
431
+
432
+ copy (sequence , expandedSequence )
433
+
410
434
return nil
411
435
}
412
436
@@ -425,19 +449,10 @@ func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequ
425
449
return fmt .Errorf ("could not obtain tail corpus call sequence for splice-at-random corpus mutation: %v" , err )
426
450
}
427
451
428
- // Determine a random position to slice off the head of the call sequence.
429
- maxLength := utils .Min (len (sequence ), len (headSequence ))
430
- headSequenceLength := sequenceGenerator .worker .randomProvider .Intn (maxLength ) + 1
431
-
432
- // Copy the head of the first corpus sequence to our destination sequence.
433
- copy (sequence , headSequence [:headSequenceLength ])
434
-
435
- // Determine a random position to slice off the tail of the call sequence.
436
- maxLength = utils .Min (len (sequence )- headSequenceLength , len (tailSequence ))
437
- tailSequenceLength := sequenceGenerator .worker .randomProvider .Intn (maxLength + 1 )
452
+ // Splice the two sequences
453
+ splicedSequence := spliceAtRandom (headSequence , tailSequence )
438
454
439
- // Copy the tail of the second corpus sequence to our destination sequence (after the head sequence portion).
440
- copy (sequence [headSequenceLength :], tailSequence [len (tailSequence )- tailSequenceLength :])
455
+ copy (sequence , splicedSequence )
441
456
442
457
return nil
443
458
}
@@ -457,30 +472,11 @@ func callSeqGenFuncInterleaveAtRandom(sequenceGenerator *CallSequenceGenerator,
457
472
return fmt .Errorf ("could not obtain second corpus call sequence for interleave-at-random corpus mutation: %v" , err )
458
473
}
459
474
460
- // Determine how many transactions to take from the first sequence and slice it.
461
- maxLength := utils .Min (len (sequence ), len (firstSequence ))
462
- firstSequenceLength := sequenceGenerator .worker .randomProvider .Intn (maxLength ) + 1
463
- firstSequence = firstSequence [:firstSequenceLength ]
464
-
465
- // Determine how many transactions to take from the second sequence and slice it.
466
- maxLength = utils .Min (len (sequence )- firstSequenceLength , len (secondSequence ))
467
- secondSequenceLength := sequenceGenerator .worker .randomProvider .Intn (maxLength + 1 )
468
- secondSequence = secondSequence [:secondSequenceLength ]
469
-
470
- // Now that we have both sequences, and we know they will not exceed our destination sequence length, interleave
471
- // them.
472
- destIndex := 0
473
- largestSequenceSize := utils .Max (firstSequenceLength , secondSequenceLength )
474
- for i := 0 ; i < largestSequenceSize ; i ++ {
475
- if i < len (firstSequence ) {
476
- sequence [destIndex ] = firstSequence [i ]
477
- destIndex ++
478
- }
479
- if i < len (secondSequence ) {
480
- sequence [destIndex ] = secondSequence [i ]
481
- destIndex ++
482
- }
483
- }
475
+ // Interleave the two sequences
476
+ interleavedSequence := interleaveLL (firstSequence , secondSequence )
477
+
478
+ copy (sequence , interleavedSequence )
479
+
484
480
return nil
485
481
}
486
482
@@ -507,3 +503,104 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
507
503
508
504
return nil
509
505
}
506
+
507
+ // replaceAt replaces the element at the given index with the provided value.
508
+ func replaceAt [T any ](xs []T , i T , n int ) []T {
509
+ return append (append (xs [:n ], i ), xs [n + 1 :]... )
510
+ }
511
+
512
+ // expandAt expands the element at index k by t times.
513
+ func expandAt [T any ](xs []T , k int , t int ) []T {
514
+ if len (xs ) == 0 {
515
+ return xs
516
+ }
517
+ return append (append (xs [:k ], repeat (xs [k ], t )... ), xs [k + 1 :]... )
518
+ }
519
+
520
+ // repeat replicates an element t times.
521
+ func repeat [T any ](v T , t int ) []T {
522
+ res := make ([]T , t )
523
+ for i := range res {
524
+ res [i ] = v
525
+ }
526
+ return res
527
+ }
528
+
529
+ // expandRandList expands a random element of the list by 1 to 32 times.
530
+ func expandRandList [T any ](xs []T ) []T {
531
+ l := len (xs )
532
+ if l == 0 || l >= 32 {
533
+ return xs
534
+ }
535
+ k := rand .Intn (l )
536
+ t := rand .Intn (min (32 , l )) + 1
537
+ return expandAt (xs , k , t )
538
+ }
539
+
540
+ // deleteAt deletes the element at the given index.
541
+ func deleteAt [T any ](xs []T , n int ) []T {
542
+ return append (xs [:n ], xs [n + 1 :]... )
543
+ }
544
+
545
+ // deleteRandList deletes a random element from the list.
546
+ func deleteRandList [T any ](xs []T ) []T {
547
+ if len (xs ) == 0 {
548
+ return xs
549
+ }
550
+ k := rand .Intn (len (xs ))
551
+ return deleteAt (xs , k )
552
+ }
553
+
554
+ // swapAt swaps two elements in the list.
555
+ func swapAt [T any ](xs []T , i , j int ) []T {
556
+ xs [i ], xs [j ] = xs [j ], xs [i ]
557
+ return xs
558
+ }
559
+
560
+ // swapRandList swaps two random elements in the list.
561
+ func swapRandList [T any ](xs []T ) []T {
562
+ if len (xs ) == 0 {
563
+ return xs
564
+ }
565
+ i , j := rand .Intn (len (xs )), rand .Intn (len (xs ))
566
+ return swapAt (xs , min (i , j ), max (i , j ))
567
+ }
568
+
569
+ // spliceAtRandom splices two lists at random positions.
570
+ func spliceAtRandom [T any ](xs1 , xs2 []T ) []T {
571
+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
572
+ return append (xs1 [:idx1 ], xs2 [idx2 :]... )
573
+ }
574
+
575
+ // interleaveAtRandom interleaves two lists at random positions.
576
+ func interleaveAtRandom [T any ](xs1 , xs2 []T ) []T {
577
+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
578
+ return interleaveLL (xs1 [:idx1 ], xs2 [:idx2 ])
579
+ }
580
+
581
+ // interleaveLL interleaves two lists.
582
+ func interleaveLL [T any ](a , b []T ) []T {
583
+ if len (a ) == 0 {
584
+ return b
585
+ }
586
+ if len (b ) == 0 {
587
+ return a
588
+ }
589
+ return append ([]T {a [0 ], b [0 ]}, interleaveLL (a [1 :], b [1 :])... )
590
+ }
591
+
592
+ // min returns the smaller of two integers.
593
+ func min (a , b int ) int {
594
+ if a < b {
595
+ return a
596
+ }
597
+ return b
598
+ }
599
+
600
+ // max returns the larger of two integers.
601
+ func max (a , b int ) int {
602
+ if a > b {
603
+ return a
604
+ }
605
+ return b
606
+ }
0 commit comments