예제 #1
0
        /// <summary>
        /// Interprets a pointer within the current segment as capability pointer and returns the according low-level capability object from
        /// the capability table. Does not mutate this state.
        /// </summary>
        /// <param name="offset">Offset relative to this.Offset within current segment</param>
        /// <returns>the low-level capability object</returns>
        /// <exception cref="IndexOutOfRangeException">offset negative or out of range</exception>
        /// <exception cref="InvalidOperationException">capability table not set</exception>
        /// <exception cref="Rpc.RpcException">not a capability pointer or invalid capability index</exception>
        internal Rpc.ConsumedCapability DecodeCapPointer(int offset)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException(nameof(offset));
            }

            if (Caps == null)
            {
                throw new InvalidOperationException("Capbility table not set");
            }

            WirePointer pointer = CurrentSegment[Offset + offset];

            if (pointer.IsNull)
            {
                // Despite this behavior is not officially specified,
                // the official C++ implementation seems to send null pointers for null caps.
                return(null);
            }

            if (pointer.Kind != PointerKind.Other)
            {
                throw new Rpc.RpcException("Expected a capability pointer, but got something different");
            }

            if (pointer.CapabilityIndex >= Caps.Count)
            {
                throw new Rpc.RpcException("Capability index out of range");
            }

            return(Caps[(int)pointer.CapabilityIndex]);
        }
예제 #2
0
        /// <summary>
        /// Interprets a pointer within the current segment and mutates this state to represent the pointer's target.
        /// </summary>
        /// <param name="offset">word offset relative to this.Offset within current segment</param>
        /// <exception cref="IndexOutOfRangeException">offset negative or out of range</exception>
        /// <exception cref="DeserializationException">invalid pointer data or traversal limit exceeded</exception>
        internal void DecodePointer(int offset)
        {
            if (offset < 0)
            {
                throw new IndexOutOfRangeException(nameof(offset));
            }

            WirePointer pointer = CurrentSegment[Offset + offset];

            int derefCount = 0;

            do
            {
                if (pointer.IsNull)
                {
                    this = default;
                    return;
                }

                switch (pointer.Kind)
                {
                case PointerKind.Struct:
                    Offset = checked (pointer.Offset + Offset + offset + 1);
                    IncrementBytesTraversed(checked (8u * pointer.StructSize));
                    StructDataCount = pointer.StructDataCount;
                    StructPtrCount  = pointer.StructPtrCount;
                    Kind            = ObjectKind.Struct;
                    Validate();
                    return;

                case PointerKind.List:
                    Offset           = checked (pointer.Offset + Offset + offset + 1);
                    ListElementCount = pointer.ListElementCount;
                    StructDataCount  = 0;
                    StructPtrCount   = 0;

                    switch (pointer.ListKind)
                    {
                    case ListKind.ListOfEmpty:         // e.g. List(void)
                                                       // the “traversal limit” should count a list of zero-sized elements as if each element were one word instead.
                        IncrementBytesTraversed(checked (8u * (uint)ListElementCount));
                        Kind = ObjectKind.ListOfEmpty;
                        break;

                    case ListKind.ListOfBits:
                        IncrementBytesTraversed(checked ((uint)ListElementCount + 7) / 8);
                        Kind = ObjectKind.ListOfBits;
                        break;

                    case ListKind.ListOfBytes:
                        IncrementBytesTraversed((uint)ListElementCount);
                        Kind = ObjectKind.ListOfBytes;
                        break;

                    case ListKind.ListOfShorts:
                        IncrementBytesTraversed(checked (2u * (uint)ListElementCount));
                        Kind = ObjectKind.ListOfShorts;
                        break;

                    case ListKind.ListOfInts:
                        IncrementBytesTraversed(checked (4u * (uint)ListElementCount));
                        Kind = ObjectKind.ListOfInts;
                        break;

                    case ListKind.ListOfLongs:
                        IncrementBytesTraversed(checked (8u * (uint)ListElementCount));
                        Kind = ObjectKind.ListOfLongs;
                        break;

                    case ListKind.ListOfPointers:
                        IncrementBytesTraversed(checked (8u * (uint)ListElementCount));
                        Kind = ObjectKind.ListOfPointers;
                        break;

                    case ListKind.ListOfStructs:
                    {
                        WirePointer tag = CurrentSegment[Offset];
                        if (tag.Kind != PointerKind.Struct)
                        {
                            throw new DeserializationException("Unexpected: List of composites with non-struct type tag");
                        }
                        IncrementBytesTraversed(checked (8u * (uint)pointer.ListElementCount + 8u));
                        ListElementCount = tag.ListOfStructsElementCount;
                        StructDataCount  = tag.StructDataCount;
                        StructPtrCount   = tag.StructPtrCount;
                        Kind             = ObjectKind.ListOfStructs;
                    }
                    break;

                    default:
                        throw new InvalidProgramException();
                    }
                    Validate();
                    return;

                case PointerKind.Far:

                    if (pointer.IsDoubleFar)
                    {
                        CurrentSegmentIndex = pointer.TargetSegmentIndex;
                        Offset = 0;

                        WirePointer pointer1 = CurrentSegment[pointer.LandingPadOffset];
                        if (pointer1.Kind != PointerKind.Far || pointer1.IsDoubleFar)
                        {
                            throw new DeserializationException("Error decoding double-far pointer: convention broken");
                        }

                        WirePointer pointer2 = CurrentSegment[pointer.LandingPadOffset + 1];
                        if (pointer2.Kind == PointerKind.Far)
                        {
                            throw new DeserializationException("Error decoding double-far pointer: not followed by intra-segment pointer");
                        }

                        CurrentSegmentIndex = pointer1.TargetSegmentIndex;
                        Offset  = 0;
                        pointer = pointer2;
                        offset  = -1;
                    }
                    else
                    {
                        CurrentSegmentIndex = pointer.TargetSegmentIndex;
                        Offset  = 0;
                        offset  = pointer.LandingPadOffset;
                        pointer = CurrentSegment[pointer.LandingPadOffset];
                    }
                    continue;

                case PointerKind.Other:
                    var tmp = Caps;
                    this = default;
                    Caps = tmp;
                    Kind = ObjectKind.Capability;
                    BytesTraversedOrData = pointer.CapabilityIndex;
                    return;

                default:
                    throw new InvalidProgramException();
                }
            } while (++derefCount < SecurityOptions.RecursionLimit);

            throw new DeserializationException("Recursion limit reached while decoding a pointer");
        }