summaryrefslogtreecommitdiffhomepage
path: root/pkg/safemem
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/safemem')
-rw-r--r--pkg/safemem/BUILD30
-rw-r--r--pkg/safemem/io_test.go199
-rw-r--r--pkg/safemem/safemem_state_autogen.go3
-rw-r--r--pkg/safemem/safemem_unsafe_state_autogen.go3
-rw-r--r--pkg/safemem/seq_test.go217
5 files changed, 6 insertions, 446 deletions
diff --git a/pkg/safemem/BUILD b/pkg/safemem/BUILD
deleted file mode 100644
index 2c7cc8769..000000000
--- a/pkg/safemem/BUILD
+++ /dev/null
@@ -1,30 +0,0 @@
-load("//tools:defs.bzl", "go_library", "go_test")
-
-package(licenses = ["notice"])
-
-go_library(
- name = "safemem",
- srcs = [
- "block_unsafe.go",
- "io.go",
- "safemem.go",
- "seq_unsafe.go",
- ],
- visibility = ["//:sandbox"],
- deps = [
- "//pkg/gohacks",
- "//pkg/safecopy",
- "//pkg/sync",
- "@org_golang_x_sys//unix:go_default_library",
- ],
-)
-
-go_test(
- name = "safemem_test",
- size = "small",
- srcs = [
- "io_test.go",
- "seq_test.go",
- ],
- library = ":safemem",
-)
diff --git a/pkg/safemem/io_test.go b/pkg/safemem/io_test.go
deleted file mode 100644
index 629741bee..000000000
--- a/pkg/safemem/io_test.go
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2018 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 safemem
-
-import (
- "bytes"
- "io"
- "testing"
-)
-
-func makeBlocks(slices ...[]byte) []Block {
- blocks := make([]Block, 0, len(slices))
- for _, s := range slices {
- blocks = append(blocks, BlockFromSafeSlice(s))
- }
- return blocks
-}
-
-func TestFromIOReaderFullRead(t *testing.T) {
- r := FromIOReader{bytes.NewBufferString("foobar")}
- dsts := makeBlocks(make([]byte, 3), make([]byte, 3))
- n, err := r.ReadToBlocks(BlockSeqFromSlice(dsts))
- if wantN := uint64(6); n != wantN || err != nil {
- t.Errorf("ReadToBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- for i, want := range [][]byte{[]byte("foo"), []byte("bar")} {
- if got := dsts[i].ToSlice(); !bytes.Equal(got, want) {
- t.Errorf("dsts[%d]: got %q, wanted %q", i, got, want)
- }
- }
-}
-
-type eofHidingReader struct {
- Reader io.Reader
-}
-
-func (r eofHidingReader) Read(dst []byte) (int, error) {
- n, err := r.Reader.Read(dst)
- if err == io.EOF {
- return n, nil
- }
- return n, err
-}
-
-func TestFromIOReaderPartialRead(t *testing.T) {
- r := FromIOReader{eofHidingReader{bytes.NewBufferString("foob")}}
- dsts := makeBlocks(make([]byte, 3), make([]byte, 3))
- n, err := r.ReadToBlocks(BlockSeqFromSlice(dsts))
- // FromIOReader should stop after the eofHidingReader returns (1, nil)
- // for a 3-byte read.
- if wantN := uint64(4); n != wantN || err != nil {
- t.Errorf("ReadToBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- for i, want := range [][]byte{[]byte("foo"), []byte("b\x00\x00")} {
- if got := dsts[i].ToSlice(); !bytes.Equal(got, want) {
- t.Errorf("dsts[%d]: got %q, wanted %q", i, got, want)
- }
- }
-}
-
-type singleByteReader struct {
- Reader io.Reader
-}
-
-func (r singleByteReader) Read(dst []byte) (int, error) {
- if len(dst) == 0 {
- return r.Reader.Read(dst)
- }
- return r.Reader.Read(dst[:1])
-}
-
-func TestSingleByteReader(t *testing.T) {
- r := FromIOReader{singleByteReader{bytes.NewBufferString("foobar")}}
- dsts := makeBlocks(make([]byte, 3), make([]byte, 3))
- n, err := r.ReadToBlocks(BlockSeqFromSlice(dsts))
- // FromIOReader should stop after the singleByteReader returns (1, nil)
- // for a 3-byte read.
- if wantN := uint64(1); n != wantN || err != nil {
- t.Errorf("ReadToBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- for i, want := range [][]byte{[]byte("f\x00\x00"), []byte("\x00\x00\x00")} {
- if got := dsts[i].ToSlice(); !bytes.Equal(got, want) {
- t.Errorf("dsts[%d]: got %q, wanted %q", i, got, want)
- }
- }
-}
-
-func TestReadFullToBlocks(t *testing.T) {
- r := FromIOReader{singleByteReader{bytes.NewBufferString("foobar")}}
- dsts := makeBlocks(make([]byte, 3), make([]byte, 3))
- n, err := ReadFullToBlocks(r, BlockSeqFromSlice(dsts))
- // ReadFullToBlocks should call into FromIOReader => singleByteReader
- // repeatedly until dsts is exhausted.
- if wantN := uint64(6); n != wantN || err != nil {
- t.Errorf("ReadFullToBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- for i, want := range [][]byte{[]byte("foo"), []byte("bar")} {
- if got := dsts[i].ToSlice(); !bytes.Equal(got, want) {
- t.Errorf("dsts[%d]: got %q, wanted %q", i, got, want)
- }
- }
-}
-
-func TestFromIOWriterFullWrite(t *testing.T) {
- srcs := makeBlocks([]byte("foo"), []byte("bar"))
- var dst bytes.Buffer
- w := FromIOWriter{&dst}
- n, err := w.WriteFromBlocks(BlockSeqFromSlice(srcs))
- if wantN := uint64(6); n != wantN || err != nil {
- t.Errorf("WriteFromBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- if got, want := dst.Bytes(), []byte("foobar"); !bytes.Equal(got, want) {
- t.Errorf("dst: got %q, wanted %q", got, want)
- }
-}
-
-type limitedWriter struct {
- Writer io.Writer
- Done int
- Limit int
-}
-
-func (w *limitedWriter) Write(src []byte) (int, error) {
- count := len(src)
- if count > (w.Limit - w.Done) {
- count = w.Limit - w.Done
- }
- n, err := w.Writer.Write(src[:count])
- w.Done += n
- return n, err
-}
-
-func TestFromIOWriterPartialWrite(t *testing.T) {
- srcs := makeBlocks([]byte("foo"), []byte("bar"))
- var dst bytes.Buffer
- w := FromIOWriter{&limitedWriter{&dst, 0, 4}}
- n, err := w.WriteFromBlocks(BlockSeqFromSlice(srcs))
- // FromIOWriter should stop after the limitedWriter returns (1, nil) for a
- // 3-byte write.
- if wantN := uint64(4); n != wantN || err != nil {
- t.Errorf("WriteFromBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- if got, want := dst.Bytes(), []byte("foob"); !bytes.Equal(got, want) {
- t.Errorf("dst: got %q, wanted %q", got, want)
- }
-}
-
-type singleByteWriter struct {
- Writer io.Writer
-}
-
-func (w singleByteWriter) Write(src []byte) (int, error) {
- if len(src) == 0 {
- return w.Writer.Write(src)
- }
- return w.Writer.Write(src[:1])
-}
-
-func TestSingleByteWriter(t *testing.T) {
- srcs := makeBlocks([]byte("foo"), []byte("bar"))
- var dst bytes.Buffer
- w := FromIOWriter{singleByteWriter{&dst}}
- n, err := w.WriteFromBlocks(BlockSeqFromSlice(srcs))
- // FromIOWriter should stop after the singleByteWriter returns (1, nil)
- // for a 3-byte write.
- if wantN := uint64(1); n != wantN || err != nil {
- t.Errorf("WriteFromBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- if got, want := dst.Bytes(), []byte("f"); !bytes.Equal(got, want) {
- t.Errorf("dst: got %q, wanted %q", got, want)
- }
-}
-
-func TestWriteFullToBlocks(t *testing.T) {
- srcs := makeBlocks([]byte("foo"), []byte("bar"))
- var dst bytes.Buffer
- w := FromIOWriter{singleByteWriter{&dst}}
- n, err := WriteFullFromBlocks(w, BlockSeqFromSlice(srcs))
- // WriteFullToBlocks should call into FromIOWriter => singleByteWriter
- // repeatedly until srcs is exhausted.
- if wantN := uint64(6); n != wantN || err != nil {
- t.Errorf("WriteFullFromBlocks: got (%v, %v), wanted (%v, nil)", n, err, wantN)
- }
- if got, want := dst.Bytes(), []byte("foobar"); !bytes.Equal(got, want) {
- t.Errorf("dst: got %q, wanted %q", got, want)
- }
-}
diff --git a/pkg/safemem/safemem_state_autogen.go b/pkg/safemem/safemem_state_autogen.go
new file mode 100644
index 000000000..66d53f22d
--- /dev/null
+++ b/pkg/safemem/safemem_state_autogen.go
@@ -0,0 +1,3 @@
+// automatically generated by stateify.
+
+package safemem
diff --git a/pkg/safemem/safemem_unsafe_state_autogen.go b/pkg/safemem/safemem_unsafe_state_autogen.go
new file mode 100644
index 000000000..66d53f22d
--- /dev/null
+++ b/pkg/safemem/safemem_unsafe_state_autogen.go
@@ -0,0 +1,3 @@
+// automatically generated by stateify.
+
+package safemem
diff --git a/pkg/safemem/seq_test.go b/pkg/safemem/seq_test.go
deleted file mode 100644
index de34005e9..000000000
--- a/pkg/safemem/seq_test.go
+++ /dev/null
@@ -1,217 +0,0 @@
-// Copyright 2018 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 safemem
-
-import (
- "bytes"
- "reflect"
- "testing"
-)
-
-func TestBlockSeqOfEmptyBlock(t *testing.T) {
- bs := BlockSeqOf(Block{})
- if !bs.IsEmpty() {
- t.Errorf("BlockSeqOf(Block{}).IsEmpty(): got false, wanted true; BlockSeq is %v", bs)
- }
-}
-
-func TestBlockSeqOfNonemptyBlock(t *testing.T) {
- b := BlockFromSafeSlice(make([]byte, 1))
- bs := BlockSeqOf(b)
- if bs.IsEmpty() {
- t.Fatalf("BlockSeqOf(non-empty Block).IsEmpty(): got true, wanted false; BlockSeq is %v", bs)
- }
- if head := bs.Head(); head != b {
- t.Fatalf("BlockSeqOf(non-empty Block).Head(): got %v, wanted %v", head, b)
- }
- if tail := bs.Tail(); !tail.IsEmpty() {
- t.Fatalf("BlockSeqOf(non-empty Block).Tail().IsEmpty(): got false, wanted true: tail is %v", tail)
- }
-}
-
-type blockSeqTest struct {
- desc string
-
- pieces []string
- haveOffset bool
- offset uint64
- haveLimit bool
- limit uint64
-
- want string
-}
-
-func (t blockSeqTest) NonEmptyByteSlices() [][]byte {
- // t is a value, so we can mutate it freely.
- slices := make([][]byte, 0, len(t.pieces))
- for _, str := range t.pieces {
- if t.haveOffset {
- strOff := t.offset
- if strOff > uint64(len(str)) {
- strOff = uint64(len(str))
- }
- str = str[strOff:]
- t.offset -= strOff
- }
- if t.haveLimit {
- strLim := t.limit
- if strLim > uint64(len(str)) {
- strLim = uint64(len(str))
- }
- str = str[:strLim]
- t.limit -= strLim
- }
- if len(str) != 0 {
- slices = append(slices, []byte(str))
- }
- }
- return slices
-}
-
-func (t blockSeqTest) BlockSeq() BlockSeq {
- blocks := make([]Block, 0, len(t.pieces))
- for _, str := range t.pieces {
- blocks = append(blocks, BlockFromSafeSlice([]byte(str)))
- }
- bs := BlockSeqFromSlice(blocks)
- if t.haveOffset {
- bs = bs.DropFirst64(t.offset)
- }
- if t.haveLimit {
- bs = bs.TakeFirst64(t.limit)
- }
- return bs
-}
-
-var blockSeqTests = []blockSeqTest{
- {
- desc: "Empty sequence",
- },
- {
- desc: "Sequence of length 1",
- pieces: []string{"foobar"},
- want: "foobar",
- },
- {
- desc: "Sequence of length 2",
- pieces: []string{"foo", "bar"},
- want: "foobar",
- },
- {
- desc: "Empty Blocks",
- pieces: []string{"", "foo", "", "", "bar", ""},
- want: "foobar",
- },
- {
- desc: "Sequence with non-zero offset",
- pieces: []string{"foo", "bar"},
- haveOffset: true,
- offset: 2,
- want: "obar",
- },
- {
- desc: "Sequence with non-maximal limit",
- pieces: []string{"foo", "bar"},
- haveLimit: true,
- limit: 5,
- want: "fooba",
- },
- {
- desc: "Sequence with offset and limit",
- pieces: []string{"foo", "bar"},
- haveOffset: true,
- offset: 2,
- haveLimit: true,
- limit: 3,
- want: "oba",
- },
-}
-
-func TestBlockSeqNumBytes(t *testing.T) {
- for _, test := range blockSeqTests {
- t.Run(test.desc, func(t *testing.T) {
- if got, want := test.BlockSeq().NumBytes(), uint64(len(test.want)); got != want {
- t.Errorf("NumBytes: got %d, wanted %d", got, want)
- }
- })
- }
-}
-
-func TestBlockSeqIterBlocks(t *testing.T) {
- // Tests BlockSeq iteration using Head/Tail.
- for _, test := range blockSeqTests {
- t.Run(test.desc, func(t *testing.T) {
- srcs := test.BlockSeq()
- // "Note that a non-nil empty slice and a nil slice ... are not
- // deeply equal." - reflect
- slices := make([][]byte, 0, 0)
- for !srcs.IsEmpty() {
- src := srcs.Head()
- slices = append(slices, src.ToSlice())
- nextSrcs := srcs.Tail()
- if got, want := nextSrcs.NumBytes(), srcs.NumBytes()-uint64(src.Len()); got != want {
- t.Fatalf("%v.Tail(): got %v (%d bytes), wanted %d bytes", srcs, nextSrcs, got, want)
- }
- srcs = nextSrcs
- }
- if wantSlices := test.NonEmptyByteSlices(); !reflect.DeepEqual(slices, wantSlices) {
- t.Errorf("Accumulated slices: got %v, wanted %v", slices, wantSlices)
- }
- })
- }
-}
-
-func TestBlockSeqIterBytes(t *testing.T) {
- // Tests BlockSeq iteration using Head/DropFirst.
- for _, test := range blockSeqTests {
- t.Run(test.desc, func(t *testing.T) {
- srcs := test.BlockSeq()
- var dst bytes.Buffer
- for !srcs.IsEmpty() {
- src := srcs.Head()
- var b [1]byte
- n, err := Copy(BlockFromSafeSlice(b[:]), src)
- if n != 1 || err != nil {
- t.Fatalf("Copy: got (%v, %v), wanted (1, nil)", n, err)
- }
- dst.WriteByte(b[0])
- nextSrcs := srcs.DropFirst(1)
- if got, want := nextSrcs.NumBytes(), srcs.NumBytes()-1; got != want {
- t.Fatalf("%v.DropFirst(1): got %v (%d bytes), wanted %d bytes", srcs, nextSrcs, got, want)
- }
- srcs = nextSrcs
- }
- if got := string(dst.Bytes()); got != test.want {
- t.Errorf("Copied string: got %q, wanted %q", got, test.want)
- }
- })
- }
-}
-
-func TestBlockSeqDropBeyondLimit(t *testing.T) {
- blocks := []Block{BlockFromSafeSlice([]byte("123")), BlockFromSafeSlice([]byte("4"))}
- bs := BlockSeqFromSlice(blocks)
- if got, want := bs.NumBytes(), uint64(4); got != want {
- t.Errorf("%v.NumBytes(): got %d, wanted %d", bs, got, want)
- }
- bs = bs.TakeFirst(1)
- if got, want := bs.NumBytes(), uint64(1); got != want {
- t.Errorf("%v.NumBytes(): got %d, wanted %d", bs, got, want)
- }
- bs = bs.DropFirst(2)
- if got, want := bs.NumBytes(), uint64(0); got != want {
- t.Errorf("%v.NumBytes(): got %d, wanted %d", bs, got, want)
- }
-}