github.com/nicocha30/gvisor-ligolo@v0.0.0-20230726075806-989fa2c0a413/pkg/state/types.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 "reflect" 19 "sort" 20 21 "github.com/nicocha30/gvisor-ligolo/pkg/state/wire" 22 ) 23 24 // assertValidType asserts that the type is valid. 25 func assertValidType(name string, fields []string) { 26 if name == "" { 27 Failf("type has empty name") 28 } 29 fieldsCopy := make([]string, len(fields)) 30 for i := 0; i < len(fields); i++ { 31 if fields[i] == "" { 32 Failf("field has empty name for type %q", name) 33 } 34 fieldsCopy[i] = fields[i] 35 } 36 sort.Slice(fieldsCopy, func(i, j int) bool { 37 return fieldsCopy[i] < fieldsCopy[j] 38 }) 39 for i := range fieldsCopy { 40 if i > 0 && fieldsCopy[i-1] == fieldsCopy[i] { 41 Failf("duplicate field %q for type %s", fieldsCopy[i], name) 42 } 43 } 44 } 45 46 // typeEntry is an entry in the typeDatabase. 47 type typeEntry struct { 48 ID typeID 49 wire.Type 50 } 51 52 // reconciledTypeEntry is a reconciled entry in the typeDatabase. 53 type reconciledTypeEntry struct { 54 wire.Type 55 LocalType reflect.Type 56 FieldOrder []int 57 } 58 59 // typeEncodeDatabase is an internal TypeInfo database for encoding. 60 type typeEncodeDatabase struct { 61 // byType maps by type to the typeEntry. 62 byType map[reflect.Type]*typeEntry 63 64 // lastID is the last used ID. 65 lastID typeID 66 } 67 68 // makeTypeEncodeDatabase makes a typeDatabase. 69 func makeTypeEncodeDatabase() typeEncodeDatabase { 70 return typeEncodeDatabase{ 71 byType: make(map[reflect.Type]*typeEntry), 72 } 73 } 74 75 // typeDecodeDatabase is an internal TypeInfo database for decoding. 76 type typeDecodeDatabase struct { 77 // byID maps by ID to type. 78 byID []*reconciledTypeEntry 79 80 // pending are entries that are pending validation by Lookup. These 81 // will be reconciled with actual objects. Note that these will also be 82 // used to lookup types by name, since they may not be reconciled and 83 // there's little value to deleting from this map. 84 pending []*wire.Type 85 } 86 87 // makeTypeDecodeDatabase makes a typeDatabase. 88 func makeTypeDecodeDatabase() typeDecodeDatabase { 89 return typeDecodeDatabase{} 90 } 91 92 // lookupNameFields extracts the name and fields from an object. 93 func lookupNameFields(typ reflect.Type) (string, []string, bool) { 94 v := reflect.Zero(reflect.PtrTo(typ)).Interface() 95 t, ok := v.(Type) 96 if !ok { 97 // Is this a primitive? 98 if typ.Kind() == reflect.Interface { 99 return interfaceType, nil, true 100 } 101 name := typ.Name() 102 if _, ok := primitiveTypeDatabase[name]; !ok { 103 // This is not a known type, and not a primitive. The 104 // encoder may proceed for anonymous empty structs, or 105 // it may deference the type pointer and try again. 106 return "", nil, false 107 } 108 return name, nil, true 109 } 110 // Sanity check the type. 111 if raceEnabled { 112 if _, ok := reverseTypeDatabase[typ]; !ok { 113 // The type was not registered? Must be an embedded 114 // structure or something else. 115 return "", nil, false 116 } 117 } 118 // Extract the name from the object. 119 name := t.StateTypeName() 120 fields := t.StateFields() 121 assertValidType(name, fields) 122 return name, fields, true 123 } 124 125 // Lookup looks up or registers the given object. 126 // 127 // The bool indicates whether this is an existing entry: false means the entry 128 // did not exist, and true means the entry did exist. If this bool is false and 129 // the returned typeEntry are nil, then the obj did not implement the Type 130 // interface. 131 func (tdb *typeEncodeDatabase) Lookup(typ reflect.Type) (*typeEntry, bool) { 132 te, ok := tdb.byType[typ] 133 if !ok { 134 // Lookup the type information. 135 name, fields, ok := lookupNameFields(typ) 136 if !ok { 137 // Empty structs may still be encoded, so let the 138 // caller decide what to do from here. 139 return nil, false 140 } 141 142 // Register the new type. 143 tdb.lastID++ 144 te = &typeEntry{ 145 ID: tdb.lastID, 146 Type: wire.Type{ 147 Name: name, 148 Fields: fields, 149 }, 150 } 151 152 // All done. 153 tdb.byType[typ] = te 154 return te, false 155 } 156 return te, true 157 } 158 159 // Register adds a typeID entry. 160 func (tbd *typeDecodeDatabase) Register(typ *wire.Type) { 161 assertValidType(typ.Name, typ.Fields) 162 tbd.pending = append(tbd.pending, typ) 163 } 164 165 // LookupName looks up the type name by ID. 166 func (tbd *typeDecodeDatabase) LookupName(id typeID) string { 167 if len(tbd.pending) < int(id) { 168 // This is likely an encoder error? 169 Failf("type ID %d not available", id) 170 } 171 return tbd.pending[id-1].Name 172 } 173 174 // LookupType looks up the type by ID. 175 func (tbd *typeDecodeDatabase) LookupType(id typeID) reflect.Type { 176 name := tbd.LookupName(id) 177 typ, ok := globalTypeDatabase[name] 178 if !ok { 179 // If not available, see if it's primitive. 180 typ, ok = primitiveTypeDatabase[name] 181 if !ok && name == interfaceType { 182 // Matches the built-in interface type. 183 var i any 184 return reflect.TypeOf(&i).Elem() 185 } 186 if !ok { 187 // The type is perhaps not registered? 188 Failf("type name %q is not available", name) 189 } 190 return typ // Primitive type. 191 } 192 return typ // Registered type. 193 } 194 195 // singleFieldOrder defines the field order for a single field. 196 var singleFieldOrder = []int{0} 197 198 // Lookup looks up or registers the given object. 199 // 200 // First, the typeID is searched to see if this has already been appropriately 201 // reconciled. If no, then a reconcilation will take place that may result in a 202 // field ordering. If a nil reconciledTypeEntry is returned from this method, 203 // then the object does not support the Type interface. 204 // 205 // This method never returns nil. 206 func (tbd *typeDecodeDatabase) Lookup(id typeID, typ reflect.Type) *reconciledTypeEntry { 207 if len(tbd.byID) > int(id) && tbd.byID[id-1] != nil { 208 // Already reconciled. 209 return tbd.byID[id-1] 210 } 211 // The ID has not been reconciled yet. That's fine. We need to make 212 // sure it aligns with the current provided object. 213 if len(tbd.pending) < int(id) { 214 // This id was never registered. Probably an encoder error? 215 Failf("typeDatabase does not contain id %d", id) 216 } 217 // Extract the pending info. 218 pending := tbd.pending[id-1] 219 // Grow the byID list. 220 if len(tbd.byID) < int(id) { 221 tbd.byID = append(tbd.byID, make([]*reconciledTypeEntry, int(id)-len(tbd.byID))...) 222 } 223 // Reconcile the type. 224 name, fields, ok := lookupNameFields(typ) 225 if !ok { 226 // Empty structs are decoded only when the type is nil. Since 227 // this isn't the case, we fail here. 228 Failf("unsupported type %q during decode; can't reconcile", pending.Name) 229 } 230 if name != pending.Name { 231 // Are these the same type? Print a helpful message as this may 232 // actually happen in practice if types change. 233 Failf("typeDatabase contains conflicting definitions for id %d: %s->%v (current) and %s->%v (existing)", 234 id, name, fields, pending.Name, pending.Fields) 235 } 236 rte := &reconciledTypeEntry{ 237 Type: wire.Type{ 238 Name: name, 239 Fields: fields, 240 }, 241 LocalType: typ, 242 } 243 // If there are zero or one fields, then we skip allocating the field 244 // slice. There is special handling for decoding in this case. If the 245 // field name does not match, it will be caught in the general purpose 246 // code below. 247 if len(fields) != len(pending.Fields) { 248 Failf("type %q contains different fields: %v (decode) and %v (encode)", 249 name, fields, pending.Fields) 250 } 251 if len(fields) == 0 { 252 tbd.byID[id-1] = rte // Save. 253 return rte 254 } 255 if len(fields) == 1 && fields[0] == pending.Fields[0] { 256 tbd.byID[id-1] = rte // Save. 257 rte.FieldOrder = singleFieldOrder 258 return rte 259 } 260 // For each field in the current object's information, match it to a 261 // field in the destination object. We know from the assertion above 262 // and the insertion on insertion to pending that neither field 263 // contains any duplicates. 264 fieldOrder := make([]int, len(fields)) 265 for i, name := range fields { 266 fieldOrder[i] = -1 // Sentinel. 267 // Is it an exact match? 268 if pending.Fields[i] == name { 269 fieldOrder[i] = i 270 continue 271 } 272 // Find the matching field. 273 for j, otherName := range pending.Fields { 274 if name == otherName { 275 fieldOrder[i] = j 276 break 277 } 278 } 279 if fieldOrder[i] == -1 { 280 // The type name matches but we are lacking some common fields. 281 Failf("type %q has mismatched fields: %v (decode) and %v (encode)", 282 name, fields, pending.Fields) 283 } 284 } 285 // The type has been reeconciled. 286 rte.FieldOrder = fieldOrder 287 tbd.byID[id-1] = rte 288 return rte 289 } 290 291 // interfaceType defines all interfaces. 292 const interfaceType = "interface" 293 294 // primitiveTypeDatabase is a set of fixed types. 295 var primitiveTypeDatabase = func() map[string]reflect.Type { 296 r := make(map[string]reflect.Type) 297 for _, t := range []reflect.Type{ 298 reflect.TypeOf(false), 299 reflect.TypeOf(int(0)), 300 reflect.TypeOf(int8(0)), 301 reflect.TypeOf(int16(0)), 302 reflect.TypeOf(int32(0)), 303 reflect.TypeOf(int64(0)), 304 reflect.TypeOf(uint(0)), 305 reflect.TypeOf(uintptr(0)), 306 reflect.TypeOf(uint8(0)), 307 reflect.TypeOf(uint16(0)), 308 reflect.TypeOf(uint32(0)), 309 reflect.TypeOf(uint64(0)), 310 reflect.TypeOf(""), 311 reflect.TypeOf(float32(0.0)), 312 reflect.TypeOf(float64(0.0)), 313 reflect.TypeOf(complex64(0.0)), 314 reflect.TypeOf(complex128(0.0)), 315 } { 316 r[t.Name()] = t 317 } 318 return r 319 }() 320 321 // globalTypeDatabase is used for dispatching interfaces on decode. 322 var globalTypeDatabase = map[string]reflect.Type{} 323 324 // reverseTypeDatabase is a reverse mapping. 325 var reverseTypeDatabase = map[reflect.Type]string{} 326 327 // Release releases references to global type databases. 328 // Must only be called in contexts where they will definitely never be used, 329 // in order to save memory. 330 func Release() { 331 globalTypeDatabase = nil 332 reverseTypeDatabase = nil 333 } 334 335 // Register registers a type. 336 // 337 // This must be called on init and only done once. 338 func Register(t Type) { 339 name := t.StateTypeName() 340 typ := reflect.TypeOf(t) 341 if raceEnabled { 342 assertValidType(name, t.StateFields()) 343 // Register must always be called on pointers. 344 if typ.Kind() != reflect.Ptr { 345 Failf("Register must be called on pointers") 346 } 347 } 348 typ = typ.Elem() 349 if raceEnabled { 350 if typ.Kind() == reflect.Struct { 351 // All registered structs must implement SaverLoader. We allow 352 // the registration is non-struct types with just the Type 353 // interface, but we need to call StateSave/StateLoad methods 354 // on aggregate types. 355 if _, ok := t.(SaverLoader); !ok { 356 Failf("struct %T does not implement SaverLoader", t) 357 } 358 } else { 359 // Non-structs must not have any fields. We don't support 360 // calling StateSave/StateLoad methods on any non-struct types. 361 // If custom behavior is required, these types should be 362 // wrapped in a structure of some kind. 363 if fields := t.StateFields(); len(fields) != 0 { 364 Failf("non-struct %T has non-zero fields %v", t, fields) 365 } 366 // We don't allow non-structs to implement StateSave/StateLoad 367 // methods, because they won't be called and it's confusing. 368 if _, ok := t.(SaverLoader); ok { 369 Failf("non-struct %T implements SaverLoader", t) 370 } 371 } 372 if _, ok := primitiveTypeDatabase[name]; ok { 373 Failf("conflicting primitiveTypeDatabase entry for %T: used by primitive", t) 374 } 375 if _, ok := globalTypeDatabase[name]; ok { 376 Failf("conflicting globalTypeDatabase entries for %T: name conflict", t) 377 } 378 if name == interfaceType { 379 Failf("conflicting name for %T: matches interfaceType", t) 380 } 381 reverseTypeDatabase[typ] = name 382 } 383 globalTypeDatabase[name] = typ 384 }