Beispiel #1
0
// Low level stress/fuzz test: serialize/deserialize a variety of
// different kinds of data in different combinations
func checkFuzz(fuzzFields, fuzzObjects int, fail func(string, ...interface{})) {

	// Values we're testing against: chosen to ensure no bits get chopped
	// off anywhere, and also be different from eachother.
	boolVal := true
	int8Val := int8(-127) // 0x81
	uint8Val := uint8(0xFF)
	int16Val := int16(-32222) // 0x8222
	uint16Val := uint16(0xFEEE)
	int32Val := int32(overflowingInt32Val)
	uint32Val := uint32(0xFDDDDDDD)
	int64Val := int64(overflowingInt64Val)
	uint64Val := uint64(0xFCCCCCCCCCCCCCCC)
	float32Val := float32(3.14159)
	float64Val := float64(3.14159265359)

	testValuesMax := 11 // hardcoded to the number of scalar types

	builder := flatbuffers.NewBuilder(0)
	l := NewLCG()

	objects := make([]flatbuffers.UOffsetT, fuzzObjects)

	// Generate fuzzObjects random objects each consisting of
	// fuzzFields fields, each of a random type.
	for i := 0; i < fuzzObjects; i++ {
		builder.StartObject(fuzzFields)

		for f := 0; f < fuzzFields; f++ {
			choice := l.Next() % uint32(testValuesMax)
			switch choice {
			case 0:
				builder.PrependBoolSlot(int(f), boolVal, false)
			case 1:
				builder.PrependInt8Slot(int(f), int8Val, 0)
			case 2:
				builder.PrependUint8Slot(int(f), uint8Val, 0)
			case 3:
				builder.PrependInt16Slot(int(f), int16Val, 0)
			case 4:
				builder.PrependUint16Slot(int(f), uint16Val, 0)
			case 5:
				builder.PrependInt32Slot(int(f), int32Val, 0)
			case 6:
				builder.PrependUint32Slot(int(f), uint32Val, 0)
			case 7:
				builder.PrependInt64Slot(int(f), int64Val, 0)
			case 8:
				builder.PrependUint64Slot(int(f), uint64Val, 0)
			case 9:
				builder.PrependFloat32Slot(int(f), float32Val, 0)
			case 10:
				builder.PrependFloat64Slot(int(f), float64Val, 0)
			}
		}

		off := builder.EndObject()

		// store the offset from the end of the builder buffer,
		// since it will keep growing:
		objects[i] = off
	}

	// Do some bookkeeping to generate stats on fuzzes:
	stats := map[string]int{}
	check := func(desc string, want, got interface{}) {
		stats[desc]++
		if want != got {
			fail("%s want %v got %v", desc, want, got)
		}
	}

	l = NewLCG() // Reset.

	// Test that all objects we generated are readable and return the
	// expected values. We generate random objects in the same order
	// so this is deterministic.
	for i := 0; i < fuzzObjects; i++ {

		table := &flatbuffers.Table{
			Bytes: builder.Bytes,
			Pos:   flatbuffers.UOffsetT(len(builder.Bytes)) - objects[i],
		}

		for j := 0; j < fuzzFields; j++ {
			f := flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + j) * flatbuffers.SizeVOffsetT)
			choice := int(l.Next()) % testValuesMax

			switch choice {
			case 0:
				check("bool", boolVal, table.GetBoolSlot(f, false))
			case 1:
				check("int8", int8Val, table.GetInt8Slot(f, 0))
			case 2:
				check("uint8", uint8Val, table.GetUint8Slot(f, 0))
			case 3:
				check("int16", int16Val, table.GetInt16Slot(f, 0))
			case 4:
				check("uint16", uint16Val, table.GetUint16Slot(f, 0))
			case 5:
				check("int32", int32Val, table.GetInt32Slot(f, 0))
			case 6:
				check("uint32", uint32Val, table.GetUint32Slot(f, 0))
			case 7:
				check("int64", int64Val, table.GetInt64Slot(f, 0))
			case 8:
				check("uint64", uint64Val, table.GetUint64Slot(f, 0))
			case 9:
				check("float32", float32Val, table.GetFloat32Slot(f, 0))
			case 10:
				check("float64", float64Val, table.GetFloat64Slot(f, 0))
			}
		}
	}

	// If enough checks were made, verify that all scalar types were used:
	if fuzzFields*fuzzObjects >= testValuesMax {
		if len(stats) != testValuesMax {
			fail("fuzzing failed to test all scalar types")
		}
	}

	// Print some counts, if needed:
	if testing.Verbose() {
		if fuzzFields == 0 || fuzzObjects == 0 {
			fmt.Printf("fuzz\tfields: %d\tobjects: %d\t[none]\t%d\n",
				fuzzFields, fuzzObjects, 0)
		} else {
			keys := make([]string, 0, len(stats))
			for k := range stats {
				keys = append(keys, k)
			}
			sort.Strings(keys)
			for _, k := range keys {
				fmt.Printf("fuzz\tfields: %d\tobjects: %d\t%s\t%d\n",
					fuzzFields, fuzzObjects, k, stats[k])
			}
		}
	}

	return
}
Beispiel #2
0
// CheckMutateMethods checks all mutate methods one by one
func CheckMutateMethods(fail func(string, ...interface{})) {
	b := flatbuffers.NewBuilder(0)
	b.StartObject(15)
	b.PrependBoolSlot(0, true, false)
	b.PrependByteSlot(1, 1, 0)
	b.PrependUint8Slot(2, 2, 0)
	b.PrependUint16Slot(3, 3, 0)
	b.PrependUint32Slot(4, 4, 0)
	b.PrependUint64Slot(5, 5, 0)
	b.PrependInt8Slot(6, 6, 0)
	b.PrependInt16Slot(7, 7, 0)
	b.PrependInt32Slot(8, 8, 0)
	b.PrependInt64Slot(9, 9, 0)
	b.PrependFloat32Slot(10, 10, 0)
	b.PrependFloat64Slot(11, 11, 0)

	b.PrependUOffsetTSlot(12, 12, 0)
	uoVal := b.Offset() - 12

	b.PrependVOffsetT(13)
	b.Slot(13)

	b.PrependSOffsetT(14)
	b.Slot(14)
	soVal := flatbuffers.SOffsetT(b.Offset() - 14)

	offset := b.EndObject()

	t := &flatbuffers.Table{
		Bytes: b.Bytes,
		Pos:   flatbuffers.UOffsetT(len(b.Bytes)) - offset,
	}

	calcVOffsetT := func(slot int) (vtableOffset flatbuffers.VOffsetT) {
		return flatbuffers.VOffsetT((flatbuffers.VtableMetadataFields + slot) * flatbuffers.SizeVOffsetT)
	}
	calcUOffsetT := func(vtableOffset flatbuffers.VOffsetT) (valueOffset flatbuffers.UOffsetT) {
		return t.Pos + flatbuffers.UOffsetT(t.Offset(vtableOffset))
	}

	type testcase struct {
		field  string
		testfn func() bool
	}

	testForOriginalValues := []testcase{
		testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == true }},
		testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 1 }},
		testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 2) == 2 }},
		testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 3) == 3 }},
		testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 4) == 4 }},
		testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 5) == 5 }},
		testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 6) == 6 }},
		testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 7) == 7 }},
		testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 8) == 8 }},
		testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 9) == 9 }},
		testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 10) == 10 }},
		testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 11) == 11 }},
		testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == uoVal }},
		testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 13 }},
		testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == soVal }},
	}

	testMutability := []testcase{
		testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(0), false) }},
		testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(1), 2) }},
		testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(2), 4) }},
		testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(3), 6) }},
		testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(4), 8) }},
		testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(5), 10) }},
		testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(6), 12) }},
		testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(7), 14) }},
		testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(8), 16) }},
		testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(9), 18) }},
		testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(10), 20) }},
		testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(11), 22) }},
		testcase{"UOffsetTSlot", func() bool { return t.MutateUOffsetT(calcUOffsetT(calcVOffsetT(12)), 24) }},
		testcase{"VOffsetTSlot", func() bool { return t.MutateVOffsetT(calcUOffsetT(calcVOffsetT(13)), 26) }},
		testcase{"SOffsetTSlot", func() bool { return t.MutateSOffsetT(calcUOffsetT(calcVOffsetT(14)), 28) }},
	}

	testMutabilityWithoutSlot := []testcase{
		testcase{"BoolSlot", func() bool { return t.MutateBoolSlot(calcVOffsetT(16), false) }},
		testcase{"ByteSlot", func() bool { return t.MutateByteSlot(calcVOffsetT(16), 2) }},
		testcase{"Uint8Slot", func() bool { return t.MutateUint8Slot(calcVOffsetT(16), 2) }},
		testcase{"Uint16Slot", func() bool { return t.MutateUint16Slot(calcVOffsetT(16), 2) }},
		testcase{"Uint32Slot", func() bool { return t.MutateUint32Slot(calcVOffsetT(16), 2) }},
		testcase{"Uint64Slot", func() bool { return t.MutateUint64Slot(calcVOffsetT(16), 2) }},
		testcase{"Int8Slot", func() bool { return t.MutateInt8Slot(calcVOffsetT(16), 2) }},
		testcase{"Int16Slot", func() bool { return t.MutateInt16Slot(calcVOffsetT(16), 2) }},
		testcase{"Int32Slot", func() bool { return t.MutateInt32Slot(calcVOffsetT(16), 2) }},
		testcase{"Int64Slot", func() bool { return t.MutateInt64Slot(calcVOffsetT(16), 2) }},
		testcase{"Float32Slot", func() bool { return t.MutateFloat32Slot(calcVOffsetT(16), 2) }},
		testcase{"Float64Slot", func() bool { return t.MutateFloat64Slot(calcVOffsetT(16), 2) }},
	}

	testForMutatedValues := []testcase{
		testcase{"BoolSlot", func() bool { return t.GetBoolSlot(calcVOffsetT(0), true) == false }},
		testcase{"ByteSlot", func() bool { return t.GetByteSlot(calcVOffsetT(1), 1) == 2 }},
		testcase{"Uint8Slot", func() bool { return t.GetUint8Slot(calcVOffsetT(2), 1) == 4 }},
		testcase{"Uint16Slot", func() bool { return t.GetUint16Slot(calcVOffsetT(3), 1) == 6 }},
		testcase{"Uint32Slot", func() bool { return t.GetUint32Slot(calcVOffsetT(4), 1) == 8 }},
		testcase{"Uint64Slot", func() bool { return t.GetUint64Slot(calcVOffsetT(5), 1) == 10 }},
		testcase{"Int8Slot", func() bool { return t.GetInt8Slot(calcVOffsetT(6), 1) == 12 }},
		testcase{"Int16Slot", func() bool { return t.GetInt16Slot(calcVOffsetT(7), 1) == 14 }},
		testcase{"Int32Slot", func() bool { return t.GetInt32Slot(calcVOffsetT(8), 1) == 16 }},
		testcase{"Int64Slot", func() bool { return t.GetInt64Slot(calcVOffsetT(9), 1) == 18 }},
		testcase{"Float32Slot", func() bool { return t.GetFloat32Slot(calcVOffsetT(10), 1) == 20 }},
		testcase{"Float64Slot", func() bool { return t.GetFloat64Slot(calcVOffsetT(11), 1) == 22 }},
		testcase{"UOffsetTSlot", func() bool { return t.GetUOffsetT(calcUOffsetT(calcVOffsetT(12))) == 24 }},
		testcase{"VOffsetTSlot", func() bool { return t.GetVOffsetT(calcUOffsetT(calcVOffsetT(13))) == 26 }},
		testcase{"SOffsetTSlot", func() bool { return t.GetSOffsetT(calcUOffsetT(calcVOffsetT(14))) == 28 }},
	}

	// make sure original values are okay
	for _, t := range testForOriginalValues {
		if !t.testfn() {
			fail(t.field + "' field doesn't have the expected original value")
		}
	}

	// try to mutate fields and check mutability
	for _, t := range testMutability {
		if !t.testfn() {
			fail(FailString(t.field+"' field failed mutability test", "passed", "failed"))
		}
	}

	// try to mutate fields and check mutability
	// these have wrong slots so should fail
	for _, t := range testMutabilityWithoutSlot {
		if t.testfn() {
			fail(FailString(t.field+"' field failed no slot mutability test", "failed", "passed"))
		}
	}

	// test whether values have changed
	for _, t := range testForMutatedValues {
		if !t.testfn() {
			fail(t.field + "' field doesn't have the expected mutated value")
		}
	}
}