mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Check in gVisor.
PiperOrigin-RevId: 194583126 Change-Id: Ica1d8821a90f74e7e745962d71801c598c652463
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
package(licenses = ["notice"]) # Apache 2.0
|
||||
|
||||
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "binary",
|
||||
srcs = ["binary.go"],
|
||||
importpath = "gvisor.googlesource.com/gvisor/pkg/binary",
|
||||
visibility = ["//:sandbox"],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "binary_test",
|
||||
size = "small",
|
||||
srcs = ["binary_test.go"],
|
||||
embed = [":binary"],
|
||||
)
|
||||
@@ -0,0 +1,263 @@
|
||||
// Copyright 2018 Google Inc.
|
||||
//
|
||||
// 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 binary translates between select fixed-sized types and a binary
|
||||
// representation.
|
||||
package binary
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// LittleEndian is the same as encoding/binary.LittleEndian.
|
||||
//
|
||||
// It is included here as a convenience.
|
||||
var LittleEndian = binary.LittleEndian
|
||||
|
||||
// BigEndian is the same as encoding/binary.BigEndian.
|
||||
//
|
||||
// It is included here as a convenience.
|
||||
var BigEndian = binary.BigEndian
|
||||
|
||||
// AppendUint16 appends the binary representation of a uint16 to buf.
|
||||
func AppendUint16(buf []byte, order binary.ByteOrder, num uint16) []byte {
|
||||
buf = extendZero(2, buf)
|
||||
order.PutUint16(buf[len(buf)-2:], num)
|
||||
return buf
|
||||
}
|
||||
|
||||
// AppendUint32 appends the binary representation of a uint32 to buf.
|
||||
func AppendUint32(buf []byte, order binary.ByteOrder, num uint32) []byte {
|
||||
buf = extendZero(4, buf)
|
||||
order.PutUint32(buf[len(buf)-4:], num)
|
||||
return buf
|
||||
}
|
||||
|
||||
// AppendUint64 appends the binary representation of a uint64 to buf.
|
||||
func AppendUint64(buf []byte, order binary.ByteOrder, num uint64) []byte {
|
||||
buf = extendZero(8, buf)
|
||||
order.PutUint64(buf[len(buf)-8:], num)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Marshal appends a binary representation of data to buf.
|
||||
//
|
||||
// data must only contain fixed-length signed and unsigned ints, arrays,
|
||||
// slices, structs and compositions of said types. data may be a pointer,
|
||||
// but cannot contain pointers.
|
||||
func Marshal(buf []byte, order binary.ByteOrder, data interface{}) []byte {
|
||||
return marshal(buf, order, reflect.Indirect(reflect.ValueOf(data)))
|
||||
}
|
||||
|
||||
func marshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte {
|
||||
switch data.Kind() {
|
||||
case reflect.Int8:
|
||||
buf = append(buf, byte(int8(data.Int())))
|
||||
case reflect.Int16:
|
||||
buf = AppendUint16(buf, order, uint16(int16(data.Int())))
|
||||
case reflect.Int32:
|
||||
buf = AppendUint32(buf, order, uint32(int32(data.Int())))
|
||||
case reflect.Int64:
|
||||
buf = AppendUint64(buf, order, uint64(data.Int()))
|
||||
|
||||
case reflect.Uint8:
|
||||
buf = append(buf, byte(data.Uint()))
|
||||
case reflect.Uint16:
|
||||
buf = AppendUint16(buf, order, uint16(data.Uint()))
|
||||
case reflect.Uint32:
|
||||
buf = AppendUint32(buf, order, uint32(data.Uint()))
|
||||
case reflect.Uint64:
|
||||
buf = AppendUint64(buf, order, data.Uint())
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i, l := 0, data.Len(); i < l; i++ {
|
||||
buf = marshal(buf, order, data.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
for i, l := 0, data.NumField(); i < l; i++ {
|
||||
buf = marshal(buf, order, data.Field(i))
|
||||
}
|
||||
|
||||
default:
|
||||
panic("invalid type: " + data.Type().String())
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Unmarshal unpacks buf into data.
|
||||
//
|
||||
// data must be a slice or a pointer and buf must have a length of exactly
|
||||
// Size(data). data must only contain fixed-length signed and unsigned ints,
|
||||
// arrays, slices, structs and compositions of said types.
|
||||
func Unmarshal(buf []byte, order binary.ByteOrder, data interface{}) {
|
||||
value := reflect.ValueOf(data)
|
||||
switch value.Kind() {
|
||||
case reflect.Ptr:
|
||||
value = value.Elem()
|
||||
case reflect.Slice:
|
||||
default:
|
||||
panic("invalid type: " + value.Type().String())
|
||||
}
|
||||
buf = unmarshal(buf, order, value)
|
||||
if len(buf) != 0 {
|
||||
panic(fmt.Sprintf("buffer too long by %d bytes", len(buf)))
|
||||
}
|
||||
}
|
||||
|
||||
func unmarshal(buf []byte, order binary.ByteOrder, data reflect.Value) []byte {
|
||||
switch data.Kind() {
|
||||
case reflect.Int8:
|
||||
data.SetInt(int64(int8(buf[0])))
|
||||
buf = buf[1:]
|
||||
case reflect.Int16:
|
||||
data.SetInt(int64(int16(order.Uint16(buf))))
|
||||
buf = buf[2:]
|
||||
case reflect.Int32:
|
||||
data.SetInt(int64(int32(order.Uint32(buf))))
|
||||
buf = buf[4:]
|
||||
case reflect.Int64:
|
||||
data.SetInt(int64(order.Uint64(buf)))
|
||||
buf = buf[8:]
|
||||
|
||||
case reflect.Uint8:
|
||||
data.SetUint(uint64(buf[0]))
|
||||
buf = buf[1:]
|
||||
case reflect.Uint16:
|
||||
data.SetUint(uint64(order.Uint16(buf)))
|
||||
buf = buf[2:]
|
||||
case reflect.Uint32:
|
||||
data.SetUint(uint64(order.Uint32(buf)))
|
||||
buf = buf[4:]
|
||||
case reflect.Uint64:
|
||||
data.SetUint(order.Uint64(buf))
|
||||
buf = buf[8:]
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
for i, l := 0, data.Len(); i < l; i++ {
|
||||
buf = unmarshal(buf, order, data.Index(i))
|
||||
}
|
||||
|
||||
case reflect.Struct:
|
||||
for i, l := 0, data.NumField(); i < l; i++ {
|
||||
if field := data.Field(i); field.CanSet() {
|
||||
buf = unmarshal(buf, order, field)
|
||||
} else {
|
||||
buf = buf[sizeof(field):]
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
panic("invalid type: " + data.Type().String())
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Size calculates the buffer sized needed by Marshal or Unmarshal.
|
||||
//
|
||||
// Size only support the types supported by Marshal.
|
||||
func Size(v interface{}) uintptr {
|
||||
return sizeof(reflect.Indirect(reflect.ValueOf(v)))
|
||||
}
|
||||
|
||||
func sizeof(data reflect.Value) uintptr {
|
||||
switch data.Kind() {
|
||||
case reflect.Int8, reflect.Uint8:
|
||||
return 1
|
||||
case reflect.Int16, reflect.Uint16:
|
||||
return 2
|
||||
case reflect.Int32, reflect.Uint32:
|
||||
return 4
|
||||
case reflect.Int64, reflect.Uint64:
|
||||
return 8
|
||||
|
||||
case reflect.Array, reflect.Slice:
|
||||
var size uintptr
|
||||
for i, l := 0, data.Len(); i < l; i++ {
|
||||
size += sizeof(data.Index(i))
|
||||
}
|
||||
return size
|
||||
|
||||
case reflect.Struct:
|
||||
var size uintptr
|
||||
for i, l := 0, data.NumField(); i < l; i++ {
|
||||
size += sizeof(data.Field(i))
|
||||
}
|
||||
return size
|
||||
|
||||
default:
|
||||
panic("invalid type: " + data.Type().String())
|
||||
}
|
||||
}
|
||||
|
||||
func extendZero(amount uintptr, buf []byte) []byte {
|
||||
for i := uintptr(0); i < amount; i++ {
|
||||
buf = append(buf, 0)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// ReadUint16 reads a uint16 from r.
|
||||
func ReadUint16(r io.Reader, order binary.ByteOrder) (uint16, error) {
|
||||
buf := make([]byte, 2)
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return order.Uint16(buf), nil
|
||||
}
|
||||
|
||||
// ReadUint32 reads a uint32 from r.
|
||||
func ReadUint32(r io.Reader, order binary.ByteOrder) (uint32, error) {
|
||||
buf := make([]byte, 4)
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return order.Uint32(buf), nil
|
||||
}
|
||||
|
||||
// ReadUint64 reads a uint64 from r.
|
||||
func ReadUint64(r io.Reader, order binary.ByteOrder) (uint64, error) {
|
||||
buf := make([]byte, 8)
|
||||
if _, err := io.ReadFull(r, buf); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return order.Uint64(buf), nil
|
||||
}
|
||||
|
||||
// WriteUint16 writes a uint16 to w.
|
||||
func WriteUint16(w io.Writer, order binary.ByteOrder, num uint16) error {
|
||||
buf := make([]byte, 2)
|
||||
order.PutUint16(buf, num)
|
||||
_, err := w.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteUint32 writes a uint32 to w.
|
||||
func WriteUint32(w io.Writer, order binary.ByteOrder, num uint32) error {
|
||||
buf := make([]byte, 4)
|
||||
order.PutUint32(buf, num)
|
||||
_, err := w.Write(buf)
|
||||
return err
|
||||
}
|
||||
|
||||
// WriteUint64 writes a uint64 to w.
|
||||
func WriteUint64(w io.Writer, order binary.ByteOrder, num uint64) error {
|
||||
buf := make([]byte, 8)
|
||||
order.PutUint64(buf, num)
|
||||
_, err := w.Write(buf)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
// Copyright 2018 Google Inc.
|
||||
//
|
||||
// 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 binary
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func newInt32(i int32) *int32 {
|
||||
return &i
|
||||
}
|
||||
|
||||
func TestSize(t *testing.T) {
|
||||
if got, want := Size(uint32(10)), uintptr(4); got != want {
|
||||
t.Errorf("Got = %d, want = %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPanic(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f func([]byte, binary.ByteOrder, interface{})
|
||||
data interface{}
|
||||
want string
|
||||
}{
|
||||
{"Unmarshal int", Unmarshal, 5, "invalid type: int"},
|
||||
{"Unmarshal []int", Unmarshal, []int{5}, "invalid type: int"},
|
||||
{"Marshal int", func(_ []byte, bo binary.ByteOrder, d interface{}) { Marshal(nil, bo, d) }, 5, "invalid type: int"},
|
||||
{"Marshal int[]", func(_ []byte, bo binary.ByteOrder, d interface{}) { Marshal(nil, bo, d) }, []int{5}, "invalid type: int"},
|
||||
{"Unmarshal short buffer", Unmarshal, newInt32(5), "runtime error: index out of range"},
|
||||
{"Unmarshal long buffer", func(_ []byte, bo binary.ByteOrder, d interface{}) { Unmarshal(make([]byte, 50), bo, d) }, newInt32(5), "buffer too long by 46 bytes"},
|
||||
{"marshal int", func(_ []byte, bo binary.ByteOrder, d interface{}) { marshal(nil, bo, reflect.ValueOf(d)) }, 5, "invalid type: int"},
|
||||
{"Size int", func(_ []byte, _ binary.ByteOrder, d interface{}) { Size(d) }, 5, "invalid type: int"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
defer func() {
|
||||
r := recover()
|
||||
if got := fmt.Sprint(r); got != test.want {
|
||||
t.Errorf("Got recover() = %q, want = %q", got, test.want)
|
||||
}
|
||||
}()
|
||||
|
||||
test.f(nil, LittleEndian, test.data)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type inner struct {
|
||||
Field int32
|
||||
}
|
||||
|
||||
type outer struct {
|
||||
Int8 int8
|
||||
Int16 int16
|
||||
Int32 int32
|
||||
Int64 int64
|
||||
Uint8 uint8
|
||||
Uint16 uint16
|
||||
Uint32 uint32
|
||||
Uint64 uint64
|
||||
|
||||
Slice []int32
|
||||
Array [5]int32
|
||||
Struct inner
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshal(t *testing.T) {
|
||||
want := outer{
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
[]int32{9, 10, 11},
|
||||
[5]int32{12, 13, 14, 15, 16},
|
||||
inner{17},
|
||||
}
|
||||
buf := Marshal(nil, LittleEndian, want)
|
||||
got := outer{Slice: []int32{0, 0, 0}}
|
||||
Unmarshal(buf, LittleEndian, &got)
|
||||
if !reflect.DeepEqual(&got, &want) {
|
||||
t.Errorf("Got = %#v, want = %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type outerBenchmark struct {
|
||||
Int8 int8
|
||||
Int16 int16
|
||||
Int32 int32
|
||||
Int64 int64
|
||||
Uint8 uint8
|
||||
Uint16 uint16
|
||||
Uint32 uint32
|
||||
Uint64 uint64
|
||||
|
||||
Array [5]int32
|
||||
Struct inner
|
||||
}
|
||||
|
||||
func BenchmarkMarshalUnmarshal(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
in := outerBenchmark{
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
[5]int32{9, 10, 11, 12, 13},
|
||||
inner{14},
|
||||
}
|
||||
buf := make([]byte, Size(&in))
|
||||
out := outerBenchmark{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf := Marshal(buf[:0], LittleEndian, &in)
|
||||
Unmarshal(buf, LittleEndian, &out)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkReadWrite(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
|
||||
in := outerBenchmark{
|
||||
1, 2, 3, 4, 5, 6, 7, 8,
|
||||
[5]int32{9, 10, 11, 12, 13},
|
||||
inner{14},
|
||||
}
|
||||
buf := bytes.NewBuffer(make([]byte, binary.Size(&in)))
|
||||
out := outerBenchmark{}
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
buf.Reset()
|
||||
if err := binary.Write(buf, LittleEndian, &in); err != nil {
|
||||
b.Error("Write:", err)
|
||||
}
|
||||
if err := binary.Read(buf, LittleEndian, &out); err != nil {
|
||||
b.Error("Read:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type outerPadding struct {
|
||||
_ int8
|
||||
_ int16
|
||||
_ int32
|
||||
_ int64
|
||||
_ uint8
|
||||
_ uint16
|
||||
_ uint32
|
||||
_ uint64
|
||||
|
||||
_ []int32
|
||||
_ [5]int32
|
||||
_ inner
|
||||
}
|
||||
|
||||
func TestMarshalUnmarshalPadding(t *testing.T) {
|
||||
var want outerPadding
|
||||
buf := Marshal(nil, LittleEndian, want)
|
||||
var got outerPadding
|
||||
Unmarshal(buf, LittleEndian, &got)
|
||||
if !reflect.DeepEqual(&got, &want) {
|
||||
t.Errorf("Got = %#v, want = %#v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Numbers with bits in every byte that distinguishable in big and little endian.
|
||||
const (
|
||||
want16 = 64<<8 | 128
|
||||
want32 = 16<<24 | 32<<16 | want16
|
||||
want64 = 1<<56 | 2<<48 | 4<<40 | 8<<32 | want32
|
||||
)
|
||||
|
||||
func TestReadWriteUint16(t *testing.T) {
|
||||
const want = uint16(want16)
|
||||
var buf bytes.Buffer
|
||||
if err := WriteUint16(&buf, LittleEndian, want); err != nil {
|
||||
t.Error("WriteUint16:", err)
|
||||
}
|
||||
got, err := ReadUint16(&buf, LittleEndian)
|
||||
if err != nil {
|
||||
t.Error("ReadUint16:", err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("got = %d, want = %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteUint32(t *testing.T) {
|
||||
const want = uint32(want32)
|
||||
var buf bytes.Buffer
|
||||
if err := WriteUint32(&buf, LittleEndian, want); err != nil {
|
||||
t.Error("WriteUint32:", err)
|
||||
}
|
||||
got, err := ReadUint32(&buf, LittleEndian)
|
||||
if err != nil {
|
||||
t.Error("ReadUint32:", err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("got = %d, want = %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadWriteUint64(t *testing.T) {
|
||||
const want = uint64(want64)
|
||||
var buf bytes.Buffer
|
||||
if err := WriteUint64(&buf, LittleEndian, want); err != nil {
|
||||
t.Error("WriteUint64:", err)
|
||||
}
|
||||
got, err := ReadUint64(&buf, LittleEndian)
|
||||
if err != nil {
|
||||
t.Error("ReadUint64:", err)
|
||||
}
|
||||
if got != want {
|
||||
t.Errorf("got = %d, want = %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
type readWriter struct {
|
||||
err error
|
||||
}
|
||||
|
||||
func (rw *readWriter) Write([]byte) (int, error) {
|
||||
return 0, rw.err
|
||||
}
|
||||
|
||||
func (rw *readWriter) Read([]byte) (int, error) {
|
||||
return 0, rw.err
|
||||
}
|
||||
|
||||
func TestReadWriteError(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
f func(rw io.ReadWriter) error
|
||||
}{
|
||||
{"WriteUint16", func(rw io.ReadWriter) error { return WriteUint16(rw, LittleEndian, 0) }},
|
||||
{"ReadUint16", func(rw io.ReadWriter) error { _, err := ReadUint16(rw, LittleEndian); return err }},
|
||||
{"WriteUint32", func(rw io.ReadWriter) error { return WriteUint32(rw, LittleEndian, 0) }},
|
||||
{"ReadUint32", func(rw io.ReadWriter) error { _, err := ReadUint32(rw, LittleEndian); return err }},
|
||||
{"WriteUint64", func(rw io.ReadWriter) error { return WriteUint64(rw, LittleEndian, 0) }},
|
||||
{"ReadUint64", func(rw io.ReadWriter) error { _, err := ReadUint64(rw, LittleEndian); return err }},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
want := errors.New("want")
|
||||
if got := test.f(&readWriter{want}); got != want {
|
||||
t.Errorf("got = %v, want = %v", got, want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user