summaryrefslogtreecommitdiffhomepage
path: root/pkg/marshal/marshal.go
blob: a48a5835d3929260d4ba20a36d54bee9de2e352c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright 2019 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 marshal defines the Marshallable interface for
// serialize/deserializing go data structures to/from memory, according to the
// Linux ABI.
//
// Implementations of this interface are typically automatically generated by
// tools/go_marshal. See the go_marshal README for details.
package marshal

import (
	"io"

	"gvisor.dev/gvisor/pkg/hostarch"
)

// CopyContext defines the memory operations required to marshal to and from
// user memory. Typically, kernel.Task is used to provide implementations for
// these operations.
type CopyContext interface {
	// CopyScratchBuffer provides a task goroutine-local scratch buffer. See
	// kernel.CopyScratchBuffer.
	CopyScratchBuffer(size int) []byte

	// CopyOutBytes writes the contents of b to the task's memory. See
	// kernel.CopyOutBytes.
	CopyOutBytes(addr hostarch.Addr, b []byte) (int, error)

	// CopyInBytes reads the contents of the task's memory to b. See
	// kernel.CopyInBytes.
	CopyInBytes(addr hostarch.Addr, b []byte) (int, error)
}

// Marshallable represents operations on a type that can be marshalled to and
// from memory.
//
// go-marshal automatically generates implementations for this interface for
// types marked as '+marshal'.
type Marshallable interface {
	io.WriterTo

	// SizeBytes is the size of the memory representation of a type in
	// marshalled form.
	//
	// SizeBytes must handle a nil receiver. Practically, this means SizeBytes
	// cannot deference any fields on the object implementing it (but will
	// likely make use of the type of these fields).
	SizeBytes() int

	// MarshalBytes serializes a copy of a type to dst and returns the remaining
	// buffer.
	// Precondition: dst must be at least SizeBytes() in length.
	MarshalBytes(dst []byte) []byte

	// UnmarshalBytes deserializes a type from src and returns the remaining
	// buffer.
	// Precondition: src must be at least SizeBytes() in length.
	UnmarshalBytes(src []byte) []byte

	// Packed returns true if the marshalled size of the type is the same as the
	// size it occupies in memory. This happens when the type has no fields
	// starting at unaligned addresses (should always be true by default for ABI
	// structs, verified by automatically generated tests when using
	// go_marshal), and has no fields marked `marshal:"unaligned"`.
	//
	// Packed must return the same result for all possible values of the type
	// implementing it. Violating this constraint implies the type doesn't have
	// a static memory layout, and will lead to memory corruption.
	// Go-marshal-generated code reuses the result of Packed for multiple values
	// of the same type.
	Packed() bool

	// MarshalUnsafe serializes a type by bulk copying its in-memory
	// representation to the dst buffer. This is only safe to do when the type
	// has no implicit padding, see Marshallable.Packed. When Packed would
	// return false, MarshalUnsafe should fall back to the safer but slower
	// MarshalBytes.
	// Precondition: dst must be at least SizeBytes() in length.
	MarshalUnsafe(dst []byte) []byte

	// UnmarshalUnsafe deserializes a type by directly copying to the underlying
	// memory allocated for the object by the runtime.
	//
	// This allows much faster unmarshalling of types which have no implicit
	// padding, see Marshallable.Packed. When Packed would return false,
	// UnmarshalUnsafe should fall back to the safer but slower unmarshal
	// mechanism implemented in UnmarshalBytes.
	// Precondition: src must be at least SizeBytes() in length.
	UnmarshalUnsafe(src []byte) []byte

	// CopyIn deserializes a Marshallable type from a task's memory. This may
	// only be called from a task goroutine. This is more efficient than calling
	// UnmarshalUnsafe on Marshallable.Packed types, as the type being
	// marshalled does not escape. The implementation should avoid creating
	// extra copies in memory by directly deserializing to the object's
	// underlying memory.
	//
	// If the copy-in from the task memory is only partially successful, CopyIn
	// should still attempt to deserialize as much data as possible. See comment
	// for UnmarshalBytes.
	CopyIn(cc CopyContext, addr hostarch.Addr) (int, error)

	// CopyOut serializes a Marshallable type to a task's memory. This may only
	// be called from a task goroutine. This is more efficient than calling
	// MarshalUnsafe on Marshallable.Packed types, as the type being serialized
	// does not escape. The implementation should avoid creating extra copies in
	// memory by directly serializing from the object's underlying memory.
	//
	// The copy-out to the task memory may be partially successful, in which
	// case CopyOut returns how much data was serialized. See comment for
	// MarshalBytes for implications.
	CopyOut(cc CopyContext, addr hostarch.Addr) (int, error)

	// CopyOutN is like CopyOut, but explicitly requests a partial
	// copy-out. Note that this may yield unexpected results for non-packed
	// types and the caller may only want to allow this for packed types. See
	// comment on MarshalBytes.
	//
	// The limit must be less than or equal to SizeBytes().
	CopyOutN(cc CopyContext, addr hostarch.Addr, limit int) (int, error)
}

// go-marshal generates additional functions for a type based on additional
// clauses to the +marshal directive. They are documented below.
//
// Slice API
// =========
//
// Adding a "slice" clause to the +marshal directive for structs or newtypes on
// primitives like this:
//
// // +marshal slice:FooSlice
// type Foo struct { ... }
//
// Generates four additional functions for marshalling slices of Foos like this:
//
// // MarshalUnsafeFooSlice is like Foo.MarshalUnsafe, buf for a []Foo. It
// // might be more efficient that repeatedly calling Foo.MarshalUnsafe
// // over a []Foo in a loop if the type is Packed.
// // Preconditions: dst must be at least len(src)*Foo.SizeBytes() in length.
// func MarshalUnsafeFooSlice(src []Foo, dst []byte) []byte { ... }
//
// // UnmarshalUnsafeFooSlice is like Foo.UnmarshalUnsafe, buf for a []Foo. It
// // might be more efficient that repeatedly calling Foo.UnmarshalUnsafe
// // over a []Foo in a loop if the type is Packed.
// // Preconditions: src must be at least len(dst)*Foo.SizeBytes() in length.
// func UnmarshalUnsafeFooSlice(dst []Foo, src []byte) []byte { ... }
//
// // CopyFooSliceIn copies in a slice of Foo objects from the task's memory.
// func CopyFooSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Foo) (int, error) { ... }
//
// // CopyFooSliceIn copies out a slice of Foo objects to the task's memory.
// func CopyFooSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []Foo) (int, error) { ... }
//
// The name of the functions are of the format "Copy%sIn" and "Copy%sOut", where
// %s is the first argument to the slice clause. This directive is not supported
// for newtypes on arrays.
//
// Note: Partial copies are not supported for Slice API UnmarshalUnsafe and
// MarshalUnsafe.
//
// The slice clause also takes an optional second argument, which must be the
// value "inner":
//
// // +marshal slice:Int32Slice:inner
// type Int32 int32
//
// This is only valid on newtypes on primitives, and causes the generated
// functions to accept slices of the inner type instead:
//
// func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []int32) (int, error) { ... }
//
// Without "inner", they would instead be:
//
// func CopyInt32SliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst []Int32) (int, error) { ... }
//
// This may help avoid a cast depending on how the generated functions are used.