예제 #1
0
        // -------------------------
        // Implementation rationale
        // -------------------------
        //
        // Objects in .NET are implemented as a single memory region containing all fields and are referenced by
        // a single pointer to the first byte of the object. Getting and setting field values of an object is done
        // by reading from this base pointer + the field offset. In C this would be something like the following:
        //
        //    *(MyFieldType*) (ptr_to_TypeA_object + offset_MyField);
        //
        // or using pointer notation:
        //
        //    ptr_to_TypeA_object->MyField
        //
        // Although C# represents itself as a type-safe language, CIL is not. As a result, it is possible for a
        // ldfld instruction to perform type confusion, and read "non-existing" fields from a type, by pushing
        // an object reference of type A, and referencing a field from another type B in the  operand of the
        // ldfld instruction. For example, the following CIL snippet runs fine:
        //
        //     newobj     void TypeA::.ctor()
        //     ldfld      MyFieldType TypeB::MyField
        //
        // The runtime (tested on Mono and .NET Core) will reinterpret the pushed object as TypeB, even though it is
        // a pointer to TypeA, and use the field offset as if it was actually an instance of TypeB:
        //
        //    ((TypeB*) ptr_to_TypeA_object)->MyField
        //
        // which is equivalent to:
        //
        //    *(MyFieldType*) (ptr_to_TypeA_object + offset_MyField))
        //
        // For this reason, we do not store the memory type layout of the current object within this class, but rather
        // query the memory allocator that was used to create this LLE object for the memory layout of the field's
        // declaring type.

        /// <inheritdoc />
        public IConcreteValue GetFieldValue(IFieldDescriptor field)
        {
            var typeMemoryLayout  = _memoryAllocator.GetTypeMemoryLayout(field.DeclaringType);
            var fieldMemoryLayout = typeMemoryLayout[field.Resolve()];

            return(this.ReadStruct((int)fieldMemoryLayout.Offset, _memoryAllocator, fieldMemoryLayout.ContentsLayout));
        }
예제 #2
0
        /// <inheritdoc />
        public void SetFieldValue(IFieldDescriptor field, IConcreteValue value)
        {
            var typeMemoryLayout  = _memoryAllocator.GetTypeMemoryLayout(field.DeclaringType);
            var fieldMemoryLayout = typeMemoryLayout[field.Resolve()];

            this.WriteStruct((int)fieldMemoryLayout.Offset, _memoryAllocator, fieldMemoryLayout.ContentsLayout, value);
        }
예제 #3
0
        private IConcreteValue GetInitialFieldValue(IFieldDescriptor field)
        {
            var definition = field.Resolve();

            if (definition != null)
            {
                // Check if the field has an initial value through a Constant row.
                var constant = definition.Constant;
                if (constant?.Value != null)
                {
                    return(ObjectToCtsValue(
                               constant.Value.Data,
                               definition.Module.CorLibTypeFactory.FromElementType(constant.Type)));
                }

                // Check if the field has an initial value through a field RVA row.
                if (definition.HasFieldRva && definition.FieldRva != null &&
                    definition.FieldRva is IReadableSegment readableSegment)
                {
                    return(ObjectToCtsValue(
                               readableSegment.ToArray(),
                               field.Signature.FieldType));
                }
            }

            return(_valueFactory.CreateValue(field.Signature.FieldType, false));
        }