github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/tools/go_marshal/analysis/analysis_unsafe.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 analysis implements common functionality used by generated 16 // go_marshal tests. 17 package analysis 18 19 // All functions in this package are unsafe and are not intended for general 20 // consumption. They contain sharp edge cases and the caller is responsible for 21 // ensuring none of them are hit. Callers must be carefully to pass in only sane 22 // arguments. Failure to do so may cause panics at best and arbitrary memory 23 // corruption at worst. 24 // 25 // Never use outside of tests. 26 27 import ( 28 "fmt" 29 "math/rand" 30 "reflect" 31 "testing" 32 "unsafe" 33 ) 34 35 // RandomizeValue assigns random value(s) to an abitrary type. This is intended 36 // for used with ABI structs from go_marshal, meaning the typical restrictions 37 // apply (fixed-size types, no pointers, maps, channels, etc), and should only 38 // be used on zeroed values to avoid overwriting pointers to active go objects. 39 // 40 // Internally, we populate the type with random data by doing an unsafe cast to 41 // access the underlying memory of the type and filling it as if it were a byte 42 // slice. This almost gets us what we want, but padding fields named "_" are 43 // normally not accessible, so we walk the type and recursively zero all "_" 44 // fields. 45 // 46 // Precondition: x must be a pointer. x must not contain any valid 47 // pointers to active go objects (pointer fields aren't allowed in ABI 48 // structs anyways), or we'd be violating the go runtime contract and 49 // the GC may malfunction. 50 func RandomizeValue(x interface{}) { 51 v := reflect.Indirect(reflect.ValueOf(x)) 52 if !v.CanSet() { 53 panic("RandomizeType() called with an unaddressable value. You probably need to pass a pointer to the argument") 54 } 55 56 // Cast the underlying memory for the type into a byte slice. 57 var b []byte 58 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&b)) 59 // Note: v.UnsafeAddr panics if x is passed by value. x should be a pointer. 60 hdr.Data = v.UnsafeAddr() 61 hdr.Len = int(v.Type().Size()) 62 hdr.Cap = hdr.Len 63 64 // Fill the byte slice with random data, which in effect fills the type with 65 // random values. 66 n, err := rand.Read(b) 67 if err != nil || n != len(b) { 68 panic("unreachable") 69 } 70 71 // Normally, padding fields are not accessible, so zero them out. 72 reflectZeroPaddingFields(v.Type(), b, false) 73 } 74 75 // reflectZeroPaddingFields assigns zero values to padding fields for the value 76 // of type r, represented by the memory in data. Padding fields are defined as 77 // fields with the name "_". If zero is true, the immediate value itself is 78 // zeroed. In addition, the type is recursively scanned for padding fields in 79 // inner types. 80 // 81 // This is used for zeroing padding fields after calling RandomizeValue. 82 func reflectZeroPaddingFields(r reflect.Type, data []byte, zero bool) { 83 if zero { 84 for i := range data { 85 data[i] = 0 86 } 87 } 88 switch r.Kind() { 89 case reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16, reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64: 90 // These types are explicitly allowed in an ABI type, but we don't need 91 // to recurse further as they're scalar types. 92 case reflect.Struct: 93 for i, numFields := 0, r.NumField(); i < numFields; i++ { 94 f := r.Field(i) 95 off := f.Offset 96 len := f.Type.Size() 97 window := data[off : off+len] 98 reflectZeroPaddingFields(f.Type, window, f.Name == "_") 99 } 100 case reflect.Array: 101 eLen := int(r.Elem().Size()) 102 if int(r.Size()) != eLen*r.Len() { 103 panic("Array has unexpected size?") 104 } 105 for i, n := 0, r.Len(); i < n; i++ { 106 reflectZeroPaddingFields(r.Elem(), data[i*eLen:(i+1)*eLen], false) 107 } 108 default: 109 panic(fmt.Sprintf("Type %v not allowed in ABI struct", r.Kind())) 110 111 } 112 } 113 114 // AlignmentCheck ensures the definition of the type represented by typ doesn't 115 // cause the go compiler to emit implicit padding between elements of the type 116 // (i.e. fields in a struct). 117 // 118 // AlignmentCheck doesn't explicitly recurse for embedded structs because any 119 // struct present in an ABI struct must also be Marshallable, and therefore 120 // they're aligned by definition (or their alignment check would have failed). 121 func AlignmentCheck(t *testing.T, typ reflect.Type) (ok bool, delta uint64) { 122 switch typ.Kind() { 123 case reflect.Int8, reflect.Uint8, reflect.Int16, reflect.Uint16, reflect.Int32, reflect.Uint32, reflect.Int64, reflect.Uint64: 124 // Primitive types are always considered well aligned. Primitive types 125 // that are fields in structs are checked independently, this branch 126 // exists to handle recursive calls to alignmentCheck. 127 case reflect.Struct: 128 xOff := 0 129 nextXOff := 0 130 skipNext := false 131 for i, numFields := 0, typ.NumField(); i < numFields; i++ { 132 xOff = nextXOff 133 f := typ.Field(i) 134 fmt.Printf("Checking alignment of %s.%s @ %d [+%d]...\n", typ.Name(), f.Name, f.Offset, f.Type.Size()) 135 nextXOff = int(f.Offset + f.Type.Size()) 136 137 if f.Name == "_" { 138 // Padding fields need not be aligned. 139 fmt.Printf("Padding field of type %v\n", f.Type) 140 continue 141 } 142 143 if tag, ok := f.Tag.Lookup("marshal"); ok && tag == "unaligned" { 144 skipNext = true 145 continue 146 } 147 148 if skipNext { 149 skipNext = false 150 fmt.Printf("Skipping alignment check for field %s.%s explicitly marked as unaligned.\n", typ.Name(), f.Name) 151 continue 152 } 153 154 if xOff != int(f.Offset) { 155 implicitPad := int(f.Offset) - xOff 156 t.Fatalf("Suspect offset for field %s.%s, detected an implicit %d byte padding from offset %d to %d; either add %d bytes of explicit padding before this field or tag it as `marshal:\"unaligned\"`.", typ.Name(), f.Name, implicitPad, xOff, f.Offset, implicitPad) 157 } 158 } 159 160 // Ensure structs end on a byte explicitly defined by the type. 161 if typ.NumField() > 0 && nextXOff != int(typ.Size()) { 162 implicitPad := int(typ.Size()) - nextXOff 163 f := typ.Field(typ.NumField() - 1) // Final field 164 if tag, ok := f.Tag.Lookup("marshal"); ok && tag == "unaligned" { 165 // Final field explicitly marked unaligned. 166 break 167 } 168 t.Fatalf("Suspect offset for field %s.%s at the end of %s, detected an implicit %d byte padding from offset %d to %d at the end of the struct; either add %d bytes of explict padding at end of the struct or tag the final field %s as `marshal:\"unaligned\"`.", 169 typ.Name(), f.Name, typ.Name(), implicitPad, nextXOff, typ.Size(), implicitPad, f.Name) 170 } 171 case reflect.Array: 172 // Independent arrays are also always considered well aligned. We only 173 // need to worry about their alignment when they're embedded in structs, 174 // which we handle above. 175 default: 176 t.Fatalf("Unsupported type in ABI struct while checking for field alignment for type: %v", typ.Kind()) 177 } 178 return true, uint64(typ.Size()) 179 }