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

     1  // Copyright 2019 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 marshal defines the Marshallable interface for
    16  // serialize/deserializing go data structures to/from memory, according to the
    17  // Linux ABI.
    18  //
    19  // Implementations of this interface are typically automatically generated by
    20  // tools/go_marshal. See the go_marshal README for details.
    21  package marshal
    22  
    23  import (
    24  	"io"
    25  
    26  	"github.com/SagerNet/gvisor/pkg/hostarch"
    27  )
    28  
    29  // CopyContext defines the memory operations required to marshal to and from
    30  // user memory. Typically, kernel.Task is used to provide implementations for
    31  // these operations.
    32  type CopyContext interface {
    33  	// CopyScratchBuffer provides a task goroutine-local scratch buffer. See
    34  	// kernel.CopyScratchBuffer.
    35  	CopyScratchBuffer(size int) []byte
    36  
    37  	// CopyOutBytes writes the contents of b to the task's memory. See
    38  	// kernel.CopyOutBytes.
    39  	CopyOutBytes(addr hostarch.Addr, b []byte) (int, error)
    40  
    41  	// CopyInBytes reads the contents of the task's memory to b. See
    42  	// kernel.CopyInBytes.
    43  	CopyInBytes(addr hostarch.Addr, b []byte) (int, error)
    44  }
    45  
    46  // Marshallable represents operations on a type that can be marshalled to and
    47  // from memory.
    48  //
    49  // go-marshal automatically generates implementations for this interface for
    50  // types marked as '+marshal'.
    51  type Marshallable interface {
    52  	io.WriterTo
    53  
    54  	// SizeBytes is the size of the memory representation of a type in
    55  	// marshalled form.
    56  	//
    57  	// SizeBytes must handle a nil receiver. Practically, this means SizeBytes
    58  	// cannot deference any fields on the object implementing it (but will
    59  	// likely make use of the type of these fields).
    60  	SizeBytes() int
    61  
    62  	// MarshalBytes serializes a copy of a type to dst.
    63  	// Precondition: dst must be at least SizeBytes() in length.
    64  	MarshalBytes(dst []byte)
    65  
    66  	// UnmarshalBytes deserializes a type from src.
    67  	// Precondition: src must be at least SizeBytes() in length.
    68  	UnmarshalBytes(src []byte)
    69  
    70  	// Packed returns true if the marshalled size of the type is the same as the
    71  	// size it occupies in memory. This happens when the type has no fields
    72  	// starting at unaligned addresses (should always be true by default for ABI
    73  	// structs, verified by automatically generated tests when using
    74  	// go_marshal), and has no fields marked `marshal:"unaligned"`.
    75  	//
    76  	// Packed must return the same result for all possible values of the type
    77  	// implementing it. Violating this constraint implies the type doesn't have
    78  	// a static memory layout, and will lead to memory corruption.
    79  	// Go-marshal-generated code reuses the result of Packed for multiple values
    80  	// of the same type.
    81  	Packed() bool
    82  
    83  	// MarshalUnsafe serializes a type by bulk copying its in-memory
    84  	// representation to the dst buffer. This is only safe to do when the type
    85  	// has no implicit padding, see Marshallable.Packed. When Packed would
    86  	// return false, MarshalUnsafe should fall back to the safer but slower
    87  	// MarshalBytes.
    88  	// Precondition: dst must be at least SizeBytes() in length.
    89  	MarshalUnsafe(dst []byte)
    90  
    91  	// UnmarshalUnsafe deserializes a type by directly copying to the underlying
    92  	// memory allocated for the object by the runtime.
    93  	//
    94  	// This allows much faster unmarshalling of types which have no implicit
    95  	// padding, see Marshallable.Packed. When Packed would return false,
    96  	// UnmarshalUnsafe should fall back to the safer but slower unmarshal
    97  	// mechanism implemented in UnmarshalBytes.
    98  	// Precondition: src must be at least SizeBytes() in length.
    99  	UnmarshalUnsafe(src []byte)
   100  
   101  	// CopyIn deserializes a Marshallable type from a task's memory. This may
   102  	// only be called from a task goroutine. This is more efficient than calling
   103  	// UnmarshalUnsafe on Marshallable.Packed types, as the type being
   104  	// marshalled does not escape. The implementation should avoid creating
   105  	// extra copies in memory by directly deserializing to the object's
   106  	// underlying memory.
   107  	//
   108  	// If the copy-in from the task memory is only partially successful, CopyIn
   109  	// should still attempt to deserialize as much data as possible. See comment
   110  	// for UnmarshalBytes.
   111  	CopyIn(cc CopyContext, addr hostarch.Addr) (int, error)
   112  
   113  	// CopyOut serializes a Marshallable type to a task's memory. This may only
   114  	// be called from a task goroutine. This is more efficient than calling
   115  	// MarshalUnsafe on Marshallable.Packed types, as the type being serialized
   116  	// does not escape. The implementation should avoid creating extra copies in
   117  	// memory by directly serializing from the object's underlying memory.
   118  	//
   119  	// The copy-out to the task memory may be partially successful, in which
   120  	// case CopyOut returns how much data was serialized. See comment for
   121  	// MarshalBytes for implications.
   122  	CopyOut(cc CopyContext, addr hostarch.Addr) (int, error)
   123  
   124  	// CopyOutN is like CopyOut, but explicitly requests a partial
   125  	// copy-out. Note that this may yield unexpected results for non-packed
   126  	// types and the caller may only want to allow this for packed types. See
   127  	// comment on MarshalBytes.
   128  	//
   129  	// The limit must be less than or equal to SizeBytes().
   130  	CopyOutN(cc CopyContext, addr hostarch.Addr, limit int) (int, error)
   131  }
   132  
   133  // go-marshal generates additional functions for a type based on additional
   134  // clauses to the +marshal directive. They are documented below.
   135  //
   136  // Slice API
   137  // =========
   138  //
   139  // Adding a "slice" clause to the +marshal directive for structs or newtypes on
   140  // primitives like this:
   141  //
   142  // // +marshal slice:FooSlice
   143  // type Foo struct { ... }
   144  //
   145  // Generates four additional functions for marshalling slices of Foos like this:
   146  //
   147  // // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
   148  // // might be more efficient that repeatedly calling Foo.MarshalUnsafe
   149  // // over a []Foo in a loop if the type is Packed.
   150  // // Preconditions: dst must be at least len(src)*Foo.SizeBytes() in length.
   151  // func MarshalUnsafeFooSlice(src []Foo, dst []byte) (int, error) { ... }
   152  //
   153  // // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
   154  // // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
   155  // // over a []Foo in a loop if the type is Packed.
   156  // // Preconditions: src must be at least len(dst)*Foo.SizeBytes() in length.
   157  // func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) (int, error) { ... }
   158  //
   159  // // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
   160  // func CopyFooSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Foo) (int, error) { ... }
   161  //
   162  // // CopyFooSliceIn copies out a slice of Foo objects to the task's memory.
   163  // func CopyFooSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []Foo) (int, error) { ... }
   164  //
   165  // The name of the functions are of the format "Copy%sIn" and "Copy%sOut", where
   166  // %s is the first argument to the slice clause. This directive is not supported
   167  // for newtypes on arrays.
   168  //
   169  // Note: Partial copies are not supported for Slice API UnmarshalUnsafe and
   170  // MarshalUnsafe.
   171  //
   172  // The slice clause also takes an optional second argument, which must be the
   173  // value "inner":
   174  //
   175  // // +marshal slice:Int32Slice:inner
   176  // type Int32 int32
   177  //
   178  // This is only valid on newtypes on primitives, and causes the generated
   179  // functions to accept slices of the inner type instead:
   180  //
   181  // func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []int32) (int, error) { ... }
   182  //
   183  // Without "inner", they would instead be:
   184  //
   185  // func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Int32) (int, error) { ... }
   186  //
   187  // This may help avoid a cast depending on how the generated functions are used.