@@ -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 := interleaveLL (firstSequence , secondSequence )
473+
474+ copy (sequence , interleavedSequence )
475+
484476 return nil
485477}
486478
@@ -507,3 +499,104 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
507499
508500 return nil
509501}
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