From 47c9c81bf83d76ee508d717b129d575249dd3cd0 Mon Sep 17 00:00:00 2001 From: Nathaniel Brough Date: Sun, 19 Mar 2023 10:35:47 -0700 Subject: [PATCH 1/2] feat(fuzz): Adds a fuzz test harness Adds a structured fuzz testing harness that excersizes the bloom filter and ensures that particular properties are enforced e.g. A value added to the filter should always be testable as in the filter set. --- fuzz/bloom_fuzz_test.go | 102 ++++++++++++++++++++++++++++++++++++++++ go.mod | 1 + go.sum | 15 ++++++ 3 files changed, 118 insertions(+) create mode 100644 fuzz/bloom_fuzz_test.go diff --git a/fuzz/bloom_fuzz_test.go b/fuzz/bloom_fuzz_test.go new file mode 100644 index 0000000..c71f6cd --- /dev/null +++ b/fuzz/bloom_fuzz_test.go @@ -0,0 +1,102 @@ +package fuzz_bloom + +import ( + "bytes" + "encoding/gob" + fuzz "github.com/AdaLogics/go-fuzz-headers" + "github.com/bits-and-blooms/bloom/v3" + "math" + "runtime/debug" + "testing" +) + +func RoundTripGobEncodeDecode(t *testing.T, filter *bloom.BloomFilter) { + var buffer bytes.Buffer + enc := gob.NewEncoder(&buffer) + err := enc.Encode(filter) + if err != nil { + t.Error(err) + } + dec := gob.NewDecoder(&buffer) + var decoded_filter bloom.BloomFilter + err = dec.Decode(&decoded_filter) + if err != nil { + t.Error(err) + } + if !decoded_filter.Equal(filter) { + t.Errorf("Expected round trip encode/decode to result in identical bloom filters.") + } +} + +type FuzzData struct { + ElementCount uint64 + FalsePositives float64 + Add [][]byte + AddString []string + TestLocations []uint64 + NotAdded [][]byte +} + +const ( + maxElements = 10240 + minElements = 2 + maxFalsePositives = 0.99 + minFalsePositives = 0.01 +) + +func FuzzBloom(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + f := fuzz.NewConsumer(data) + structuredData := FuzzData{} + err := f.GenerateStruct(&structuredData) + if err != nil { + return + } + defer func() { + if r := recover(); r != nil { + t.Log(string(debug.Stack())) + t.Fatalf("Failing input:\n %+v", structuredData) + } + }() + + // Limit input to max size. + structuredData.ElementCount %= maxElements + if structuredData.ElementCount == 0 { + return + } + + // Limit false positives. + structuredData.FalsePositives = math.Mod(structuredData.FalsePositives, maxFalsePositives) + if structuredData.FalsePositives < minFalsePositives || math.IsNaN(structuredData.FalsePositives) || math.IsInf(structuredData.FalsePositives, 0) { + return + } + + filter := bloom.NewWithEstimates(uint(structuredData.ElementCount), structuredData.FalsePositives) + for _, to_add := range structuredData.Add { + _ = filter.Add(to_add) + } + for _, to_add := range structuredData.AddString { + _ = filter.AddString(to_add) + } + for _, to_test := range structuredData.Add { + if !filter.Test(to_test) { + t.Logf("Failed with structured input: %v", structuredData) + t.Errorf("%v was added but was not reported as present in the set.", to_test) + } + } + for _, to_test := range structuredData.AddString { + if !filter.TestString(to_test) { + t.Errorf("String '%s' was added but was not reported as present in the set.", to_test) + } + } + + for _, to_test := range structuredData.NotAdded { + _ = filter.Test(to_test) + } + _ = filter.K() + _ = filter.ApproximatedSize() + _ = filter.Cap() + _ = filter.TestLocations(structuredData.TestLocations) + RoundTripGobEncodeDecode(t, filter) + }) +} \ No newline at end of file diff --git a/go.mod b/go.mod index 91b237d..5450802 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/bits-and-blooms/bloom/v3 go 1.14 require ( + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 // indirect github.com/bits-and-blooms/bitset v1.3.1 github.com/twmb/murmur3 v1.1.6 ) diff --git a/go.sum b/go.sum index 0b2d3fe..c63ae10 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,19 @@ +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1 h1:EKPd1INOIyr5hWOWhvpmQpY6tKjeG0hT1s3AMC/9fic= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20230106234847-43070de90fa1/go.mod h1:VzwV+t+dZ9j/H867F1M2ziD+yLHtB46oM35FxxMJ4d0= github.com/bits-and-blooms/bitset v1.3.1 h1:y+qrlmq3XsWi+xZqSaueaE8ry8Y127iMxlMfqcK8p0g= github.com/bits-and-blooms/bitset v1.3.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 5634eacfb5b03850cca2b146dd443247b012d747 Mon Sep 17 00:00:00 2001 From: Nathaniel Brough Date: Sun, 19 Mar 2023 10:52:52 -0700 Subject: [PATCH 2/2] feat: Adds OSS-fuzz build script --- fuzz/build.sh | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 fuzz/build.sh diff --git a/fuzz/build.sh b/fuzz/build.sh new file mode 100644 index 0000000..2540435 --- /dev/null +++ b/fuzz/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# OSS-fuzz build script + +compile_native_go_fuzzer $SRC/bloom/fuzz FuzzBloom fuzz_bloom