diff options
Diffstat (limited to 'tools/go_marshal/test')
-rw-r--r-- | tools/go_marshal/test/BUILD | 52 | ||||
-rw-r--r-- | tools/go_marshal/test/benchmark_test.go | 220 | ||||
-rw-r--r-- | tools/go_marshal/test/dynamic.go | 83 | ||||
-rw-r--r-- | tools/go_marshal/test/escape/BUILD | 14 | ||||
-rw-r--r-- | tools/go_marshal/test/escape/escape.go | 100 | ||||
-rw-r--r-- | tools/go_marshal/test/external/BUILD | 11 | ||||
-rw-r--r-- | tools/go_marshal/test/external/external.go | 31 | ||||
-rw-r--r-- | tools/go_marshal/test/marshal_test.go | 554 | ||||
-rw-r--r-- | tools/go_marshal/test/test.go | 200 |
9 files changed, 0 insertions, 1265 deletions
diff --git a/tools/go_marshal/test/BUILD b/tools/go_marshal/test/BUILD deleted file mode 100644 index d315be060..000000000 --- a/tools/go_marshal/test/BUILD +++ /dev/null @@ -1,52 +0,0 @@ -load("//tools:defs.bzl", "go_library", "go_test") - -licenses(["notice"]) - -package_group( - name = "gomarshal_test", - packages = [ - "//tools/go_marshal/test/...", - ], -) - -go_test( - name = "benchmark_test", - srcs = ["benchmark_test.go"], - deps = [ - ":test", - "//pkg/binary", - "//pkg/hostarch", - "//tools/go_marshal/analysis", - ], -) - -go_library( - name = "test", - testonly = 1, - srcs = [ - "dynamic.go", - "test.go", - ], - marshal = True, - visibility = ["//tools/go_marshal/test:__subpackages__"], - deps = [ - "//pkg/marshal/primitive", - "//tools/go_marshal/test/external", - ], -) - -go_test( - name = "marshal_test", - size = "small", - srcs = ["marshal_test.go"], - deps = [ - ":test", - "//pkg/errors/linuxerr", - "//pkg/hostarch", - "//pkg/marshal", - "//pkg/marshal/primitive", - "//pkg/usermem", - "//tools/go_marshal/analysis", - "@com_github_google_go_cmp//cmp:go_default_library", - ], -) diff --git a/tools/go_marshal/test/benchmark_test.go b/tools/go_marshal/test/benchmark_test.go deleted file mode 100644 index 16f478ff7..000000000 --- a/tools/go_marshal/test/benchmark_test.go +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package benchmark_test - -import ( - "bytes" - encbin "encoding/binary" - "fmt" - "reflect" - "testing" - - "gvisor.dev/gvisor/pkg/binary" - "gvisor.dev/gvisor/pkg/hostarch" - "gvisor.dev/gvisor/tools/go_marshal/analysis" - "gvisor.dev/gvisor/tools/go_marshal/test" -) - -// Marshalling using the standard encoding/binary package. -func BenchmarkEncodingBinary(b *testing.B) { - var s1, s2 test.Stat - analysis.RandomizeValue(&s1) - - size := encbin.Size(&s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := bytes.NewBuffer(make([]byte, size)) - buf.Reset() - if err := encbin.Write(buf, hostarch.ByteOrder, &s1); err != nil { - b.Error("Write:", err) - } - if err := encbin.Read(buf, hostarch.ByteOrder, &s2); err != nil { - b.Error("Read:", err) - } - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -// Marshalling using the sentry's binary.Marshal. -func BenchmarkBinary(b *testing.B) { - var s1, s2 test.Stat - analysis.RandomizeValue(&s1) - - size := binary.Size(s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, 0, size) - buf = binary.Marshal(buf, hostarch.ByteOrder, &s1) - binary.Unmarshal(buf, hostarch.ByteOrder, &s2) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -// Marshalling field-by-field with manually-written code. -func BenchmarkMarshalManual(b *testing.B) { - var s1, s2 test.Stat - analysis.RandomizeValue(&s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, 0, s1.SizeBytes()) - - // Marshal - buf = binary.AppendUint64(buf, hostarch.ByteOrder, s1.Dev) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, s1.Ino) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, s1.Nlink) - buf = binary.AppendUint32(buf, hostarch.ByteOrder, s1.Mode) - buf = binary.AppendUint32(buf, hostarch.ByteOrder, s1.UID) - buf = binary.AppendUint32(buf, hostarch.ByteOrder, s1.GID) - buf = binary.AppendUint32(buf, hostarch.ByteOrder, 0) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, s1.Rdev) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.Size)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.Blksize)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.Blocks)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.ATime.Sec)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.ATime.Nsec)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.MTime.Sec)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.MTime.Nsec)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.CTime.Sec)) - buf = binary.AppendUint64(buf, hostarch.ByteOrder, uint64(s1.CTime.Nsec)) - - // Unmarshal - s2.Dev = hostarch.ByteOrder.Uint64(buf[0:8]) - s2.Ino = hostarch.ByteOrder.Uint64(buf[8:16]) - s2.Nlink = hostarch.ByteOrder.Uint64(buf[16:24]) - s2.Mode = hostarch.ByteOrder.Uint32(buf[24:28]) - s2.UID = hostarch.ByteOrder.Uint32(buf[28:32]) - s2.GID = hostarch.ByteOrder.Uint32(buf[32:36]) - // Padding: buf[36:40] - s2.Rdev = hostarch.ByteOrder.Uint64(buf[40:48]) - s2.Size = int64(hostarch.ByteOrder.Uint64(buf[48:56])) - s2.Blksize = int64(hostarch.ByteOrder.Uint64(buf[56:64])) - s2.Blocks = int64(hostarch.ByteOrder.Uint64(buf[64:72])) - s2.ATime.Sec = int64(hostarch.ByteOrder.Uint64(buf[72:80])) - s2.ATime.Nsec = int64(hostarch.ByteOrder.Uint64(buf[80:88])) - s2.MTime.Sec = int64(hostarch.ByteOrder.Uint64(buf[88:96])) - s2.MTime.Nsec = int64(hostarch.ByteOrder.Uint64(buf[96:104])) - s2.CTime.Sec = int64(hostarch.ByteOrder.Uint64(buf[104:112])) - s2.CTime.Nsec = int64(hostarch.ByteOrder.Uint64(buf[112:120])) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -// Marshalling with the go_marshal safe API. -func BenchmarkGoMarshalSafe(b *testing.B) { - var s1, s2 test.Stat - analysis.RandomizeValue(&s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, s1.SizeBytes()) - s1.MarshalBytes(buf) - s2.UnmarshalBytes(buf) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -// Marshalling with the go_marshal unsafe API. -func BenchmarkGoMarshalUnsafe(b *testing.B) { - var s1, s2 test.Stat - analysis.RandomizeValue(&s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, s1.SizeBytes()) - s1.MarshalUnsafe(buf) - s2.UnmarshalUnsafe(buf) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -func BenchmarkBinarySlice(b *testing.B) { - var s1, s2 [64]test.Stat - analysis.RandomizeValue(&s1) - - size := binary.Size(s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, 0, size) - buf = binary.Marshal(buf, hostarch.ByteOrder, &s1) - binary.Unmarshal(buf, hostarch.ByteOrder, &s2) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} - -func BenchmarkGoMarshalUnsafeSlice(b *testing.B) { - var s1, s2 [64]test.Stat - analysis.RandomizeValue(&s1) - - b.ResetTimer() - - for n := 0; n < b.N; n++ { - buf := make([]byte, (*test.Stat)(nil).SizeBytes()*len(s1)) - test.MarshalUnsafeStatSlice(s1[:], buf) - test.UnmarshalUnsafeStatSlice(s2[:], buf) - } - - b.StopTimer() - - // Sanity check, make sure the values were preserved. - if !reflect.DeepEqual(s1, s2) { - panic(fmt.Sprintf("Data corruption across marshal/unmarshal cycle:\nBefore: %+v\nAfter: %+v\n", s1, s2)) - } -} diff --git a/tools/go_marshal/test/dynamic.go b/tools/go_marshal/test/dynamic.go deleted file mode 100644 index 46b446392..000000000 --- a/tools/go_marshal/test/dynamic.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2021 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package test - -import "gvisor.dev/gvisor/pkg/marshal/primitive" - -// Type12Dynamic is a dynamically sized struct which depends on the -// autogenerator to generate some Marshallable methods for it. -// -// +marshal dynamic -type Type12Dynamic struct { - X primitive.Int64 - Y []primitive.Int64 -} - -// SizeBytes implements marshal.Marshallable.SizeBytes. -func (t *Type12Dynamic) SizeBytes() int { - return (len(t.Y) * 8) + t.X.SizeBytes() -} - -// MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (t *Type12Dynamic) MarshalBytes(dst []byte) []byte { - dst = t.X.MarshalBytes(dst) - for _, x := range t.Y { - dst = x.MarshalBytes(dst) - } - return dst -} - -// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (t *Type12Dynamic) UnmarshalBytes(src []byte) []byte { - src = t.X.UnmarshalBytes(src) - if t.Y != nil { - t.Y = t.Y[:0] - } - for len(src) > 0 { - var x primitive.Int64 - src = x.UnmarshalBytes(src) - t.Y = append(t.Y, x) - } - return src -} - -// Type13Dynamic is a dynamically sized struct which depends on the -// autogenerator to generate some Marshallable methods for it. -// -// It represents a string in memory which is preceded by a uint32 indicating -// the string size. -// -// +marshal dynamic -type Type13Dynamic string - -// SizeBytes implements marshal.Marshallable.SizeBytes. -func (t *Type13Dynamic) SizeBytes() int { - return (*primitive.Uint32)(nil).SizeBytes() + len(*t) -} - -// MarshalBytes implements marshal.Marshallable.MarshalBytes. -func (t *Type13Dynamic) MarshalBytes(dst []byte) []byte { - strLen := primitive.Uint32(len(*t)) - dst = strLen.MarshalBytes(dst) - return dst[copy(dst[:strLen], *t):] -} - -// UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. -func (t *Type13Dynamic) UnmarshalBytes(src []byte) []byte { - var strLen primitive.Uint32 - src = strLen.UnmarshalBytes(src) - *t = Type13Dynamic(src[:strLen]) - return src[strLen:] -} diff --git a/tools/go_marshal/test/escape/BUILD b/tools/go_marshal/test/escape/BUILD deleted file mode 100644 index 62e0b4665..000000000 --- a/tools/go_marshal/test/escape/BUILD +++ /dev/null @@ -1,14 +0,0 @@ -load("//tools:defs.bzl", "go_library") - -licenses(["notice"]) - -go_library( - name = "escape", - testonly = 1, - srcs = ["escape.go"], - deps = [ - "//pkg/hostarch", - "//pkg/marshal", - "//tools/go_marshal/test", - ], -) diff --git a/tools/go_marshal/test/escape/escape.go b/tools/go_marshal/test/escape/escape.go deleted file mode 100644 index 1ac606862..000000000 --- a/tools/go_marshal/test/escape/escape.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package escape contains test cases for escape analysis. -package escape - -import ( - "gvisor.dev/gvisor/pkg/hostarch" - "gvisor.dev/gvisor/pkg/marshal" - "gvisor.dev/gvisor/tools/go_marshal/test" -) - -// dummyCopyContext implements marshal.CopyContext. -type dummyCopyContext struct { -} - -func (*dummyCopyContext) CopyScratchBuffer(size int) []byte { - return make([]byte, size) -} - -func (*dummyCopyContext) CopyOutBytes(addr hostarch.Addr, b []byte) (int, error) { - return len(b), nil -} - -func (*dummyCopyContext) CopyInBytes(addr hostarch.Addr, b []byte) (int, error) { - return len(b), nil -} - -func (t *dummyCopyContext) MarshalBytes(addr hostarch.Addr, marshallable marshal.Marshallable) { - buf := t.CopyScratchBuffer(marshallable.SizeBytes()) - marshallable.MarshalBytes(buf) - t.CopyOutBytes(addr, buf) -} - -func (t *dummyCopyContext) MarshalUnsafe(addr hostarch.Addr, marshallable marshal.Marshallable) { - buf := t.CopyScratchBuffer(marshallable.SizeBytes()) - marshallable.MarshalUnsafe(buf) - t.CopyOutBytes(addr, buf) -} - -// +checkescape:all -//go:nosplit -func doCopyIn(t *dummyCopyContext) { - var stat test.Stat - stat.CopyIn(t, hostarch.Addr(0xf000ba12)) -} - -// +checkescape:all -//go:nosplit -func doCopyOut(t *dummyCopyContext) { - var stat test.Stat - stat.CopyOut(t, hostarch.Addr(0xf000ba12)) -} - -// +mustescape:builtin -// +mustescape:stack -//go:nosplit -func doMarshalBytesDirect(t *dummyCopyContext) { - var stat test.Stat - buf := t.CopyScratchBuffer(stat.SizeBytes()) - stat.MarshalBytes(buf) - t.CopyOutBytes(hostarch.Addr(0xf000ba12), buf) -} - -// +mustescape:builtin -// +mustescape:stack -//go:nosplit -func doMarshalUnsafeDirect(t *dummyCopyContext) { - var stat test.Stat - buf := t.CopyScratchBuffer(stat.SizeBytes()) - stat.MarshalUnsafe(buf) - t.CopyOutBytes(hostarch.Addr(0xf000ba12), buf) -} - -// +mustescape:local,heap -// +mustescape:stack -//go:nosplit -func doMarshalBytesViaMarshallable(t *dummyCopyContext) { - var stat test.Stat - t.MarshalBytes(hostarch.Addr(0xf000ba12), &stat) -} - -// +mustescape:local,heap -// +mustescape:stack -//go:nosplit -func doMarshalUnsafeViaMarshallable(t *dummyCopyContext) { - var stat test.Stat - t.MarshalUnsafe(hostarch.Addr(0xf000ba12), &stat) -} diff --git a/tools/go_marshal/test/external/BUILD b/tools/go_marshal/test/external/BUILD deleted file mode 100644 index 0cf6da603..000000000 --- a/tools/go_marshal/test/external/BUILD +++ /dev/null @@ -1,11 +0,0 @@ -load("//tools:defs.bzl", "go_library") - -licenses(["notice"]) - -go_library( - name = "external", - testonly = 1, - srcs = ["external.go"], - marshal = True, - visibility = ["//tools/go_marshal/test:gomarshal_test"], -) diff --git a/tools/go_marshal/test/external/external.go b/tools/go_marshal/test/external/external.go deleted file mode 100644 index 26fe8e0c8..000000000 --- a/tools/go_marshal/test/external/external.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package external defines types we can import for testing. -package external - -// External is a public Marshallable type for use in testing. -// -// +marshal -type External struct { - j int64 -} - -// NotPacked is an unaligned Marshallable type for use in testing. -// -// +marshal -type NotPacked struct { - a int32 - b byte `marshal:"unaligned"` -} diff --git a/tools/go_marshal/test/marshal_test.go b/tools/go_marshal/test/marshal_test.go deleted file mode 100644 index dec3e84fd..000000000 --- a/tools/go_marshal/test/marshal_test.go +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright 2020 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package marshal_test contains manual tests for the marshal interface. These -// are intended to test behaviour not covered by the automatically generated -// tests. -package marshal_test - -import ( - "bytes" - "encoding/binary" - "fmt" - "reflect" - "runtime" - "testing" - "unsafe" - - "github.com/google/go-cmp/cmp" - "gvisor.dev/gvisor/pkg/errors/linuxerr" - "gvisor.dev/gvisor/pkg/hostarch" - "gvisor.dev/gvisor/pkg/marshal" - "gvisor.dev/gvisor/pkg/marshal/primitive" - "gvisor.dev/gvisor/pkg/usermem" - "gvisor.dev/gvisor/tools/go_marshal/analysis" - "gvisor.dev/gvisor/tools/go_marshal/test" -) - -var simulatedErr error = linuxerr.EFAULT - -// mockCopyContext implements marshal.CopyContext. -type mockCopyContext struct { - taskMem usermem.BytesIO -} - -// populate fills the task memory with the contents of val. -func (t *mockCopyContext) populate(val interface{}) { - var buf bytes.Buffer - // Use binary.Write so we aren't testing go-marshal against its own - // potentially buggy implementation. - if err := binary.Write(&buf, hostarch.ByteOrder, val); err != nil { - panic(err) - } - t.taskMem.Bytes = buf.Bytes() -} - -func (t *mockCopyContext) setLimit(n int) { - if len(t.taskMem.Bytes) < n { - grown := make([]byte, n) - copy(grown, t.taskMem.Bytes) - t.taskMem.Bytes = grown - return - } - t.taskMem.Bytes = t.taskMem.Bytes[:n] -} - -// CopyScratchBuffer implements marshal.CopyContext.CopyScratchBuffer. -func (t *mockCopyContext) CopyScratchBuffer(size int) []byte { - return make([]byte, size) -} - -// CopyOutBytes implements marshal.CopyContext.CopyOutBytes. The implementation -// completely ignores the target address and stores a copy of b in its -// internally buffer, overriding any previous contents. -func (t *mockCopyContext) CopyOutBytes(_ hostarch.Addr, b []byte) (int, error) { - return t.taskMem.CopyOut(nil, 0, b, usermem.IOOpts{}) -} - -// CopyInBytes implements marshal.CopyContext.CopyInBytes. The implementation -// completely ignores the source address and always fills b from the begining of -// its internal buffer. -func (t *mockCopyContext) CopyInBytes(_ hostarch.Addr, b []byte) (int, error) { - return t.taskMem.CopyIn(nil, 0, b, usermem.IOOpts{}) -} - -// unsafeMemory returns the underlying memory for m. The returned slice is only -// valid for the lifetime for m. The garbage collector isn't aware that the -// returned slice is related to m, the caller must ensure m lives long enough. -func unsafeMemory(m marshal.Marshallable) []byte { - if !m.Packed() { - // We can't return a slice pointing to the underlying memory - // since the layout isn't packed. Allocate a temporary buffer - // and marshal instead. - var buf bytes.Buffer - if err := binary.Write(&buf, hostarch.ByteOrder, m); err != nil { - panic(err) - } - return buf.Bytes() - } - - // reflect.ValueOf(m) - // .Elem() // Unwrap interface to inner concrete object - // .Addr() // Pointer value to object - // .Pointer() // Actual address from the pointer value - ptr := reflect.ValueOf(m).Elem().Addr().Pointer() - - size := m.SizeBytes() - - var mem []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&mem)) - hdr.Data = ptr - hdr.Len = size - hdr.Cap = size - - return mem -} - -// unsafeMemorySlice returns the underlying memory for m. The returned slice is -// only valid for the lifetime for m. The garbage collector isn't aware that the -// returned slice is related to m, the caller must ensure m lives long enough. -// -// Precondition: m must be a slice. -func unsafeMemorySlice(m interface{}, elt marshal.Marshallable) []byte { - kind := reflect.TypeOf(m).Kind() - if kind != reflect.Slice { - panic("unsafeMemorySlice called on non-slice") - } - - if !elt.Packed() { - // We can't return a slice pointing to the underlying memory - // since the layout isn't packed. Allocate a temporary buffer - // and marshal instead. - var buf bytes.Buffer - if err := binary.Write(&buf, hostarch.ByteOrder, m); err != nil { - panic(err) - } - return buf.Bytes() - } - - v := reflect.ValueOf(m) - length := v.Len() * elt.SizeBytes() - - var mem []byte - hdr := (*reflect.SliceHeader)(unsafe.Pointer(&mem)) - hdr.Data = v.Pointer() // This is a pointer to the first elem for slices. - hdr.Len = length - hdr.Cap = length - - return mem -} - -func isZeroes(buf []byte) bool { - for _, b := range buf { - if b != 0 { - return false - } - } - return true -} - -// compareMemory compares the first n bytes of two chuncks of memory represented -// by expected and actual. -func compareMemory(t *testing.T, expected, actual []byte, n int) { - t.Logf("Expected (%d): %v (%d) + (%d) %v\n", len(expected), expected[:n], n, len(expected)-n, expected[n:]) - t.Logf("Actual (%d): %v (%d) + (%d) %v\n", len(actual), actual[:n], n, len(actual)-n, actual[n:]) - - if diff := cmp.Diff(expected[:n], actual[:n]); diff != "" { - t.Errorf("Memory buffers don't match:\n--- expected only\n+++ actual only\n%v", diff) - } -} - -// limitedCopyIn populates task memory with src, then unmarshals task memory to -// dst. The task signals an error at limit bytes during copy-in, which should -// result in a truncated unmarshalling. -func limitedCopyIn(t *testing.T, src, dst marshal.Marshallable, limit int) { - var cc mockCopyContext - cc.populate(src) - cc.setLimit(limit) - - n, err := dst.CopyIn(&cc, hostarch.Addr(0)) - if n != limit { - t.Errorf("CopyIn copied unexpected number of bytes, expected %d, got %d", limit, n) - } - if err != simulatedErr { - t.Errorf("CopyIn returned unexpected error, expected %v, got %v", simulatedErr, err) - } - - expectedMem := unsafeMemory(src) - defer runtime.KeepAlive(src) - actualMem := unsafeMemory(dst) - defer runtime.KeepAlive(dst) - - compareMemory(t, expectedMem, actualMem, n) - - // The last n bytes should be zero for actual, since actual was - // zero-initialized, and CopyIn shouldn't have touched those bytes. However - // we can only guarantee we didn't touch anything in the last n bytes if the - // layout is packed. - if dst.Packed() && !isZeroes(actualMem[n:]) { - t.Errorf("Expected the last %d bytes of copied in object to be zeroes, got %v\n", dst.SizeBytes()-n, actualMem) - } -} - -// limitedCopyOut marshals src to task memory. The task signals an error at -// limit bytes during copy-out, which should result in a truncated marshalling. -func limitedCopyOut(t *testing.T, src marshal.Marshallable, limit int) { - var cc mockCopyContext - cc.setLimit(limit) - - n, err := src.CopyOut(&cc, hostarch.Addr(0)) - if n != limit { - t.Errorf("CopyOut copied unexpected number of bytes, expected %d, got %d", limit, n) - } - if err != simulatedErr { - t.Errorf("CopyOut returned unexpected error, expected %v, got %v", simulatedErr, err) - } - - expectedMem := unsafeMemory(src) - defer runtime.KeepAlive(src) - actualMem := cc.taskMem.Bytes - - compareMemory(t, expectedMem, actualMem, n) -} - -// copyOutN marshals src to task memory, requesting the marshalling to be -// limited to limit bytes. -func copyOutN(t *testing.T, src marshal.Marshallable, limit int) { - var cc mockCopyContext - cc.setLimit(limit) - - n, err := src.CopyOutN(&cc, hostarch.Addr(0), limit) - if err != nil { - t.Errorf("CopyOut returned unexpected error: %v", err) - } - if n != limit { - t.Errorf("CopyOut copied unexpected number of bytes, expected %d, got %d", limit, n) - } - - expectedMem := unsafeMemory(src) - defer runtime.KeepAlive(src) - actualMem := cc.taskMem.Bytes - - t.Logf("Expected: %v + %v\n", expectedMem[:n], expectedMem[n:]) - t.Logf("Actual : %v + %v\n", actualMem[:n], actualMem[n:]) - - compareMemory(t, expectedMem, actualMem, n) -} - -// TestLimitedMarshalling verifies marshalling/unmarshalling succeeds when the -// underyling copy in/out operations partially succeed. -func TestLimitedMarshalling(t *testing.T) { - types := []reflect.Type{ - // Packed types. - reflect.TypeOf((*test.Type2)(nil)), - reflect.TypeOf((*test.Type3)(nil)), - reflect.TypeOf((*test.Timespec)(nil)), - reflect.TypeOf((*test.Stat)(nil)), - reflect.TypeOf((*test.InetAddr)(nil)), - reflect.TypeOf((*test.SignalSet)(nil)), - reflect.TypeOf((*test.SignalSetAlias)(nil)), - // Non-packed types. - reflect.TypeOf((*test.Type1)(nil)), - reflect.TypeOf((*test.Type4)(nil)), - reflect.TypeOf((*test.Type5)(nil)), - reflect.TypeOf((*test.Type6)(nil)), - reflect.TypeOf((*test.Type7)(nil)), - reflect.TypeOf((*test.Type8)(nil)), - } - - for _, tyPtr := range types { - // Remove one level of pointer-indirection from the type. We get this - // back when we pass the type to reflect.New. - ty := tyPtr.Elem() - - // Partial copy-in. - t.Run(fmt.Sprintf("PartialCopyIn_%v", ty), func(t *testing.T) { - expected := reflect.New(ty).Interface().(marshal.Marshallable) - actual := reflect.New(ty).Interface().(marshal.Marshallable) - analysis.RandomizeValue(expected) - - limitedCopyIn(t, expected, actual, expected.SizeBytes()/2) - }) - - // Partial copy-out. - t.Run(fmt.Sprintf("PartialCopyOut_%v", ty), func(t *testing.T) { - expected := reflect.New(ty).Interface().(marshal.Marshallable) - analysis.RandomizeValue(expected) - - limitedCopyOut(t, expected, expected.SizeBytes()/2) - }) - - // Explicitly request partial copy-out. - t.Run(fmt.Sprintf("PartialCopyOutN_%v", ty), func(t *testing.T) { - expected := reflect.New(ty).Interface().(marshal.Marshallable) - analysis.RandomizeValue(expected) - - copyOutN(t, expected, expected.SizeBytes()/2) - }) - } -} - -// TestLimitedMarshalling verifies marshalling/unmarshalling of slices of -// marshallable types succeed when the underyling copy in/out operations -// partially succeed. -func TestLimitedSliceMarshalling(t *testing.T) { - types := []struct { - arrayPtrType reflect.Type - copySliceIn func(cc marshal.CopyContext, addr hostarch.Addr, dstSlice interface{}) (int, error) - copySliceOut func(cc marshal.CopyContext, addr hostarch.Addr, srcSlice interface{}) (int, error) - unsafeMemory func(arrPtr interface{}) []byte - }{ - // Packed types. - { - reflect.TypeOf((*[20]test.Stat)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[20]test.Stat)[:] - return test.CopyStatSliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[20]test.Stat)[:] - return test.CopyStatSliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[20]test.Stat)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - { - reflect.TypeOf((*[1]test.Stat)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[1]test.Stat)[:] - return test.CopyStatSliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[1]test.Stat)[:] - return test.CopyStatSliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[1]test.Stat)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - { - reflect.TypeOf((*[5]test.SignalSetAlias)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[5]test.SignalSetAlias)[:] - return test.CopySignalSetAliasSliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[5]test.SignalSetAlias)[:] - return test.CopySignalSetAliasSliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[5]test.SignalSetAlias)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - // Non-packed types. - { - reflect.TypeOf((*[20]test.Type1)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[20]test.Type1)[:] - return test.CopyType1SliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[20]test.Type1)[:] - return test.CopyType1SliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[20]test.Type1)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - { - reflect.TypeOf((*[1]test.Type1)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[1]test.Type1)[:] - return test.CopyType1SliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[1]test.Type1)[:] - return test.CopyType1SliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[1]test.Type1)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - { - reflect.TypeOf((*[7]test.Type8)(nil)), - func(cc marshal.CopyContext, addr hostarch.Addr, dst interface{}) (int, error) { - slice := dst.(*[7]test.Type8)[:] - return test.CopyType8SliceIn(cc, addr, slice) - }, - func(cc marshal.CopyContext, addr hostarch.Addr, src interface{}) (int, error) { - slice := src.(*[7]test.Type8)[:] - return test.CopyType8SliceOut(cc, addr, slice) - }, - func(a interface{}) []byte { - slice := a.(*[7]test.Type8)[:] - return unsafeMemorySlice(slice, &slice[0]) - }, - }, - } - - for _, tt := range types { - // The body of this loop is generic over the type tt.arrayPtrType, with - // the help of reflection. To aid in readability, comments below show - // the equivalent go code assuming - // tt.arrayPtrType = typeof(*[20]test.Stat). - - // Equivalent: - // var x *[20]test.Stat - // arrayTy := reflect.TypeOf(*x) - arrayTy := tt.arrayPtrType.Elem() - - // Partial copy-in of slices. - t.Run(fmt.Sprintf("PartialCopySliceIn_%v", arrayTy), func(t *testing.T) { - // Equivalent: - // var x [20]test.Stat - // length := len(x) - length := arrayTy.Len() - if length < 1 { - panic("Test type can't be zero-length array") - } - // Equivalent: - // elem := new(test.Stat).(marshal.Marshallable) - elem := reflect.New(arrayTy.Elem()).Interface().(marshal.Marshallable) - - // Equivalent: - // var expected, actual interface{} - // expected = new([20]test.Stat) - // actual = new([20]test.Stat) - expected := reflect.New(arrayTy).Interface() - actual := reflect.New(arrayTy).Interface() - - analysis.RandomizeValue(expected) - - limit := (length * elem.SizeBytes()) / 2 - // Also make sure the limit is partially inside one of the elements. - limit += elem.SizeBytes() / 2 - analysis.RandomizeValue(expected) - - var cc mockCopyContext - cc.populate(expected) - cc.setLimit(limit) - - n, err := tt.copySliceIn(&cc, hostarch.Addr(0), actual) - if n != limit { - t.Errorf("CopyIn copied unexpected number of bytes, expected %d, got %d", limit, n) - } - if n < length*elem.SizeBytes() && err != simulatedErr { - t.Errorf("CopyIn returned unexpected error, expected %v, got %v", simulatedErr, err) - } - - expectedMem := tt.unsafeMemory(expected) - defer runtime.KeepAlive(expected) - actualMem := tt.unsafeMemory(actual) - defer runtime.KeepAlive(actual) - - compareMemory(t, expectedMem, actualMem, n) - - // The last n bytes should be zero for actual, since actual was - // zero-initialized, and CopyIn shouldn't have touched those bytes. However - // we can only guarantee we didn't touch anything in the last n bytes if the - // layout is packed. - if elem.Packed() && !isZeroes(actualMem[n:]) { - t.Errorf("Expected the last %d bytes of copied in object to be zeroes, got %v\n", (elem.SizeBytes()*length)-n, actualMem) - } - }) - - // Partial copy-out of slices. - t.Run(fmt.Sprintf("PartialCopySliceOut_%v", arrayTy), func(t *testing.T) { - // Equivalent: - // var x [20]test.Stat - // length := len(x) - length := arrayTy.Len() - if length < 1 { - panic("Test type can't be zero-length array") - } - // Equivalent: - // elem := new(test.Stat).(marshal.Marshallable) - elem := reflect.New(arrayTy.Elem()).Interface().(marshal.Marshallable) - - // Equivalent: - // var expected, actual interface{} - // expected = new([20]test.Stat) - // actual = new([20]test.Stat) - expected := reflect.New(arrayTy).Interface() - - analysis.RandomizeValue(expected) - - limit := (length * elem.SizeBytes()) / 2 - // Also make sure the limit is partially inside one of the elements. - limit += elem.SizeBytes() / 2 - analysis.RandomizeValue(expected) - - var cc mockCopyContext - cc.populate(expected) - cc.setLimit(limit) - - n, err := tt.copySliceOut(&cc, hostarch.Addr(0), expected) - if n != limit { - t.Errorf("CopyIn copied unexpected number of bytes, expected %d, got %d", limit, n) - } - if n < length*elem.SizeBytes() && err != simulatedErr { - t.Errorf("CopyIn returned unexpected error, expected %v, got %v", simulatedErr, err) - } - - expectedMem := tt.unsafeMemory(expected) - defer runtime.KeepAlive(expected) - actualMem := cc.taskMem.Bytes - - compareMemory(t, expectedMem, actualMem, n) - }) - } -} - -func TestDynamicTypeStruct(t *testing.T) { - t12 := test.Type12Dynamic{ - X: 32, - Y: []primitive.Int64{5, 6, 7}, - } - var cc mockCopyContext - cc.setLimit(t12.SizeBytes()) - - if _, err := t12.CopyOut(&cc, hostarch.Addr(0)); err != nil { - t.Fatalf("cc.CopyOut faile: %v", err) - } - - res := test.Type12Dynamic{ - Y: make([]primitive.Int64, len(t12.Y)), - } - res.CopyIn(&cc, hostarch.Addr(0)) - if !reflect.DeepEqual(t12, res) { - t.Errorf("dynamic type is not same after marshalling and unmarshalling: before = %+v, after = %+v", t12, res) - } -} - -func TestDynamicTypeIdentifier(t *testing.T) { - s := test.Type13Dynamic("go_marshal") - var cc mockCopyContext - cc.setLimit(s.SizeBytes()) - - if _, err := s.CopyOut(&cc, hostarch.Addr(0)); err != nil { - t.Fatalf("cc.CopyOut faile: %v", err) - } - - res := test.Type13Dynamic(make([]byte, len(s))) - res.CopyIn(&cc, hostarch.Addr(0)) - if res != s { - t.Errorf("dynamic type is not same after marshalling and unmarshalling: before = %s, after = %s", s, res) - } -} diff --git a/tools/go_marshal/test/test.go b/tools/go_marshal/test/test.go deleted file mode 100644 index e7e3ed74a..000000000 --- a/tools/go_marshal/test/test.go +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright 2019 The gVisor Authors. -// -// 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 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package test contains data structures for testing the go_marshal tool. -package test - -import ( - // We're intentionally using a package name alias here even though it's not - // necessary to test the code generator's ability to handle package aliases. - ex "gvisor.dev/gvisor/tools/go_marshal/test/external" -) - -// Type1 is a test data type. -// -// +marshal slice:Type1Slice -type Type1 struct { - a Type2 - x, y int64 // Multiple field names. - b byte `marshal:"unaligned"` // Short field. - c uint64 - _ uint32 // Unnamed scalar field. - _ [6]byte // Unnamed vector field, typical padding. - _ [2]byte - xs [8]int32 - as [10]Type2 `marshal:"unaligned"` // Array of Marshallable objects. - ss Type3 -} - -// Type2 is a test data type. -// -// +marshal -type Type2 struct { - n int64 - c byte - _ [7]byte - m int64 - a int64 -} - -// Type3 is a test data type. -// -// +marshal -type Type3 struct { - s int64 - x ex.External // Type defined in another package. -} - -// Type4 is a test data type. -// -// +marshal -type Type4 struct { - c byte - x int64 `marshal:"unaligned"` - d byte - _ [7]byte -} - -// Type5 is a test data type. -// -// +marshal -type Type5 struct { - n int64 - t Type4 - m int64 -} - -// Type6 is a test data type ends mid-word. -// -// +marshal -type Type6 struct { - a int64 - b int64 - // If c isn't marked unaligned, analysis fails (as it should, since - // the unsafe API corrupts Type7). - c byte `marshal:"unaligned"` -} - -// Type7 is a test data type that contains a child struct that ends -// mid-word. -// +marshal -type Type7 struct { - x Type6 - y int64 -} - -// Type8 is a test data type which contains an external non-packed field. -// -// +marshal slice:Type8Slice -type Type8 struct { - a int64 - np ex.NotPacked - b int64 -} - -// Timespec represents struct timespec in <time.h>. -// -// +marshal -type Timespec struct { - Sec int64 - Nsec int64 -} - -// Stat represents struct stat. -// -// +marshal slice:StatSlice -type Stat struct { - Dev uint64 - Ino uint64 - Nlink uint64 - Mode uint32 - UID uint32 - GID uint32 - _ int32 - Rdev uint64 - Size int64 - Blksize int64 - Blocks int64 - ATime Timespec - MTime Timespec - CTime Timespec - _ [3]int64 -} - -// InetAddr is an example marshallable newtype on an array. -// -// +marshal -type InetAddr [4]byte - -// SignalSet is an example marshallable newtype on a primitive. -// -// +marshal slice:SignalSetSlice:inner -type SignalSet uint64 - -// SignalSetAlias is an example newtype on another marshallable type. -// -// +marshal slice:SignalSetAliasSlice -type SignalSetAlias SignalSet - -const sizeA = 64 -const sizeB = 8 - -// TestArray is a test data structure on an array with a constant length. -// -// +marshal -type TestArray [sizeA]int32 - -// TestArray2 is a newtype on an array with a simple arithmetic expression of -// constants for the array length. -// -// +marshal -type TestArray2 [sizeA * sizeB]int32 - -// TestArray3 is a newtype on an array with a simple arithmetic expression of -// mixed constants and literals for the array length. -// -// +marshal -type TestArray3 [sizeA*sizeB + 12]int32 - -// Type9 is a test data type containing an array with a non-literal length. -// -// +marshal -type Type9 struct { - x int64 - y [sizeA]int32 -} - -// Type10Embed is a test data type which is be embedded into another type. -// -// +marshal -type Type10Embed struct { - x int64 -} - -// Type10 is a test data type which contains an embedded struct. -// -// +marshal -type Type10 struct { - Type10Embed - y int64 -} - -// Type11 is a test data type which contains an embedded struct from an external -// package. -// -// +marshal -type Type11 struct { - ex.External - y int64 -} |