inet.af/netstack@v0.0.0-20220214151720-7585b01ddccf/state/decode_unsafe.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 state
    16  
    17  import (
    18  	"fmt"
    19  	"reflect"
    20  	"runtime"
    21  	"unsafe"
    22  )
    23  
    24  // reflectValueRWAddr is equivalent to obj.Addr(), except that the returned
    25  // reflect.Value is usable in assignments even if obj was obtained by the use
    26  // of unexported struct fields.
    27  //
    28  // Preconditions: obj.CanAddr().
    29  func reflectValueRWAddr(obj reflect.Value) reflect.Value {
    30  	return reflect.NewAt(obj.Type(), unsafe.Pointer(obj.UnsafeAddr()))
    31  }
    32  
    33  // reflectValueRWSlice3 is equivalent to arr.Slice3(i, j, k), except that the
    34  // returned reflect.Value is usable in assignments even if obj was obtained by
    35  // the use of unexported struct fields.
    36  //
    37  // Preconditions:
    38  // * arr.Kind() == reflect.Array.
    39  // * i, j, k >= 0.
    40  // * i <= j <= k <= arr.Len().
    41  func reflectValueRWSlice3(arr reflect.Value, i, j, k int) reflect.Value {
    42  	if arr.Kind() != reflect.Array {
    43  		panic(fmt.Sprintf("arr has kind %v, wanted %v", arr.Kind(), reflect.Array))
    44  	}
    45  	if i < 0 || j < 0 || k < 0 {
    46  		panic(fmt.Sprintf("negative subscripts (%d, %d, %d)", i, j, k))
    47  	}
    48  	if i > j {
    49  		panic(fmt.Sprintf("subscript i (%d) > j (%d)", i, j))
    50  	}
    51  	if j > k {
    52  		panic(fmt.Sprintf("subscript j (%d) > k (%d)", j, k))
    53  	}
    54  	if k > arr.Len() {
    55  		panic(fmt.Sprintf("subscript k (%d) > array length (%d)", k, arr.Len()))
    56  	}
    57  
    58  	sliceTyp := reflect.SliceOf(arr.Type().Elem())
    59  	if i == arr.Len() {
    60  		// By precondition, i == j == k == arr.Len().
    61  		return reflect.MakeSlice(sliceTyp, 0, 0)
    62  	}
    63  	slh := reflect.SliceHeader{
    64  		// reflect.Value.CanAddr() == false for arrays, so we need to get the
    65  		// address from the first element of the array.
    66  		Data: arr.Index(i).UnsafeAddr(),
    67  		Len:  j - i,
    68  		Cap:  k - i,
    69  	}
    70  	slobj := reflect.NewAt(sliceTyp, unsafe.Pointer(&slh)).Elem()
    71  	// Before slobj is constructed, arr holds the only pointer-typed pointer to
    72  	// the array since reflect.SliceHeader.Data is a uintptr, so arr must be
    73  	// kept alive.
    74  	runtime.KeepAlive(arr)
    75  	return slobj
    76  }