github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/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/metacubex/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 and returns the remaining
    63  	// buffer.
    64  	// Precondition: dst must be at least SizeBytes() in length.
    65  	MarshalBytes(dst []byte) []byte
    66  
    67  	// UnmarshalBytes deserializes a type from src and returns the remaining
    68  	// buffer.
    69  	// Precondition: src must be at least SizeBytes() in length.
    70  	UnmarshalBytes(src []byte) []byte
    71  
    72  	// Packed returns true if the marshalled size of the type is the same as the
    73  	// size it occupies in memory. This happens when the type has no fields
    74  	// starting at unaligned addresses (should always be true by default for ABI
    75  	// structs, verified by automatically generated tests when using
    76  	// go_marshal), and has no fields marked `marshal:"unaligned"`.
    77  	//
    78  	// Packed must return the same result for all possible values of the type
    79  	// implementing it. Violating this constraint implies the type doesn't have
    80  	// a static memory layout, and will lead to memory corruption.
    81  	// Go-marshal-generated code reuses the result of Packed for multiple values
    82  	// of the same type.
    83  	Packed() bool
    84  
    85  	// MarshalUnsafe serializes a type by bulk copying its in-memory
    86  	// representation to the dst buffer. This is only safe to do when the type
    87  	// has no implicit padding, see Marshallable.Packed. When Packed would
    88  	// return false, MarshalUnsafe should fall back to the safer but slower
    89  	// MarshalBytes.
    90  	// Precondition: dst must be at least SizeBytes() in length.
    91  	MarshalUnsafe(dst []byte) []byte
    92  
    93  	// UnmarshalUnsafe deserializes a type by directly copying to the underlying
    94  	// memory allocated for the object by the runtime.
    95  	//
    96  	// This allows much faster unmarshalling of types which have no implicit
    97  	// padding, see Marshallable.Packed. When Packed would return false,
    98  	// UnmarshalUnsafe should fall back to the safer but slower unmarshal
    99  	// mechanism implemented in UnmarshalBytes.
   100  	// Precondition: src must be at least SizeBytes() in length.
   101  	UnmarshalUnsafe(src []byte) []byte
   102  
   103  	// CopyIn deserializes a Marshallable type from a task's memory. This may
   104  	// only be called from a task goroutine. This is more efficient than calling
   105  	// UnmarshalUnsafe on Marshallable.Packed types, as the type being
   106  	// marshalled does not escape. The implementation should avoid creating
   107  	// extra copies in memory by directly deserializing to the object's
   108  	// underlying memory.
   109  	//
   110  	// If the copy-in from the task memory is only partially successful, CopyIn
   111  	// should still attempt to deserialize as much data as possible. See comment
   112  	// for UnmarshalBytes.
   113  	CopyIn(cc CopyContext, addr hostarch.Addr) (int, error)
   114  
   115  	// CopyInN is like CopyIn, but explicitly requests a partial
   116  	// copy-in. Note that this may yield unexpected results for non-packed
   117  	// types and the caller may only want to allow this for packed types. See
   118  	// comment on UnmarshalBytes.
   119  	//
   120  	// The limit must be less than or equal to SizeBytes().
   121  	CopyInN(cc CopyContext, addr hostarch.Addr, limit int) (int, error)
   122  
   123  	// CopyOut serializes a Marshallable type to a task's memory. This may only
   124  	// be called from a task goroutine. This is more efficient than calling
   125  	// MarshalUnsafe on Marshallable.Packed types, as the type being serialized
   126  	// does not escape. The implementation should avoid creating extra copies in
   127  	// memory by directly serializing from the object's underlying memory.
   128  	//
   129  	// The copy-out to the task memory may be partially successful, in which
   130  	// case CopyOut returns how much data was serialized. See comment for
   131  	// MarshalBytes for implications.
   132  	CopyOut(cc CopyContext, addr hostarch.Addr) (int, error)
   133  
   134  	// CopyOutN is like CopyOut, but explicitly requests a partial
   135  	// copy-out. Note that this may yield unexpected results for non-packed
   136  	// types and the caller may only want to allow this for packed types. See
   137  	// comment on MarshalBytes.
   138  	//
   139  	// The limit must be less than or equal to SizeBytes().
   140  	CopyOutN(cc CopyContext, addr hostarch.Addr, limit int) (int, error)
   141  }
   142  
   143  // CheckedMarshallable represents operations on a type that can be marshalled
   144  // to and from memory and additionally does bound checking.
   145  type CheckedMarshallable interface {
   146  	// CheckedMarshal is the same as Marshallable.MarshalUnsafe but without the
   147  	// precondition that dst must at least have some appropriate length. Similar
   148  	// to Marshallable.MarshalBytes, it returns a shifted slice according to how
   149  	// much data is consumed. Additionally it returns a bool indicating whether
   150  	// marshalling was successful. Unsuccessful marshalling doesn't consume any
   151  	// data.
   152  	CheckedMarshal(dst []byte) ([]byte, bool)
   153  
   154  	// CheckedUnmarshal is the same as Marshallable.UmarshalUnsafe but without
   155  	// the precondition that src must at least have some appropriate length.
   156  	// Similar to Marshallable.UnmarshalBytes, it returns a shifted slice
   157  	// according to how much data is consumed. Additionally it returns a bool
   158  	// indicating whether marshalling was successful. Unsuccessful marshalling
   159  	// doesn't consume any data.
   160  	CheckedUnmarshal(src []byte) ([]byte, bool)
   161  }
   162  
   163  // go-marshal generates additional functions for a type based on additional
   164  // clauses to the +marshal directive. They are documented below.
   165  //
   166  // Slice API
   167  // =========
   168  //
   169  // Adding a "slice" clause to the +marshal directive for structs or newtypes on
   170  // primitives like this:
   171  //
   172  // // +marshal slice:FooSlice
   173  // type Foo struct { ... }
   174  //
   175  // Generates four additional functions for marshalling slices of Foos like this:
   176  //
   177  // // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
   178  // // might be more efficient that repeatedly calling Foo.MarshalUnsafe
   179  // // over a []Foo in a loop if the type is Packed.
   180  // // Preconditions: dst must be at least len(src)*Foo.SizeBytes() in length.
   181  // func MarshalUnsafeFooSlice(src []Foo, dst []byte) []byte { ... }
   182  //
   183  // // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
   184  // // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
   185  // // over a []Foo in a loop if the type is Packed.
   186  // // Preconditions: src must be at least len(dst)*Foo.SizeBytes() in length.
   187  // func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) []byte { ... }
   188  //
   189  // // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
   190  // func CopyFooSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Foo) (int, error) { ... }
   191  //
   192  // // CopyFooSliceIn copies out a slice of Foo objects to the task's memory.
   193  // func CopyFooSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []Foo) (int, error) { ... }
   194  //
   195  // The name of the functions are of the format "Copy%sIn" and "Copy%sOut", where
   196  // %s is the first argument to the slice clause. This directive is not supported
   197  // for newtypes on arrays.
   198  //
   199  // Note: Partial copies are not supported for Slice API UnmarshalUnsafe and
   200  // MarshalUnsafe.
   201  //
   202  // The slice clause also takes an optional second argument, which must be the
   203  // value "inner":
   204  //
   205  // // +marshal slice:Int32Slice:inner
   206  // type Int32 int32
   207  //
   208  // This is only valid on newtypes on primitives, and causes the generated
   209  // functions to accept slices of the inner type instead:
   210  //
   211  // func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []int32) (int, error) { ... }
   212  //
   213  // Without "inner", they would instead be:
   214  //
   215  // func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Int32) (int, error) { ... }
   216  //
   217  // This may help avoid a cast depending on how the generated functions are used.
   218  //
   219  // Bound Checking
   220  // ==============
   221  //
   222  // Some users might want to do bound checking on marshal and unmarshal. This is
   223  // is useful when the user does not control the buffer size. To prevent
   224  // repeated bound checking code around Marshallable, users can add a
   225  // "boundCheck" clause to the +marshal directive. go_marshal will generate the
   226  // CheckedMarshallable interface methods on the type.