--------------------------------------------------------------------------- Property: all fuzz harnesses from fuzz.go never panic on arbitrary bytes --------------------------------------------------------------------------- This is the OSS-Fuzz invariant — the harness must accept any byte sequence
(t *testing.T)
| 823 | // reqproof:proptest FuzzParseString, FuzzEachKey, FuzzDelete, FuzzSet, FuzzObjectEach, FuzzParseFloat, FuzzParseInt, FuzzParseBool, FuzzTokenStart, FuzzGetString, FuzzGetFloat, FuzzGetInt, FuzzGetBoolean, FuzzGetUnsafeString |
| 824 | // Verifies: SYS-REQ-035 [property] |
| 825 | func TestPropertyFuzzHarnessesNoCrash(t *testing.T) { |
| 826 | r := newRNG(jsonSeed + 14) |
| 827 | const iterations = 5000 |
| 828 | // Each harness is a function that takes []byte and returns int (0/1). |
| 829 | // We require: (1) no panic, (2) deterministic return for identical input. |
| 830 | harnesses := []struct { |
| 831 | name string |
| 832 | fn func([]byte) int |
| 833 | }{ |
| 834 | {"FuzzParseString", FuzzParseString}, |
| 835 | {"FuzzEachKey", FuzzEachKey}, |
| 836 | {"FuzzDelete", FuzzDelete}, |
| 837 | {"FuzzSet", FuzzSet}, |
| 838 | {"FuzzObjectEach", FuzzObjectEach}, |
| 839 | {"FuzzParseFloat", FuzzParseFloat}, |
| 840 | {"FuzzParseInt", FuzzParseInt}, |
| 841 | {"FuzzParseBool", FuzzParseBool}, |
| 842 | {"FuzzTokenStart", FuzzTokenStart}, |
| 843 | {"FuzzGetString", FuzzGetString}, |
| 844 | {"FuzzGetFloat", FuzzGetFloat}, |
| 845 | {"FuzzGetInt", FuzzGetInt}, |
| 846 | {"FuzzGetBoolean", FuzzGetBoolean}, |
| 847 | {"FuzzGetUnsafeString", FuzzGetUnsafeString}, |
| 848 | } |
| 849 | // Mix of valid JSON and arbitrary bytes. |
| 850 | inputs := make([][]byte, 0, iterations) |
| 851 | for i := 0; i < iterations/2; i++ { |
| 852 | inputs = append(inputs, randomJSONBytes(r, 2)) |
| 853 | } |
| 854 | for i := 0; i < iterations/2; i++ { |
| 855 | inputs = append(inputs, randomBytes(r, 128)) |
| 856 | } |
| 857 | // Curated edge cases. |
| 858 | inputs = append(inputs, nil, []byte{}, []byte("\x00"), []byte("\xff"), |
| 859 | []byte("{"), []byte("}"), []byte("["), []byte("]"), |
| 860 | []byte(`{"test":`), []byte(`{{{`), |
| 861 | bytes.Repeat([]byte{0x80}, 256), |
| 862 | ) |
| 863 | |
| 864 | for _, h := range harnesses { |
| 865 | for i, raw := range inputs { |
| 866 | if !recoverNoPanic(func() { _ = h.fn(raw) }) { |
| 867 | t.Fatalf("%s panicked on input #%d %q", h.name, i, raw) |
| 868 | } |
| 869 | a := safeCall(h.fn, raw) |
| 870 | b := safeCall(h.fn, raw) |
| 871 | if a != b { |
| 872 | t.Fatalf("%s non-deterministic on input #%d %q: %d vs %d", h.name, i, raw, a, b) |
| 873 | } |
| 874 | } |
| 875 | } |
| 876 | } |
| 877 | |
| 878 | // safeCall invokes a fuzz harness, recovering from any panic and returning |
| 879 | // the harness result or -1 on panic. |
nothing calls this directly
no test coverage detected