-
Notifications
You must be signed in to change notification settings - Fork 902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GODRIVER-3451 Add fuzz test for BSON MarshalValue/UnmarshalValue. #1993
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Copyright (C) MongoDB, Inc. 2025-present. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); you may | ||
// not use this file except in compliance with the License. You may obtain | ||
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
package bson | ||
|
||
import ( | ||
"math" | ||
"strings" | ||
"testing" | ||
) | ||
|
||
func FuzzDecodeValue(f *testing.F) { | ||
// Seed the fuzz corpus with all BSON values from the MarshalValue test | ||
// cases. | ||
for _, tc := range marshalValueTestCases { | ||
f.Add(byte(tc.bsontype), tc.bytes) | ||
} | ||
|
||
// Also seed the fuzz corpus with special values that we want to test. | ||
values := []any{ | ||
// int32, including max and min values. | ||
int32(0), math.MaxInt32, math.MinInt32, | ||
// int64, including max and min values. | ||
int64(0), math.MaxInt64, math.MinInt64, | ||
// string, including empty and large string. | ||
"", strings.Repeat("z", 10_000), | ||
// map | ||
map[string]any{"nested": []any{1, "two", map[string]any{"three": 3}}}, | ||
// array | ||
[]any{1, 2, 3, "four"}, | ||
} | ||
|
||
for _, v := range values { | ||
typ, b, err := MarshalValue(v) | ||
if err != nil { | ||
f.Fatal(err) | ||
} | ||
f.Add(byte(typ), b) | ||
} | ||
|
||
f.Fuzz(func(t *testing.T, bsonType byte, data []byte) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AFAIK we can run these tests in parallel. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure what you mean. I believe
Is there another way to run fuzz tests or test cases in parallel? |
||
var v any | ||
if err := UnmarshalValue(Type(bsonType), data, &v); err != nil { | ||
return | ||
} | ||
|
||
// There is no value encoder for Go "nil" (nil values handled | ||
// differently by each type encoder), so skip anything that unmarshals | ||
// to "nil". It's not clear if MarshalValue should support "nil", but | ||
// for now we skip it. | ||
if v == nil { | ||
t.Logf("data unmarshaled to nil: %v", data) | ||
return | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It might be worth logging such cases. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Test logs only seems to be printed when the fuzz test encounters another error, but I can add the log statement in case it's helpful. |
||
} | ||
|
||
typ, encoded, err := MarshalValue(v) | ||
if err != nil { | ||
t.Fatalf("failed to marshal: %v", err) | ||
} | ||
|
||
var v2 any | ||
if err := UnmarshalValue(typ, encoded, &v2); err != nil { | ||
t.Fatalf("failed to unmarshal: %v", err) | ||
} | ||
}) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we extend this to include a nested structure and a slice?