Skip to content

Commit 589ab86

Browse files
committed
wip
1 parent 1f7b539 commit 589ab86

File tree

1 file changed

+154
-57
lines changed

1 file changed

+154
-57
lines changed

Diff for: fuzzing/fuzzer_worker_sequence_generator.go

+154-57
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ package fuzzing
33
import (
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,10 +410,10 @@ 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
}
@@ -394,19 +425,12 @@ func callSeqGenFuncExpansion(sequenceGenerator *CallSequenceGenerator, sequence
394425

395426
// Get item to expand
396427
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+
410434
return nil
411435
}
412436

@@ -425,19 +449,10 @@ func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequ
425449
return fmt.Errorf("could not obtain tail corpus call sequence for splice-at-random corpus mutation: %v", err)
426450
}
427451

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)
438454

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)
441456

442457
return nil
443458
}
@@ -457,30 +472,11 @@ func callSeqGenFuncInterleaveAtRandom(sequenceGenerator *CallSequenceGenerator,
457472
return fmt.Errorf("could not obtain second corpus call sequence for interleave-at-random corpus mutation: %v", err)
458473
}
459474

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+
484480
return nil
485481
}
486482

@@ -507,3 +503,104 @@ func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, elem
507503

508504
return nil
509505
}
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

Comments
 (0)