github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/marshal/primitive/primitive.go (about)

     1  // Copyright 2020 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package primitive defines marshal.Marshallable implementations for primitive
    16  // types.
    17  package primitive
    18  
    19  import (
    20  	"io"
    21  
    22  	"github.com/SagerNet/gvisor/pkg/hostarch"
    23  	"github.com/SagerNet/gvisor/pkg/marshal"
    24  )
    25  
    26  // Int8 is a marshal.Marshallable implementation for int8.
    27  //
    28  // +marshal slice:Int8Slice:inner
    29  type Int8 int8
    30  
    31  // Uint8 is a marshal.Marshallable implementation for uint8.
    32  //
    33  // +marshal slice:Uint8Slice:inner
    34  type Uint8 uint8
    35  
    36  // Int16 is a marshal.Marshallable implementation for int16.
    37  //
    38  // +marshal slice:Int16Slice:inner
    39  type Int16 int16
    40  
    41  // Uint16 is a marshal.Marshallable implementation for uint16.
    42  //
    43  // +marshal slice:Uint16Slice:inner
    44  type Uint16 uint16
    45  
    46  // Int32 is a marshal.Marshallable implementation for int32.
    47  //
    48  // +marshal slice:Int32Slice:inner
    49  type Int32 int32
    50  
    51  // Uint32 is a marshal.Marshallable implementation for uint32.
    52  //
    53  // +marshal slice:Uint32Slice:inner
    54  type Uint32 uint32
    55  
    56  // Int64 is a marshal.Marshallable implementation for int64.
    57  //
    58  // +marshal slice:Int64Slice:inner
    59  type Int64 int64
    60  
    61  // Uint64 is a marshal.Marshallable implementation for uint64.
    62  //
    63  // +marshal slice:Uint64Slice:inner
    64  type Uint64 uint64
    65  
    66  // ByteSlice is a marshal.Marshallable implementation for []byte.
    67  // This is a convenience wrapper around a dynamically sized type, and can't be
    68  // embedded in other marshallable types because it breaks assumptions made by
    69  // go-marshal internals. It violates the "no dynamically-sized types"
    70  // constraint of the go-marshal library.
    71  type ByteSlice []byte
    72  
    73  // SizeBytes implements marshal.Marshallable.SizeBytes.
    74  func (b *ByteSlice) SizeBytes() int {
    75  	return len(*b)
    76  }
    77  
    78  // MarshalBytes implements marshal.Marshallable.MarshalBytes.
    79  func (b *ByteSlice) MarshalBytes(dst []byte) {
    80  	copy(dst, *b)
    81  }
    82  
    83  // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes.
    84  func (b *ByteSlice) UnmarshalBytes(src []byte) {
    85  	copy(*b, src)
    86  }
    87  
    88  // Packed implements marshal.Marshallable.Packed.
    89  func (b *ByteSlice) Packed() bool {
    90  	return false
    91  }
    92  
    93  // MarshalUnsafe implements marshal.Marshallable.MarshalUnsafe.
    94  func (b *ByteSlice) MarshalUnsafe(dst []byte) {
    95  	b.MarshalBytes(dst)
    96  }
    97  
    98  // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe.
    99  func (b *ByteSlice) UnmarshalUnsafe(src []byte) {
   100  	b.UnmarshalBytes(src)
   101  }
   102  
   103  // CopyIn implements marshal.Marshallable.CopyIn.
   104  func (b *ByteSlice) CopyIn(cc marshal.CopyContext, addr hostarch.Addr) (int, error) {
   105  	return cc.CopyInBytes(addr, *b)
   106  }
   107  
   108  // CopyOut implements marshal.Marshallable.CopyOut.
   109  func (b *ByteSlice) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) {
   110  	return cc.CopyOutBytes(addr, *b)
   111  }
   112  
   113  // CopyOutN implements marshal.Marshallable.CopyOutN.
   114  func (b *ByteSlice) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) {
   115  	return cc.CopyOutBytes(addr, (*b)[:limit])
   116  }
   117  
   118  // WriteTo implements io.WriterTo.WriteTo.
   119  func (b *ByteSlice) WriteTo(w io.Writer) (int64, error) {
   120  	n, err := w.Write(*b)
   121  	return int64(n), err
   122  }
   123  
   124  var _ marshal.Marshallable = (*ByteSlice)(nil)
   125  
   126  // The following set of functions are convenient shorthands for wrapping a
   127  // built-in type in a marshallable primitive type. For example:
   128  //
   129  // func useMarshallable(m marshal.Marshallable) { ... }
   130  //
   131  // // Compare:
   132  //
   133  // buf = []byte{...}
   134  // // useMarshallable(&primitive.ByteSlice(buf)) // Not allowed, can't address temp value.
   135  // bufP := primitive.ByteSlice(buf)
   136  // useMarshallable(&bufP)
   137  //
   138  // // Vs:
   139  //
   140  // useMarshallable(AsByteSlice(buf))
   141  //
   142  // Note that the argument to these function escapes, so avoid using them on very
   143  // hot code paths. But generally if a function accepts an interface as an
   144  // argument, the argument escapes anyways.
   145  
   146  // AllocateInt8 returns x as a marshallable.
   147  func AllocateInt8(x int8) marshal.Marshallable {
   148  	p := Int8(x)
   149  	return &p
   150  }
   151  
   152  // AllocateUint8 returns x as a marshallable.
   153  func AllocateUint8(x uint8) marshal.Marshallable {
   154  	p := Uint8(x)
   155  	return &p
   156  }
   157  
   158  // AllocateInt16 returns x as a marshallable.
   159  func AllocateInt16(x int16) marshal.Marshallable {
   160  	p := Int16(x)
   161  	return &p
   162  }
   163  
   164  // AllocateUint16 returns x as a marshallable.
   165  func AllocateUint16(x uint16) marshal.Marshallable {
   166  	p := Uint16(x)
   167  	return &p
   168  }
   169  
   170  // AllocateInt32 returns x as a marshallable.
   171  func AllocateInt32(x int32) marshal.Marshallable {
   172  	p := Int32(x)
   173  	return &p
   174  }
   175  
   176  // AllocateUint32 returns x as a marshallable.
   177  func AllocateUint32(x uint32) marshal.Marshallable {
   178  	p := Uint32(x)
   179  	return &p
   180  }
   181  
   182  // AllocateInt64 returns x as a marshallable.
   183  func AllocateInt64(x int64) marshal.Marshallable {
   184  	p := Int64(x)
   185  	return &p
   186  }
   187  
   188  // AllocateUint64 returns x as a marshallable.
   189  func AllocateUint64(x uint64) marshal.Marshallable {
   190  	p := Uint64(x)
   191  	return &p
   192  }
   193  
   194  // AsByteSlice returns b as a marshallable. Note that this allocates a new slice
   195  // header, but does not copy the slice contents.
   196  func AsByteSlice(b []byte) marshal.Marshallable {
   197  	bs := ByteSlice(b)
   198  	return &bs
   199  }
   200  
   201  // Below, we define some convenience functions for marshalling primitive types
   202  // using the newtypes above, without requiring superfluous casts.
   203  
   204  // 8-bit integers
   205  
   206  // CopyInt8In is a convenient wrapper for copying in an int8 from the task's
   207  // memory.
   208  func CopyInt8In(cc marshal.CopyContext, addr hostarch.Addr, dst *int8) (int, error) {
   209  	var buf Int8
   210  	n, err := buf.CopyIn(cc, addr)
   211  	if err != nil {
   212  		return n, err
   213  	}
   214  	*dst = int8(buf)
   215  	return n, nil
   216  }
   217  
   218  // CopyInt8Out is a convenient wrapper for copying out an int8 to the task's
   219  // memory.
   220  func CopyInt8Out(cc marshal.CopyContext, addr hostarch.Addr, src int8) (int, error) {
   221  	srcP := Int8(src)
   222  	return srcP.CopyOut(cc, addr)
   223  }
   224  
   225  // CopyUint8In is a convenient wrapper for copying in a uint8 from the task's
   226  // memory.
   227  func CopyUint8In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint8) (int, error) {
   228  	var buf Uint8
   229  	n, err := buf.CopyIn(cc, addr)
   230  	if err != nil {
   231  		return n, err
   232  	}
   233  	*dst = uint8(buf)
   234  	return n, nil
   235  }
   236  
   237  // CopyUint8Out is a convenient wrapper for copying out a uint8 to the task's
   238  // memory.
   239  func CopyUint8Out(cc marshal.CopyContext, addr hostarch.Addr, src uint8) (int, error) {
   240  	srcP := Uint8(src)
   241  	return srcP.CopyOut(cc, addr)
   242  }
   243  
   244  // 16-bit integers
   245  
   246  // CopyInt16In is a convenient wrapper for copying in an int16 from the task's
   247  // memory.
   248  func CopyInt16In(cc marshal.CopyContext, addr hostarch.Addr, dst *int16) (int, error) {
   249  	var buf Int16
   250  	n, err := buf.CopyIn(cc, addr)
   251  	if err != nil {
   252  		return n, err
   253  	}
   254  	*dst = int16(buf)
   255  	return n, nil
   256  }
   257  
   258  // CopyInt16Out is a convenient wrapper for copying out an int16 to the task's
   259  // memory.
   260  func CopyInt16Out(cc marshal.CopyContext, addr hostarch.Addr, src int16) (int, error) {
   261  	srcP := Int16(src)
   262  	return srcP.CopyOut(cc, addr)
   263  }
   264  
   265  // CopyUint16In is a convenient wrapper for copying in a uint16 from the task's
   266  // memory.
   267  func CopyUint16In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint16) (int, error) {
   268  	var buf Uint16
   269  	n, err := buf.CopyIn(cc, addr)
   270  	if err != nil {
   271  		return n, err
   272  	}
   273  	*dst = uint16(buf)
   274  	return n, nil
   275  }
   276  
   277  // CopyUint16Out is a convenient wrapper for copying out a uint16 to the task's
   278  // memory.
   279  func CopyUint16Out(cc marshal.CopyContext, addr hostarch.Addr, src uint16) (int, error) {
   280  	srcP := Uint16(src)
   281  	return srcP.CopyOut(cc, addr)
   282  }
   283  
   284  // 32-bit integers
   285  
   286  // CopyInt32In is a convenient wrapper for copying in an int32 from the task's
   287  // memory.
   288  func CopyInt32In(cc marshal.CopyContext, addr hostarch.Addr, dst *int32) (int, error) {
   289  	var buf Int32
   290  	n, err := buf.CopyIn(cc, addr)
   291  	if err != nil {
   292  		return n, err
   293  	}
   294  	*dst = int32(buf)
   295  	return n, nil
   296  }
   297  
   298  // CopyInt32Out is a convenient wrapper for copying out an int32 to the task's
   299  // memory.
   300  func CopyInt32Out(cc marshal.CopyContext, addr hostarch.Addr, src int32) (int, error) {
   301  	srcP := Int32(src)
   302  	return srcP.CopyOut(cc, addr)
   303  }
   304  
   305  // CopyUint32In is a convenient wrapper for copying in a uint32 from the task's
   306  // memory.
   307  func CopyUint32In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint32) (int, error) {
   308  	var buf Uint32
   309  	n, err := buf.CopyIn(cc, addr)
   310  	if err != nil {
   311  		return n, err
   312  	}
   313  	*dst = uint32(buf)
   314  	return n, nil
   315  }
   316  
   317  // CopyUint32Out is a convenient wrapper for copying out a uint32 to the task's
   318  // memory.
   319  func CopyUint32Out(cc marshal.CopyContext, addr hostarch.Addr, src uint32) (int, error) {
   320  	srcP := Uint32(src)
   321  	return srcP.CopyOut(cc, addr)
   322  }
   323  
   324  // 64-bit integers
   325  
   326  // CopyInt64In is a convenient wrapper for copying in an int64 from the task's
   327  // memory.
   328  func CopyInt64In(cc marshal.CopyContext, addr hostarch.Addr, dst *int64) (int, error) {
   329  	var buf Int64
   330  	n, err := buf.CopyIn(cc, addr)
   331  	if err != nil {
   332  		return n, err
   333  	}
   334  	*dst = int64(buf)
   335  	return n, nil
   336  }
   337  
   338  // CopyInt64Out is a convenient wrapper for copying out an int64 to the task's
   339  // memory.
   340  func CopyInt64Out(cc marshal.CopyContext, addr hostarch.Addr, src int64) (int, error) {
   341  	srcP := Int64(src)
   342  	return srcP.CopyOut(cc, addr)
   343  }
   344  
   345  // CopyUint64In is a convenient wrapper for copying in a uint64 from the task's
   346  // memory.
   347  func CopyUint64In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint64) (int, error) {
   348  	var buf Uint64
   349  	n, err := buf.CopyIn(cc, addr)
   350  	if err != nil {
   351  		return n, err
   352  	}
   353  	*dst = uint64(buf)
   354  	return n, nil
   355  }
   356  
   357  // CopyUint64Out is a convenient wrapper for copying out a uint64 to the task's
   358  // memory.
   359  func CopyUint64Out(cc marshal.CopyContext, addr hostarch.Addr, src uint64) (int, error) {
   360  	srcP := Uint64(src)
   361  	return srcP.CopyOut(cc, addr)
   362  }
   363  
   364  // CopyByteSliceIn is a convenient wrapper for copying in a []byte from the
   365  // task's memory.
   366  func CopyByteSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst *[]byte) (int, error) {
   367  	var buf ByteSlice
   368  	n, err := buf.CopyIn(cc, addr)
   369  	if err != nil {
   370  		return n, err
   371  	}
   372  	*dst = []byte(buf)
   373  	return n, nil
   374  }
   375  
   376  // CopyByteSliceOut is a convenient wrapper for copying out a []byte to the
   377  // task's memory.
   378  func CopyByteSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []byte) (int, error) {
   379  	srcP := ByteSlice(src)
   380  	return srcP.CopyOut(cc, addr)
   381  }
   382  
   383  // CopyStringIn is a convenient wrapper for copying in a string from the
   384  // task's memory.
   385  func CopyStringIn(cc marshal.CopyContext, addr hostarch.Addr, dst *string) (int, error) {
   386  	var buf ByteSlice
   387  	n, err := buf.CopyIn(cc, addr)
   388  	if err != nil {
   389  		return n, err
   390  	}
   391  	*dst = string(buf)
   392  	return n, nil
   393  }
   394  
   395  // CopyStringOut is a convenient wrapper for copying out a string to the task's
   396  // memory.
   397  func CopyStringOut(cc marshal.CopyContext, addr hostarch.Addr, src string) (int, error) {
   398  	srcP := ByteSlice(src)
   399  	return srcP.CopyOut(cc, addr)
   400  }