Skip to content

Commit 7260ca1

Browse files
committed
wip
1 parent 2ed4855 commit 7260ca1

File tree

2 files changed

+192
-65
lines changed

2 files changed

+192
-65
lines changed

fuzzing/fuzzer_worker_sequence_generator.go renamed to fuzzing/sequence_generator.go

Lines changed: 70 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/crytic/medusa/fuzzing/calls"
99
"github.com/crytic/medusa/fuzzing/contracts"
1010
"github.com/crytic/medusa/fuzzing/valuegeneration"
11+
"github.com/crytic/medusa/utils"
1112
"github.com/crytic/medusa/utils/randomutils"
1213
)
1314

@@ -98,7 +99,7 @@ type CallSequenceGeneratorConfig struct {
9899
// CallSequenceGeneratorFunc defines a method used to populate a provided call sequence with generated calls.
99100
// Returns an optional PrefetchModifyCallFunc to be executed prior to the fetching of each element, or an error if
100101
// one occurs.
101-
type CallSequenceGeneratorFunc func(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error
102+
type CallSequenceGeneratorFunc func(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error
102103

103104
// PrefetchModifyCallFunc defines a method used to modify a call sequence element before being fetched from this
104105
// provider for use.
@@ -241,7 +242,7 @@ func (g *CallSequenceGenerator) InitializeNextSequence() (bool, error) {
241242
// If we have a corpus mutation method, call it to generate our base sequence, then set the pre-fetch modify
242243
// call function.
243244
if corpusMutationFunc != nil && corpusMutationFunc.CallSequenceGeneratorFunc != nil {
244-
err = corpusMutationFunc.CallSequenceGeneratorFunc(g, g.baseSequence)
245+
err = corpusMutationFunc.CallSequenceGeneratorFunc(g.worker.randomProvider, g.worker.fuzzer.corpus.RandomMutationTargetSequence, g.baseSequence)
245246
if err != nil {
246247
return true, fmt.Errorf("could not generate a corpus mutation derived call sequence due to an error executing a mutation method: %v", err)
247248
}
@@ -364,18 +365,42 @@ func (g *CallSequenceGenerator) generateNewElement() (*calls.CallSequenceElement
364365
return calls.NewCallSequenceElement(selectedMethod.Contract, msg, blockNumberDelay, blockTimestampDelay), nil
365366
}
366367

367-
func callSeqSwapRandomElement(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
368+
// prefetchModifyCallFuncMutate is a PrefetchModifyCallFunc, called by a CallSequenceGenerator to apply mutations
369+
// to a call sequence element, prior to it being fetched.
370+
// Returns an error if one occurs.
371+
func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, element *calls.CallSequenceElement) error {
372+
// If this element has no ABI value based call data, exit early.
373+
if element.Call == nil || element.Call.DataAbiValues == nil {
374+
return nil
375+
}
376+
377+
// Loop for each input value and mutate it
378+
abiValuesMsgData := element.Call.DataAbiValues
379+
for i := 0; i < len(abiValuesMsgData.InputValues); i++ {
380+
mutatedInput, err := valuegeneration.MutateAbiValue(sequenceGenerator.config.ValueGenerator, sequenceGenerator.config.ValueMutator, &abiValuesMsgData.Method.Inputs[i].Type, abiValuesMsgData.InputValues[i])
381+
if err != nil {
382+
return fmt.Errorf("error when mutating call sequence input argument: %v", err)
383+
}
384+
abiValuesMsgData.InputValues[i] = mutatedInput
385+
}
386+
// Re-encode the message's calldata
387+
element.Call.WithDataAbiValues(abiValuesMsgData)
388+
389+
return nil
390+
}
391+
392+
func callSeqSwapRandomElement(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
368393
// Swap the element
369-
swappedSequence := swapRandList(sequence)
394+
swappedSequence := swapRandList(provider, sequence)
370395

371396
copy(sequence, swappedSequence)
372397

373398
return nil
374399
}
375400

376-
func callSeqDeleteRandomElement(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
401+
func callSeqDeleteRandomElement(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
377402
// Delete the element
378-
deletedSequence := deleteRandList(sequence)
403+
deletedSequence := deleteRandList(provider, sequence)
379404

380405
copy(sequence, deletedSequence)
381406

@@ -385,15 +410,16 @@ func callSeqDeleteRandomElement(sequenceGenerator *CallSequenceGenerator, sequen
385410
// callSeqGenFuncCorpusHead is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a sequence
386411
// whose head is based off of an existing corpus call sequence.
387412
// Returns an error if one occurs.
388-
func callSeqGenFuncCorpusHead(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
413+
func callSeqGenFuncCorpusHead(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
389414
// Obtain a call sequence from the corpus
390-
corpusSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
415+
corpusSequence, err := sequenceGenerator()
391416
if err != nil {
392417
return fmt.Errorf("could not obtain corpus call sequence for head mutation: %v", err)
393418
}
394419

395-
// Append the new calls to the end of the corpus sequence
396-
spliced := append(corpusSequence, sequence...)
420+
// Prepend the new calls to the end of the corpus sequence
421+
i := provider.Intn(len(corpusSequence)) + 1
422+
spliced := append(corpusSequence[:i], sequence...)
397423

398424
copy(sequence, spliced)
399425

@@ -403,15 +429,18 @@ func callSeqGenFuncCorpusHead(sequenceGenerator *CallSequenceGenerator, sequence
403429
// callSeqGenFuncCorpusTail is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a sequence
404430
// whose tail is based off of an existing corpus call sequence.
405431
// Returns an error if one occurs.
406-
func callSeqGenFuncCorpusTail(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
432+
func callSeqGenFuncCorpusTail(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
407433
// Obtain a call sequence from the corpus
408-
corpusSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
434+
corpusSequence, err := sequenceGenerator()
409435
if err != nil {
410436
return fmt.Errorf("could not obtain corpus call sequence for tail mutation: %v", err)
411437
}
412438

413-
// Prepend the new calls to the start of the corpus sequence
414-
spliced := append(sequence, corpusSequence...)
439+
maxLength := utils.Min(len(sequence), len(corpusSequence))
440+
i := provider.Intn(maxLength) + 1
441+
fmt.Println("i: ", i)
442+
// Append the new calls to the end of the corpus sequence
443+
spliced := append(sequence[i:], corpusSequence...)
415444

416445
copy(sequence, spliced)
417446

@@ -420,10 +449,10 @@ func callSeqGenFuncCorpusTail(sequenceGenerator *CallSequenceGenerator, sequence
420449

421450
// callSeqGenFuncExpansion is a CallSequenceGeneratorFunc which prepares a CallSequenceGenerator to generate a
422451
// sequence which is expanded up to 30 times by replicating an existing call sequence element at a random position.
423-
func callSeqGenFuncExpansion(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
452+
func callSeqGenFuncExpansion(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
424453

425454
// Expand the sequence
426-
expandedSequence := expandRandList(sequence)
455+
expandedSequence := expandRandList(provider, sequence)
427456

428457
copy(sequence, expandedSequence)
429458

@@ -434,19 +463,18 @@ func callSeqGenFuncExpansion(sequenceGenerator *CallSequenceGenerator, sequence
434463
// sequence which is based off of two corpus call sequence entries, from which a random length head and tail are
435464
// respectively sliced and joined together.
436465
// Returns an error if one occurs.
437-
func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
466+
func callSeqGenFuncSpliceAtRandom(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
438467
// Obtain two corpus call sequence entries
439-
headSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
468+
headSequence, err := sequenceGenerator()
440469
if err != nil {
441-
return fmt.Errorf("could not obtain head corpus call sequence for splice-at-random corpus mutation: %v", err)
442470
}
443-
tailSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
471+
tailSequence, err := sequenceGenerator()
444472
if err != nil {
445473
return fmt.Errorf("could not obtain tail corpus call sequence for splice-at-random corpus mutation: %v", err)
446474
}
447475

448476
// Splice the two sequences
449-
splicedSequence := spliceAtRandom(headSequence, tailSequence)
477+
splicedSequence := spliceAtRandom(provider, headSequence, tailSequence)
450478

451479
copy(sequence, splicedSequence)
452480

@@ -457,99 +485,76 @@ func callSeqGenFuncSpliceAtRandom(sequenceGenerator *CallSequenceGenerator, sequ
457485
// sequence which is based off of two corpus call sequence entries, from which a random number of transactions are
458486
// taken and interleaved (each element of one sequence will be followed by an element of the other).
459487
// Returns an error if one occurs.
460-
func callSeqGenFuncInterleaveAtRandom(sequenceGenerator *CallSequenceGenerator, sequence calls.CallSequence) error {
488+
func callSeqGenFuncInterleaveAtRandom(provider *rand.Rand, sequenceGenerator func() (calls.CallSequence, error), sequence calls.CallSequence) error {
461489
// Obtain two corpus call sequence entries
462-
firstSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
490+
firstSequence, err := sequenceGenerator()
463491
if err != nil {
464492
return fmt.Errorf("could not obtain first corpus call sequence for interleave-at-random corpus mutation: %v", err)
465493
}
466-
secondSequence, err := sequenceGenerator.worker.fuzzer.corpus.RandomMutationTargetSequence()
494+
secondSequence, err := sequenceGenerator()
467495
if err != nil {
468496
return fmt.Errorf("could not obtain second corpus call sequence for interleave-at-random corpus mutation: %v", err)
469497
}
470498

471499
// Interleave the two sequences
472-
interleavedSequence := interleaveAtRandom(firstSequence, secondSequence)
500+
interleavedSequence := interleaveAtRandom(provider, firstSequence, secondSequence)
473501

474502
copy(sequence, interleavedSequence)
475503

476504
return nil
477505
}
478506

479-
// prefetchModifyCallFuncMutate is a PrefetchModifyCallFunc, called by a CallSequenceGenerator to apply mutations
480-
// to a call sequence element, prior to it being fetched.
481-
// Returns an error if one occurs.
482-
func prefetchModifyCallFuncMutate(sequenceGenerator *CallSequenceGenerator, element *calls.CallSequenceElement) error {
483-
// If this element has no ABI value based call data, exit early.
484-
if element.Call == nil || element.Call.DataAbiValues == nil {
485-
return nil
486-
}
487-
488-
// Loop for each input value and mutate it
489-
abiValuesMsgData := element.Call.DataAbiValues
490-
for i := 0; i < len(abiValuesMsgData.InputValues); i++ {
491-
mutatedInput, err := valuegeneration.MutateAbiValue(sequenceGenerator.config.ValueGenerator, sequenceGenerator.config.ValueMutator, &abiValuesMsgData.Method.Inputs[i].Type, abiValuesMsgData.InputValues[i])
492-
if err != nil {
493-
return fmt.Errorf("error when mutating call sequence input argument: %v", err)
494-
}
495-
abiValuesMsgData.InputValues[i] = mutatedInput
496-
}
497-
// Re-encode the message's calldata
498-
element.Call.WithDataAbiValues(abiValuesMsgData)
499-
500-
return nil
501-
}
502-
503507
// expandAt expands the element at index k by t times.
504-
func expandAt[T any](xs []T, k int, t int) []T {
508+
func expandAt[T any](xs []*T, k int, t int) []*T {
505509
if len(xs) == 0 {
506510
return xs
507511
}
508512
return append(append(xs[:k], repeat(xs[k], t)...), xs[k+1:]...)
509513
}
510514

511515
// repeat replicates an element t times.
512-
func repeat[T any](v T, t int) []T {
513-
res := make([]T, t)
516+
func repeat[T any](v *T, t int) []*T {
517+
res := make([]*T, t)
514518
for i := range res {
515519
res[i] = v
516520
}
517521
return res
518522
}
519523

520524
// expandRandList expands a random element of the list by 1 to 32 times.
521-
func expandRandList[T any](xs []T) []T {
525+
func expandRandList[T any](provider *rand.Rand, xs []*T) []*T {
522526
l := len(xs)
523527
if l == 0 || l >= 32 {
524528
return xs
525529
}
526-
k := rand.Intn(l)
527-
t := rand.Intn(min(32, l)) + 1
530+
k := provider.Intn(l)
531+
t := provider.Intn(min(32, l)) + 1
528532
return expandAt(xs, k, t)
529533
}
530534

531535
// 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:]...)
536+
func deleteAt[T any](xs []*T, n int) []*T {
537+
xs[n] = nil
538+
return xs
534539
}
535540

536541
// deleteRandList deletes a random element from the list.
537-
func deleteRandList[T any](xs []T) []T {
542+
func deleteRandList[T any](provider *rand.Rand, xs []*T) []*T {
538543
if len(xs) == 0 {
539544
return xs
540545
}
541-
k := rand.Intn(len(xs))
546+
k := provider.Intn(len(xs))
542547
return deleteAt(xs, k)
543548
}
544549

545550
// swapAt swaps two elements in the list.
546-
func swapAt[T any](xs []T, i, j int) []T {
551+
func swapAt[T any](xs []*T, i, j int) []*T {
547552
xs[i], xs[j] = xs[j], xs[i]
548553
return xs
549554
}
550555

551556
// swapRandList swaps two random elements in the list.
552-
func swapRandList[T any](xs []T) []T {
557+
func swapRandList[T any](provider *rand.Rand, xs []*T) []*T {
553558
if len(xs) == 0 {
554559
return xs
555560
}
@@ -558,26 +563,26 @@ func swapRandList[T any](xs []T) []T {
558563
}
559564

560565
// spliceAtRandom splices two lists at random positions.
561-
func spliceAtRandom[T any](xs1, xs2 []T) []T {
566+
func spliceAtRandom[T any](provider *rand.Rand, xs1, xs2 []*T) []*T {
562567
idx1, idx2 := rand.Intn(len(xs1)), rand.Intn(len(xs2))
563568
return append(xs1[:idx1], xs2[idx2:]...)
564569
}
565570

566571
// interleaveAtRandom interleaves two lists at random positions.
567-
func interleaveAtRandom[T any](xs1, xs2 []T) []T {
572+
func interleaveAtRandom[T any](provider *rand.Rand, xs1, xs2 []*T) []*T {
568573
idx1, idx2 := rand.Intn(len(xs1)), rand.Intn(len(xs2))
569574
return interleaveLL(xs1[:idx1], xs2[:idx2])
570575
}
571576

572577
// interleaveLL interleaves two lists.
573-
func interleaveLL[T any](a, b []T) []T {
578+
func interleaveLL[T any](a, b []*T) []*T {
574579
if len(a) == 0 {
575580
return b
576581
}
577582
if len(b) == 0 {
578583
return a
579584
}
580-
return append([]T{a[0], b[0]}, interleaveLL(a[1:], b[1:])...)
585+
return append([]*T{a[0], b[0]}, interleaveLL(a[1:], b[1:])...)
581586
}
582587

583588
// min returns the smaller of two integers.

0 commit comments

Comments
 (0)