diff options
5 files changed, 169 insertions, 100 deletions
diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobReader.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobReader.cs index 049e7ee013..0111bb0ca6 100644 --- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobReader.cs +++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobReader.cs @@ -16,7 +16,7 @@ namespace System.Reflection.Metadata /// <summary>An array containing the '\0' character.</summary> private static readonly char[] s_nullCharArray = new char[1] { '\0' }; - internal const int InvalidCompressedInteger = Int32.MaxValue; + internal const int InvalidCompressedInteger = int.MaxValue; private readonly MemoryBlock _block; @@ -90,9 +90,25 @@ namespace System.Reflection.Metadata public int Length => _block.Length; /// <summary> - /// Offset from start of underlying memory block to current position. + /// Gets or sets the offset from start of the blob to the current position. /// </summary> - public int Offset => (int)(_currentPointer - _block.Pointer); + /// <exception cref="BadImageFormatException">Offset is set outside the bounds of underlying reader.</exception> + public int Offset + { + get + { + return (int)(_currentPointer - _block.Pointer); + } + set + { + if (unchecked((uint)value) > (uint)_block.Length) + { + Throw.OutOfBounds(); + } + + _currentPointer = _block.Pointer + value; + } + } /// <summary> /// Bytes remaining from current position to end of underlying memory block. @@ -108,37 +124,6 @@ namespace System.Reflection.Metadata } /// <summary> - /// Repositions the reader to the given offset from the start of the underlying memory block. - /// </summary> - /// <exception cref="BadImageFormatException">Offset is outside the bounds of underlying reader.</exception> - public void SeekOffset(int offset) - { - if (!TrySeekOffset(offset)) - { - Throw.OutOfBounds(); - } - } - - internal bool TrySeekOffset(int offset) - { - if (unchecked((uint)offset) >= (uint)_block.Length) - { - return false; - } - - _currentPointer = _block.Pointer + offset; - return true; - } - - /// <summary> - /// Repositions the reader forward by the given number of bytes. - /// </summary> - public void SkipBytes(int count) - { - GetCurrentPointerAndAdvance(count); - } - - /// <summary> /// Repositions the reader forward by the number of bytes required to satisfy the given alignment. /// </summary> public void Align(byte alignment) diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs index 7bbbd1b6d3..a21dc44205 100644 --- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs +++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs @@ -153,7 +153,7 @@ namespace System.Reflection.Metadata } var ilBlock = reader.GetMemoryBlockAt(0, ilSize); - reader.SkipBytes(ilSize); + reader.Offset += ilSize; ImmutableArray<ExceptionRegion> exceptionHandlers; if (hasExceptionHandlers) @@ -174,7 +174,7 @@ namespace System.Reflection.Metadata } else { - reader.SkipBytes(2); // skip over reserved field + reader.Offset += 2; // skip over reserved field exceptionHandlers = ReadSmallExceptionHandlers(ref reader, dataSize / 12); } } diff --git a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs index a0d773194d..ebf5c898c9 100644 --- a/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs +++ b/src/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs @@ -63,6 +63,7 @@ namespace System.Reflection.Metadata /// <exception cref="ArgumentNullException"><paramref name="metadata"/> is null.</exception> /// <exception cref="ArgumentException">The encoding of <paramref name="utf8Decoder"/> is not <see cref="UTF8Encoding"/>.</exception> /// <exception cref="PlatformNotSupportedException">The current platform is big-endian.</exception> + /// <exception cref="BadImageFormatException">Bad metadata header.</exception> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { // Do not throw here when length is 0. We'll throw BadImageFormatException later on, so that the caller doesn't need to @@ -206,7 +207,7 @@ namespace System.Reflection.Metadata int numberOfBytesRead; versionString = memReader.GetMemoryBlockAt(0, versionStringSize).PeekUtf8NullTerminated(0, null, UTF8Decoder, out numberOfBytesRead, '\0'); - memReader.SkipBytes(versionStringSize); + memReader.Offset += versionStringSize; } private MetadataKind GetMetadataKind(string versionString) diff --git a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs index 8689738a58..02999c0251 100644 --- a/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs +++ b/src/System.Reflection.Metadata/tests/Metadata/MetadataReaderTests.cs @@ -2756,7 +2756,7 @@ namespace System.Reflection.Metadata.Tests blobReader.ReadUInt16(); // minor version blobReader.ReadUInt32(); // reserved int versionStringSize = blobReader.ReadInt32(); - blobReader.SkipBytes(versionStringSize); + blobReader.Offset += versionStringSize; // read stream headers to collect offsets and sizes to adjust later blobReader.ReadUInt16(); // reserved diff --git a/src/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs b/src/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs index 71a2c95d5b..5a1f0bae3c 100644 --- a/src/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs +++ b/src/System.Reflection.Metadata/tests/Utilities/BlobReaderTests.cs @@ -11,6 +11,100 @@ namespace System.Reflection.Metadata.Tests public class BlobReaderTests { [Fact] + public unsafe void Properties() + { + byte[] buffer = new byte[] { 0, 1, 0, 2, 5, 6 }; + + fixed (byte* bufferPtr = buffer) + { + var reader = new BlobReader(bufferPtr, 4); + Assert.True(reader.StartPointer == bufferPtr); + Assert.True(reader.CurrentPointer == bufferPtr); + Assert.Equal(0, reader.Offset); + Assert.Equal(4, reader.RemainingBytes); + Assert.Equal(4, reader.Length); + + Assert.Equal(0, reader.ReadByte()); + Assert.True(reader.StartPointer == bufferPtr); + Assert.True(reader.CurrentPointer == bufferPtr + 1); + Assert.Equal(1, reader.Offset); + Assert.Equal(3, reader.RemainingBytes); + Assert.Equal(4, reader.Length); + + Assert.Equal(1, reader.ReadInt16()); + Assert.True(reader.StartPointer == bufferPtr); + Assert.True(reader.CurrentPointer == bufferPtr + 3); + Assert.Equal(3, reader.Offset); + Assert.Equal(1, reader.RemainingBytes); + Assert.Equal(4, reader.Length); + + Assert.Throws<BadImageFormatException>(() => reader.ReadInt16()); + Assert.True(reader.StartPointer == bufferPtr); + Assert.True(reader.CurrentPointer == bufferPtr + 3); + Assert.Equal(3, reader.Offset); + Assert.Equal(1, reader.RemainingBytes); + Assert.Equal(4, reader.Length); + + Assert.Equal(2, reader.ReadByte()); + Assert.True(reader.StartPointer == bufferPtr); + Assert.True(reader.CurrentPointer == bufferPtr + 4); + Assert.Equal(4, reader.Offset); + Assert.Equal(0, reader.RemainingBytes); + Assert.Equal(4, reader.Length); + } + } + + [Fact] + public unsafe void Offset() + { + byte[] buffer = new byte[] { 0, 1, 0, 2, 5, 6 }; + + fixed (byte* bufferPtr = buffer) + { + var reader = new BlobReader(bufferPtr, 4); + Assert.Equal(0, reader.Offset); + + reader.Offset = 0; + Assert.Equal(0, reader.Offset); + Assert.Equal(4, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr); + + reader.Offset = 3; + Assert.Equal(3, reader.Offset); + Assert.Equal(1, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 3); + + reader.Offset = 1; + Assert.Equal(1, reader.Offset); + Assert.Equal(3, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 1); + + Assert.Equal(1, reader.ReadByte()); + Assert.Equal(2, reader.Offset); + Assert.Equal(2, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 2); + + reader.Offset = 4; + Assert.Equal(4, reader.Offset); + Assert.Equal(0, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 4); + + Assert.Throws<BadImageFormatException>(() => reader.Offset = 5); + Assert.Equal(4, reader.Offset); + Assert.Equal(0, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 4); + + Assert.Throws<BadImageFormatException>(() => reader.Offset = -1); + Assert.Equal(4, reader.Offset); + Assert.Equal(0, reader.RemainingBytes); + Assert.True(reader.CurrentPointer == bufferPtr + 4); + + Assert.Throws<BadImageFormatException>(() => reader.Offset = int.MaxValue); + Assert.Throws<BadImageFormatException>(() => reader.Offset = int.MinValue); + } + } + + [Fact] public unsafe void PublicBlobReaderCtorValidatesArgs() { byte* bufferPtrForLambda; @@ -52,163 +146,152 @@ namespace System.Reflection.Metadata.Tests { var reader = new BlobReader(new MemoryBlock(bufferPtr, buffer.Length)); - Assert.False(reader.TrySeekOffset(-1)); - Assert.False(reader.TrySeekOffset(Int32.MaxValue)); - Assert.False(reader.TrySeekOffset(Int32.MinValue)); - Assert.False(reader.TrySeekOffset(buffer.Length)); - Assert.True(reader.TrySeekOffset(buffer.Length - 1)); - - Assert.True(reader.TrySeekOffset(0)); Assert.Equal(0, reader.Offset); Assert.Throws<BadImageFormatException>(() => reader.ReadUInt64()); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(1)); - Assert.Equal(1, reader.Offset); + reader.Offset = 1; Assert.Throws<BadImageFormatException>(() => reader.ReadDouble()); Assert.Equal(1, reader.Offset); - Assert.True(reader.TrySeekOffset(2)); - Assert.Equal(2, reader.Offset); + reader.Offset = 2; Assert.Throws<BadImageFormatException>(() => reader.ReadUInt32()); Assert.Equal((ushort)0x0200, reader.ReadUInt16()); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(2)); - Assert.Equal(2, reader.Offset); + reader.Offset = 2; Assert.Throws<BadImageFormatException>(() => reader.ReadSingle()); Assert.Equal(2, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Equal(9.404242E-38F, reader.ReadSingle()); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(3)); - Assert.Equal(3, reader.Offset); + reader.Offset = 3; Assert.Throws<BadImageFormatException>(() => reader.ReadUInt16()); Assert.Equal((byte)0x02, reader.ReadByte()); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Equal("\u0000\u0001\u0000\u0002", reader.ReadUTF8(4)); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadUTF8(5)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadUTF8(-1)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Equal("\u0100\u0200", reader.ReadUTF16(4)); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadUTF16(5)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadUTF16(-1)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadUTF16(6)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Equal(buffer, reader.ReadBytes(4)); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); - Assert.Same(String.Empty, reader.ReadUtf8NullTerminated()); + reader.Offset = 0; + Assert.Same(string.Empty, reader.ReadUtf8NullTerminated()); Assert.Equal(1, reader.Offset); - Assert.True(reader.TrySeekOffset(1)); + reader.Offset = 1; Assert.Equal("\u0001", reader.ReadUtf8NullTerminated()); Assert.Equal(3, reader.Offset); - Assert.True(reader.TrySeekOffset(3)); + reader.Offset = 3; Assert.Equal("\u0002", reader.ReadUtf8NullTerminated()); Assert.Equal(4, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); - Assert.Same(String.Empty, reader.ReadUtf8NullTerminated()); + reader.Offset = 0; + Assert.Same(string.Empty, reader.ReadUtf8NullTerminated()); Assert.Equal(1, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.ReadBytes(5)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); - Assert.Throws<BadImageFormatException>(() => reader.ReadBytes(Int32.MinValue)); + reader.Offset = 0; + Assert.Throws<BadImageFormatException>(() => reader.ReadBytes(int.MinValue)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.GetMemoryBlockAt(-1, 1)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Throws<BadImageFormatException>(() => reader.GetMemoryBlockAt(1, -1)); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(0)); + reader.Offset = 0; Assert.Equal(3, reader.GetMemoryBlockAt(1, 3).Length); Assert.Equal(0, reader.Offset); - Assert.True(reader.TrySeekOffset(3)); + reader.Offset = 3; reader.ReadByte(); Assert.Equal(4, reader.Offset); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Equal(0, reader.ReadBytes(0).Length); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; int value; Assert.False(reader.TryReadCompressedInteger(out value)); Assert.Equal(BlobReader.InvalidCompressedInteger, value); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadCompressedInteger()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Equal(SerializationTypeCode.Invalid, reader.ReadSerializationTypeCode()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Equal(SignatureTypeCode.Invalid, reader.ReadSignatureTypeCode()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Equal(default(EntityHandle), reader.ReadTypeHandle()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadBoolean()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadByte()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadSByte()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadUInt32()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadInt32()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadUInt64()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadInt64()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadSingle()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; Assert.Throws<BadImageFormatException>(() => reader.ReadDouble()); - Assert.Equal(4, reader.Offset); + reader.Offset = 4; } byte[] buffer2 = new byte[8] { 1, 2, 3, 4, 5, 6, 7, 8 }; @@ -266,34 +349,34 @@ namespace System.Reflection.Metadata.Tests { var block = new MemoryBlock(bufferPtr, buffer.Length); - Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(Int32.MaxValue)); + Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(int.MaxValue)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(-1)); - Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(Int32.MinValue)); + Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(int.MinValue)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(4)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(1)); Assert.Equal(0x02000100U, block.PeekUInt32(0)); - Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(Int32.MaxValue)); + Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(int.MaxValue)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(-1)); - Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(Int32.MinValue)); + Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(int.MinValue)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(4)); Assert.Equal(0x0200, block.PeekUInt16(2)); int bytesRead; MetadataStringDecoder stringDecoder = MetadataStringDecoder.DefaultUTF8; - Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(Int32.MaxValue, null, stringDecoder, out bytesRead)); + Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(int.MaxValue, null, stringDecoder, out bytesRead)); Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(-1, null, stringDecoder, out bytesRead)); - Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(Int32.MinValue, null, stringDecoder, out bytesRead)); + Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(int.MinValue, null, stringDecoder, out bytesRead)); Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(5, null, stringDecoder, out bytesRead)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-1, 1)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(1, -1)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(0, -1)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-1, 0)); - Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-Int32.MaxValue, Int32.MaxValue)); - Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(Int32.MaxValue, -Int32.MaxValue)); - Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(Int32.MaxValue, Int32.MaxValue)); + Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-int.MaxValue, int.MaxValue)); + Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(int.MaxValue, -int.MaxValue)); + Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(int.MaxValue, int.MaxValue)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(block.Length, -1)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-1, block.Length)); |