@@ -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,34 +410,23 @@ 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
}
389
420
390
421
// callSeqGenFuncExpansion is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a
391
422
// sequence which is expanded up to 30 times by replicating an existing call sequence element at a random position.
392
423
func callSeqGenFuncExpansion (sequenceGenerator * CallSequenceGenerator , sequence calls.CallSequence ) error {
393
- rounds := sequenceGenerator .worker .randomProvider .Intn (31 )
394
-
395
- // Get item to expand
396
- 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
- }
424
+
425
+ // Expand the sequence
426
+ expandedSequence := expandRandList (sequence )
427
+
428
+ copy (sequence , expandedSequence )
429
+
410
430
return nil
411
431
}
412
432
@@ -425,19 +445,10 @@ func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequ
425
445
return fmt .Errorf ("could not obtain tail corpus call sequence for splice-at-random corpus mutation: %v" , err )
426
446
}
427
447
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 )
448
+ // Splice the two sequences
449
+ splicedSequence := spliceAtRandom (headSequence , tailSequence )
438
450
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 :])
451
+ copy (sequence , splicedSequence )
441
452
442
453
return nil
443
454
}
@@ -457,30 +468,11 @@ func callSeqGenFuncInterleaveAtRandom(sequenceGenerator *CallSequenceGenerator,
457
468
return fmt .Errorf ("could not obtain second corpus call sequence for interleave-at-random corpus mutation: %v" , err )
458
469
}
459
470
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
- }
471
+ // Interleave the two sequences
472
+ interleavedSequence := interleaveLL (firstSequence , secondSequence )
473
+
474
+ copy (sequence , interleavedSequence )
475
+
484
476
return nil
485
477
}
486
478
@@ -507,3 +499,104 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
507
499
508
500
return nil
509
501
}
502
+
503
+ // replaceAt replaces the element at the given index with the provided value.
504
+ func replaceAt [T any ](xs []T , i T , n int ) []T {
505
+ return append (append (xs [:n ], i ), xs [n + 1 :]... )
506
+ }
507
+
508
+ // expandAt expands the element at index k by t times.
509
+ func expandAt [T any ](xs []T , k int , t int ) []T {
510
+ if len (xs ) == 0 {
511
+ return xs
512
+ }
513
+ return append (append (xs [:k ], repeat (xs [k ], t )... ), xs [k + 1 :]... )
514
+ }
515
+
516
+ // repeat replicates an element t times.
517
+ func repeat [T any ](v T , t int ) []T {
518
+ res := make ([]T , t )
519
+ for i := range res {
520
+ res [i ] = v
521
+ }
522
+ return res
523
+ }
524
+
525
+ // expandRandList expands a random element of the list by 1 to 32 times.
526
+ func expandRandList [T any ](xs []T ) []T {
527
+ l := len (xs )
528
+ if l == 0 || l >= 32 {
529
+ return xs
530
+ }
531
+ k := rand .Intn (l )
532
+ t := rand .Intn (min (32 , l )) + 1
533
+ return expandAt (xs , k , t )
534
+ }
535
+
536
+ // deleteAt deletes the element at the given index.
537
+ func deleteAt [T any ](xs []T , n int ) []T {
538
+ return append (xs [:n ], xs [n + 1 :]... )
539
+ }
540
+
541
+ // deleteRandList deletes a random element from the list.
542
+ func deleteRandList [T any ](xs []T ) []T {
543
+ if len (xs ) == 0 {
544
+ return xs
545
+ }
546
+ k := rand .Intn (len (xs ))
547
+ return deleteAt (xs , k )
548
+ }
549
+
550
+ // swapAt swaps two elements in the list.
551
+ func swapAt [T any ](xs []T , i , j int ) []T {
552
+ xs [i ], xs [j ] = xs [j ], xs [i ]
553
+ return xs
554
+ }
555
+
556
+ // swapRandList swaps two random elements in the list.
557
+ func swapRandList [T any ](xs []T ) []T {
558
+ if len (xs ) == 0 {
559
+ return xs
560
+ }
561
+ i , j := rand .Intn (len (xs )), rand .Intn (len (xs ))
562
+ return swapAt (xs , min (i , j ), max (i , j ))
563
+ }
564
+
565
+ // spliceAtRandom splices two lists at random positions.
566
+ func spliceAtRandom [T any ](xs1 , xs2 []T ) []T {
567
+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
568
+ return append (xs1 [:idx1 ], xs2 [idx2 :]... )
569
+ }
570
+
571
+ // interleaveAtRandom interleaves two lists at random positions.
572
+ func interleaveAtRandom [T any ](xs1 , xs2 []T ) []T {
573
+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
574
+ return interleaveLL (xs1 [:idx1 ], xs2 [:idx2 ])
575
+ }
576
+
577
+ // interleaveLL interleaves two lists.
578
+ func interleaveLL [T any ](a , b []T ) []T {
579
+ if len (a ) == 0 {
580
+ return b
581
+ }
582
+ if len (b ) == 0 {
583
+ return a
584
+ }
585
+ return append ([]T {a [0 ], b [0 ]}, interleaveLL (a [1 :], b [1 :])... )
586
+ }
587
+
588
+ // min returns the smaller of two integers.
589
+ func min (a , b int ) int {
590
+ if a < b {
591
+ return a
592
+ }
593
+ return b
594
+ }
595
+
596
+ // max returns the larger of two integers.
597
+ func max (a , b int ) int {
598
+ if a > b {
599
+ return a
600
+ }
601
+ return b
602
+ }
0 commit comments