@@ -3,11 +3,11 @@ package fuzzing
33import (
44 "fmt"
55 "math/big"
6+ "math/rand"
67
78 "github.com/crytic/medusa/fuzzing/calls"
89 "github.com/crytic/medusa/fuzzing/contracts"
910 "github.com/crytic/medusa/fuzzing/valuegeneration"
10- "github.com/crytic/medusa/utils"
1111 "github.com/crytic/medusa/utils/randomutils"
1212)
1313
@@ -186,6 +186,18 @@ func NewCallSequenceGenerator(worker *FuzzerWorker, config *CallSequenceGenerato
186186 },
187187 new (big.Int ).SetUint64 (config .RandomMutatedInterleaveAtRandomWeight ),
188188 ),
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+ ),
189201 )
190202
191203 return generator
@@ -352,6 +364,24 @@ func (g *CallSequenceGenerator) generateNewElement() (*calls.CallSequenceElement
352364 return calls .NewCallSequenceElement (selectedMethod .Contract , msg , blockNumberDelay , blockTimestampDelay ), nil
353365}
354366
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+
355385// callSeqGenFuncCorpusHead is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a sequence
356386// whose head is based off of an existing corpus call sequence.
357387// Returns an error if one occurs.
@@ -362,9 +392,10 @@ func callSeqGenFuncCorpusHead(sequenceGenerator *CallSequenceGenerator, sequence
362392 return fmt .Errorf ("could not obtain corpus call sequence for head mutation: %v" , err )
363393 }
364394
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 )
368399
369400 return nil
370401}
@@ -379,34 +410,23 @@ func callSeqGenFuncCorpusTail(sequenceGenerator *CallSequenceGenerator, sequence
379410 return fmt .Errorf ("could not obtain corpus call sequence for tail mutation: %v" , err )
380411 }
381412
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 )
386417
387418 return nil
388419}
389420
390421// callSeqGenFuncExpansion is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a
391422// sequence which is expanded up to 30 times by replicating an existing call sequence element at a random position.
392423func 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+
410430 return nil
411431}
412432
@@ -425,19 +445,10 @@ func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequ
425445 return fmt .Errorf ("could not obtain tail corpus call sequence for splice-at-random corpus mutation: %v" , err )
426446 }
427447
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 )
438450
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 )
441452
442453 return nil
443454}
@@ -457,30 +468,11 @@ func callSeqGenFuncInterleaveAtRandom(sequenceGenerator *CallSequenceGenerator,
457468 return fmt .Errorf ("could not obtain second corpus call sequence for interleave-at-random corpus mutation: %v" , err )
458469 }
459470
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 := interleaveAtRandom (firstSequence , secondSequence )
473+
474+ copy (sequence , interleavedSequence )
475+
484476 return nil
485477}
486478
@@ -507,3 +499,99 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
507499
508500 return nil
509501}
502+
503+ // expandAt expands the element at index k by t times.
504+ func expandAt [T any ](xs []T , k int , t int ) []T {
505+ if len (xs ) == 0 {
506+ return xs
507+ }
508+ return append (append (xs [:k ], repeat (xs [k ], t )... ), xs [k + 1 :]... )
509+ }
510+
511+ // repeat replicates an element t times.
512+ func repeat [T any ](v T , t int ) []T {
513+ res := make ([]T , t )
514+ for i := range res {
515+ res [i ] = v
516+ }
517+ return res
518+ }
519+
520+ // expandRandList expands a random element of the list by 1 to 32 times.
521+ func expandRandList [T any ](xs []T ) []T {
522+ l := len (xs )
523+ if l == 0 || l >= 32 {
524+ return xs
525+ }
526+ k := rand .Intn (l )
527+ t := rand .Intn (min (32 , l )) + 1
528+ return expandAt (xs , k , t )
529+ }
530+
531+ // deleteAt deletes the element at the given index.
532+ func deleteAt [T any ](xs []T , n int ) []T {
533+ return append (xs [:n ], xs [n + 1 :]... )
534+ }
535+
536+ // deleteRandList deletes a random element from the list.
537+ func deleteRandList [T any ](xs []T ) []T {
538+ if len (xs ) == 0 {
539+ return xs
540+ }
541+ k := rand .Intn (len (xs ))
542+ return deleteAt (xs , k )
543+ }
544+
545+ // swapAt swaps two elements in the list.
546+ func swapAt [T any ](xs []T , i , j int ) []T {
547+ xs [i ], xs [j ] = xs [j ], xs [i ]
548+ return xs
549+ }
550+
551+ // swapRandList swaps two random elements in the list.
552+ func swapRandList [T any ](xs []T ) []T {
553+ if len (xs ) == 0 {
554+ return xs
555+ }
556+ i , j := rand .Intn (len (xs )), rand .Intn (len (xs ))
557+ return swapAt (xs , min (i , j ), max (i , j ))
558+ }
559+
560+ // spliceAtRandom splices two lists at random positions.
561+ func spliceAtRandom [T any ](xs1 , xs2 []T ) []T {
562+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
563+ return append (xs1 [:idx1 ], xs2 [idx2 :]... )
564+ }
565+
566+ // interleaveAtRandom interleaves two lists at random positions.
567+ func interleaveAtRandom [T any ](xs1 , xs2 []T ) []T {
568+ idx1 , idx2 := rand .Intn (len (xs1 )), rand .Intn (len (xs2 ))
569+ return interleaveLL (xs1 [:idx1 ], xs2 [:idx2 ])
570+ }
571+
572+ // interleaveLL interleaves two lists.
573+ func interleaveLL [T any ](a , b []T ) []T {
574+ if len (a ) == 0 {
575+ return b
576+ }
577+ if len (b ) == 0 {
578+ return a
579+ }
580+ return append ([]T {a [0 ], b [0 ]}, interleaveLL (a [1 :], b [1 :])... )
581+ }
582+
583+ // min returns the smaller of two integers.
584+ func min (a , b int ) int {
585+ if a < b {
586+ return a
587+ }
588+ return b
589+ }
590+
591+ // max returns the larger of two integers.
592+ func max (a , b int ) int {
593+ if a > b {
594+ return a
595+ }
596+ return b
597+ }
0 commit comments