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  }