gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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 "gvisor.dev/gvisor/pkg/hostarch" 23 "gvisor.dev/gvisor/pkg/marshal" 24 ) 25 26 // Int8 is a marshal.Marshallable implementation for int8. 27 // 28 // +marshal boundCheck slice:Int8Slice:inner 29 type Int8 int8 30 31 // Uint8 is a marshal.Marshallable implementation for uint8. 32 // 33 // +marshal boundCheck slice:Uint8Slice:inner 34 type Uint8 uint8 35 36 // Int16 is a marshal.Marshallable implementation for int16. 37 // 38 // +marshal boundCheck slice:Int16Slice:inner 39 type Int16 int16 40 41 // Uint16 is a marshal.Marshallable implementation for uint16. 42 // 43 // +marshal boundCheck slice:Uint16Slice:inner 44 type Uint16 uint16 45 46 // Int32 is a marshal.Marshallable implementation for int32. 47 // 48 // +marshal boundCheck slice:Int32Slice:inner 49 type Int32 int32 50 51 // Uint32 is a marshal.Marshallable implementation for uint32. 52 // 53 // +marshal boundCheck slice:Uint32Slice:inner 54 type Uint32 uint32 55 56 // Int64 is a marshal.Marshallable implementation for int64. 57 // 58 // +marshal boundCheck slice:Int64Slice:inner 59 type Int64 int64 60 61 // Uint64 is a marshal.Marshallable implementation for uint64. 62 // 63 // +marshal boundCheck 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) []byte { 80 return dst[copy(dst, *b):] 81 } 82 83 // UnmarshalBytes implements marshal.Marshallable.UnmarshalBytes. 84 func (b *ByteSlice) UnmarshalBytes(src []byte) []byte { 85 return src[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) []byte { 95 return b.MarshalBytes(dst) 96 } 97 98 // UnmarshalUnsafe implements marshal.Marshallable.UnmarshalUnsafe. 99 func (b *ByteSlice) UnmarshalUnsafe(src []byte) []byte { 100 return 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 // CopyInN implements marshal.Marshallable.CopyInN. 109 func (b *ByteSlice) CopyInN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) { 110 return cc.CopyInBytes(addr, (*b)[:limit]) 111 } 112 113 // CopyOut implements marshal.Marshallable.CopyOut. 114 func (b *ByteSlice) CopyOut(cc marshal.CopyContext, addr hostarch.Addr) (int, error) { 115 return cc.CopyOutBytes(addr, *b) 116 } 117 118 // CopyOutN implements marshal.Marshallable.CopyOutN. 119 func (b *ByteSlice) CopyOutN(cc marshal.CopyContext, addr hostarch.Addr, limit int) (int, error) { 120 return cc.CopyOutBytes(addr, (*b)[:limit]) 121 } 122 123 // WriteTo implements io.WriterTo.WriteTo. 124 func (b *ByteSlice) WriteTo(w io.Writer) (int64, error) { 125 n, err := w.Write(*b) 126 return int64(n), err 127 } 128 129 var _ marshal.Marshallable = (*ByteSlice)(nil) 130 131 // The following set of functions are convenient shorthands for wrapping a 132 // built-in type in a marshallable primitive type. For example: 133 // 134 // func useMarshallable(m marshal.Marshallable) { ... } 135 // 136 // // Compare: 137 // 138 // buf = []byte{...} 139 // // useMarshallable(&primitive.ByteSlice(buf)) // Not allowed, can't address temp value. 140 // bufP := primitive.ByteSlice(buf) 141 // useMarshallable(&bufP) 142 // 143 // // Vs: 144 // 145 // useMarshallable(AsByteSlice(buf)) 146 // 147 // Note that the argument to these function escapes, so avoid using them on very 148 // hot code paths. But generally if a function accepts an interface as an 149 // argument, the argument escapes anyways. 150 151 // AllocateInt8 returns x as a marshallable. 152 func AllocateInt8(x int8) marshal.Marshallable { 153 p := Int8(x) 154 return &p 155 } 156 157 // AllocateUint8 returns x as a marshallable. 158 func AllocateUint8(x uint8) marshal.Marshallable { 159 p := Uint8(x) 160 return &p 161 } 162 163 // AllocateInt16 returns x as a marshallable. 164 func AllocateInt16(x int16) marshal.Marshallable { 165 p := Int16(x) 166 return &p 167 } 168 169 // AllocateUint16 returns x as a marshallable. 170 func AllocateUint16(x uint16) marshal.Marshallable { 171 p := Uint16(x) 172 return &p 173 } 174 175 // AllocateInt32 returns x as a marshallable. 176 func AllocateInt32(x int32) marshal.Marshallable { 177 p := Int32(x) 178 return &p 179 } 180 181 // AllocateUint32 returns x as a marshallable. 182 func AllocateUint32(x uint32) marshal.Marshallable { 183 p := Uint32(x) 184 return &p 185 } 186 187 // AllocateInt64 returns x as a marshallable. 188 func AllocateInt64(x int64) marshal.Marshallable { 189 p := Int64(x) 190 return &p 191 } 192 193 // AllocateUint64 returns x as a marshallable. 194 func AllocateUint64(x uint64) marshal.Marshallable { 195 p := Uint64(x) 196 return &p 197 } 198 199 // AsByteSlice returns b as a marshallable. Note that this allocates a new slice 200 // header, but does not copy the slice contents. 201 func AsByteSlice(b []byte) marshal.Marshallable { 202 bs := ByteSlice(b) 203 return &bs 204 } 205 206 // Below, we define some convenience functions for marshalling primitive types 207 // using the newtypes above, without requiring superfluous casts. 208 209 // 8-bit integers 210 211 // CopyInt8In is a convenient wrapper for copying in an int8 from the task's 212 // memory. 213 func CopyInt8In(cc marshal.CopyContext, addr hostarch.Addr, dst *int8) (int, error) { 214 var buf Int8 215 n, err := buf.CopyIn(cc, addr) 216 if err != nil { 217 return n, err 218 } 219 *dst = int8(buf) 220 return n, nil 221 } 222 223 // CopyInt8Out is a convenient wrapper for copying out an int8 to the task's 224 // memory. 225 func CopyInt8Out(cc marshal.CopyContext, addr hostarch.Addr, src int8) (int, error) { 226 srcP := Int8(src) 227 return srcP.CopyOut(cc, addr) 228 } 229 230 // CopyUint8In is a convenient wrapper for copying in a uint8 from the task's 231 // memory. 232 func CopyUint8In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint8) (int, error) { 233 var buf Uint8 234 n, err := buf.CopyIn(cc, addr) 235 if err != nil { 236 return n, err 237 } 238 *dst = uint8(buf) 239 return n, nil 240 } 241 242 // CopyUint8Out is a convenient wrapper for copying out a uint8 to the task's 243 // memory. 244 func CopyUint8Out(cc marshal.CopyContext, addr hostarch.Addr, src uint8) (int, error) { 245 srcP := Uint8(src) 246 return srcP.CopyOut(cc, addr) 247 } 248 249 // 16-bit integers 250 251 // CopyInt16In is a convenient wrapper for copying in an int16 from the task's 252 // memory. 253 func CopyInt16In(cc marshal.CopyContext, addr hostarch.Addr, dst *int16) (int, error) { 254 var buf Int16 255 n, err := buf.CopyIn(cc, addr) 256 if err != nil { 257 return n, err 258 } 259 *dst = int16(buf) 260 return n, nil 261 } 262 263 // CopyInt16Out is a convenient wrapper for copying out an int16 to the task's 264 // memory. 265 func CopyInt16Out(cc marshal.CopyContext, addr hostarch.Addr, src int16) (int, error) { 266 srcP := Int16(src) 267 return srcP.CopyOut(cc, addr) 268 } 269 270 // CopyUint16In is a convenient wrapper for copying in a uint16 from the task's 271 // memory. 272 func CopyUint16In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint16) (int, error) { 273 var buf Uint16 274 n, err := buf.CopyIn(cc, addr) 275 if err != nil { 276 return n, err 277 } 278 *dst = uint16(buf) 279 return n, nil 280 } 281 282 // CopyUint16Out is a convenient wrapper for copying out a uint16 to the task's 283 // memory. 284 func CopyUint16Out(cc marshal.CopyContext, addr hostarch.Addr, src uint16) (int, error) { 285 srcP := Uint16(src) 286 return srcP.CopyOut(cc, addr) 287 } 288 289 // 32-bit integers 290 291 // CopyInt32In is a convenient wrapper for copying in an int32 from the task's 292 // memory. 293 func CopyInt32In(cc marshal.CopyContext, addr hostarch.Addr, dst *int32) (int, error) { 294 var buf Int32 295 n, err := buf.CopyIn(cc, addr) 296 if err != nil { 297 return n, err 298 } 299 *dst = int32(buf) 300 return n, nil 301 } 302 303 // CopyInt32Out is a convenient wrapper for copying out an int32 to the task's 304 // memory. 305 func CopyInt32Out(cc marshal.CopyContext, addr hostarch.Addr, src int32) (int, error) { 306 srcP := Int32(src) 307 return srcP.CopyOut(cc, addr) 308 } 309 310 // CopyUint32In is a convenient wrapper for copying in a uint32 from the task's 311 // memory. 312 func CopyUint32In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint32) (int, error) { 313 var buf Uint32 314 n, err := buf.CopyIn(cc, addr) 315 if err != nil { 316 return n, err 317 } 318 *dst = uint32(buf) 319 return n, nil 320 } 321 322 // CopyUint32Out is a convenient wrapper for copying out a uint32 to the task's 323 // memory. 324 func CopyUint32Out(cc marshal.CopyContext, addr hostarch.Addr, src uint32) (int, error) { 325 srcP := Uint32(src) 326 return srcP.CopyOut(cc, addr) 327 } 328 329 // 64-bit integers 330 331 // CopyInt64In is a convenient wrapper for copying in an int64 from the task's 332 // memory. 333 func CopyInt64In(cc marshal.CopyContext, addr hostarch.Addr, dst *int64) (int, error) { 334 var buf Int64 335 n, err := buf.CopyIn(cc, addr) 336 if err != nil { 337 return n, err 338 } 339 *dst = int64(buf) 340 return n, nil 341 } 342 343 // CopyInt64Out is a convenient wrapper for copying out an int64 to the task's 344 // memory. 345 func CopyInt64Out(cc marshal.CopyContext, addr hostarch.Addr, src int64) (int, error) { 346 srcP := Int64(src) 347 return srcP.CopyOut(cc, addr) 348 } 349 350 // CopyUint64In is a convenient wrapper for copying in a uint64 from the task's 351 // memory. 352 func CopyUint64In(cc marshal.CopyContext, addr hostarch.Addr, dst *uint64) (int, error) { 353 var buf Uint64 354 n, err := buf.CopyIn(cc, addr) 355 if err != nil { 356 return n, err 357 } 358 *dst = uint64(buf) 359 return n, nil 360 } 361 362 // CopyUint64Out is a convenient wrapper for copying out a uint64 to the task's 363 // memory. 364 func CopyUint64Out(cc marshal.CopyContext, addr hostarch.Addr, src uint64) (int, error) { 365 srcP := Uint64(src) 366 return srcP.CopyOut(cc, addr) 367 } 368 369 // CopyByteSliceIn is a convenient wrapper for copying in a []byte from the 370 // task's memory. 371 func CopyByteSliceIn(cc marshal.CopyContext, addr hostarch.Addr, dst *[]byte) (int, error) { 372 var buf ByteSlice 373 n, err := buf.CopyIn(cc, addr) 374 if err != nil { 375 return n, err 376 } 377 *dst = []byte(buf) 378 return n, nil 379 } 380 381 // CopyByteSliceOut is a convenient wrapper for copying out a []byte to the 382 // task's memory. 383 func CopyByteSliceOut(cc marshal.CopyContext, addr hostarch.Addr, src []byte) (int, error) { 384 srcP := ByteSlice(src) 385 return srcP.CopyOut(cc, addr) 386 } 387 388 // CopyStringIn is a convenient wrapper for copying in a string from the 389 // task's memory. 390 func CopyStringIn(cc marshal.CopyContext, addr hostarch.Addr, dst *string) (int, error) { 391 var buf ByteSlice 392 n, err := buf.CopyIn(cc, addr) 393 if err != nil { 394 return n, err 395 } 396 *dst = string(buf) 397 return n, nil 398 } 399 400 // CopyStringOut is a convenient wrapper for copying out a string to the task's 401 // memory. 402 func CopyStringOut(cc marshal.CopyContext, addr hostarch.Addr, src string) (int, error) { 403 srcP := ByteSlice(src) 404 return srcP.CopyOut(cc, addr) 405 }