Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Fuzzy generics

Fuzzy generics

Alexey Palazhchenko

February 05, 2022
Tweet

More Decks by Alexey Palazhchenko

Other Decks in Programming

Transcript

  1. Generics • Generics do not work there; let's go back

    to interfaces • Let me extract a small example for a talk
  2. Generics • Generics do not work there; let's go back

    to interfaces • Let me extract a small example for a talk • Hm, that's not that bad
  3. BSON Document • Ordered map • Keys – string, values

    – any BSON value, including other documents
  4. BSON Document • Ordered map • Keys – string, values

    – any BSON value, including other documents • The central data structure in FerretDB
  5. Interfaces type BSONType interface { bsontype() // sealed } type

    Int int func (Int) bsontype() {} type String string func (String) bsontype() {}
  6. Interfaces type BSONType interface { bsontype() // sealed } type

    Int int func (Int) bsontype() {} type String string func (String) bsontype() {} type Document struct { m map[string]BSONType keys []string } func (*Document) bsontype() {}
  7. Interfaces func (d *Document) Set(key String, value BSONType) { if

    _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
  8. Generics type BSONType interface { int | string | *Document

    } type Document struct { m map[string]any keys []string }
  9. Generics func (d *Document) Set[T BSONType](key string, value T) {

    if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
  10. Generics func (d *Document) Set[T BSONType](key string, value T) {

    if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value } syntax error: method must have no type parameters
  11. Generics func DocumentSet[T BSONType](d *Document, key string, value T) {

    if _, ok := d.m[key]; !ok { d.keys = append(d.keys, key) } d.m[key] = value }
  12. Interfaces func MakeDocument(pairs ...BSONType) (*Document, error) { l := len(pairs)

    if l%2 != 0 { return nil, fmt.Errorf("%d arguments", l)
  13. Generics func MakeDocument[T BSONType](key string, value T) *Document func MakeDocument2[T1,

    T2 BSONType](key1 string, value1 T1, key2 string, value2 T2) *Document
  14. Generics func MakeDocument[T BSONType](key string, value T) *Document func MakeDocument2[T1,

    T2 BSONType](key1 string, value1 T1, key2 string, value2 T2) *Document func MakeDocument3[T1, T2, T3 BSONType](key1 string, value1 T1, key2 string, value2 T2, key3 string, value3 T3) *Document
  15. Interfaces func (d *Document) Get(key String) BSONType { return d.m[key]

    } assert.Equal(t, Int(42), d.Get("foo")) assert.Equal(t, nil, d.Get("baz"))
  16. Generics func DocumentGet[T BSONType](d *Document, key string) T { v,

    _ := d.m[key].(T) return v } assert.Equal(t, 42, DocumentGet[int](d, "foo")) assert.Equal(t, "", DocumentGet[string](d, "foo"))
  17. Fuzzing • testing/quick on steroids • MongoDB binary protocol parsing

    packages • FerretDB had fuzzing tests even before unit tests
  18. Table-driven tests type testCase struct { name string b []byte

    v bsontype err error } • Unmarshal b to (v2, err2) • compare with v or err • Marshal v2 to b2 • compare with b
  19. Table-driven tests func TestDocument(t *testing.T) { for _, tc :=

    range testCases { tc := tc t.Run(tc.name, func(t *testing.T) {
  20. Fuzzing func FuzzDocument(f *testing.F) { for _, tc := range

    testCases { f.Add(tc.b) } f.Fuzz(func(t *testing.T, b []byte) {
  21. When b2 != b • b might be larger than

    needed • The unread portion of b should be removed
  22. When b2 != b • b might be larger than

    needed • The unread portion of b should be removed • Some bytes might be insigni fi cant
  23. When b2 != b • b might be larger than

    needed • The unread portion of b should be removed • Some bytes might be insigni fi cant • Use canonization (json.Compact, etc)
  24. Fuzzing issues • No subtests (testing.F.Run) • Unnamed seed values

    • Hanging detection is unreliable with unset GOMAXPROCS
  25. Fuzzing • Found a few bugs in `go test -fuzz`

    • Found many many bugs in FerretDB
  26. Fuzzing • Found a few bugs in `go test -fuzz`

    • Found many many bugs in FerretDB • De fi nitely use it for parsing
  27. Links • https://github.com/AlekSi/ generics-vs-interfaces • https://github.com/akutz/
 go-generics-the-hard-way • https://go.dev/doc/tutorial/ •

    https://go.dev/doc/fuzz/ • https://www.ferretdb.io • https://github.com/FerretDB ⭐ • https://github.com/AlekSi • @paaleksey