internal BlobReader(MemoryBlock block) { Debug.Assert(BitConverter.IsLittleEndian && block.Length >= 0 && (block.Pointer != null || block.Length == 0)); _block = block; _currentPointer = block.Pointer; _endPointer = block.Pointer + block.Length; }
public unsafe void DefaultDecodingFallbackMatchesBcl() { byte[] buffer; int bytesRead; var decoder = MetadataStringDecoder.DefaultUTF8; // dangling lead byte fixed (byte* ptr = (buffer = new byte[] { 0xC0 })) { string s = new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, null, decoder, out bytesRead); Assert.Equal("\uFFFD", new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, null, decoder, out bytesRead)); Assert.Equal(s, Encoding.UTF8.GetString(buffer)); Assert.Equal(buffer.Length, bytesRead); s = new MemoryBlock(ptr, buffer.Length).PeekUtf8NullTerminated(0, Encoding.UTF8.GetBytes("Hello"), decoder, out bytesRead); Assert.Equal("Hello\uFFFD", s); Assert.Equal(s, "Hello" + Encoding.UTF8.GetString(buffer)); Assert.Equal(buffer.Length, bytesRead); Assert.Equal("\uFFFD", new MemoryBlock(ptr, buffer.Length).PeekUtf8(0, buffer.Length)); } // overlong encoding fixed (byte* ptr = (buffer = new byte[] { (byte)'a', 0xC0, 0xAF, (byte)'b', 0x0 })) { var block = new MemoryBlock(ptr, buffer.Length); Assert.Equal("a\uFFFD\uFFFDb", block.PeekUtf8NullTerminated(0, null, decoder, out bytesRead)); Assert.Equal(buffer.Length, bytesRead); } // TODO: There are a bunch more error cases of course, but this is enough to break the old code // and we now just call the BCL, so from a white box perspective, we needn't get carried away. }
internal MethodDebugInformationTableReader( int numberOfRows, int documentRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset) { NumberOfRows = numberOfRows; _isDocumentRefSmall = documentRefSize == 2; _isBlobHeapRefSizeSmall = blobHeapRefSize == 2; _sequencePointsOffset = DocumentOffset + documentRefSize; RowSize = _sequencePointsOffset + blobHeapRefSize; Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, RowSize * numberOfRows); }
private MethodBodyBlock( bool localVariablesInitialized, ushort maxStack, StandaloneSignatureHandle localSignatureHandle, MemoryBlock il, ImmutableArray<ExceptionRegion> exceptionRegions, int size) { Debug.Assert(!exceptionRegions.IsDefault); this.localVariablesInitialized = localVariablesInitialized; this.maxStack = maxStack; this.localSignature = localSignatureHandle; this.il = il; this.exceptionRegions = exceptionRegions; this.size = size; }
internal DocumentTableReader( int numberOfRows, int guidHeapRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset) { NumberOfRows = numberOfRows; _isGuidHeapRefSizeSmall = guidHeapRefSize == 2; _isBlobHeapRefSizeSmall = blobHeapRefSize == 2; _hashAlgorithmOffset = NameOffset + blobHeapRefSize; _hashOffset = _hashAlgorithmOffset + guidHeapRefSize; _languageOffset = _hashOffset + blobHeapRefSize; RowSize = _languageOffset + guidHeapRefSize; Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, RowSize * numberOfRows); }
internal ModuleTableReader( int numberOfRows, int stringHeapRefSize, int guidHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; _IsGUIDHeapRefSizeSmall = guidHeapRefSize == 2; _GenerationOffset = 0; _NameOffset = _GenerationOffset + sizeof(UInt16); _MVIdOffset = _NameOffset + stringHeapRefSize; _EnCIdOffset = _MVIdOffset + guidHeapRefSize; _EnCBaseIdOffset = _EnCIdOffset + guidHeapRefSize; this.RowSize = _EnCBaseIdOffset + guidHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, this.RowSize * (int)numberOfRows); }
private void TestUtf8NullTerminatedFastCompare( MemoryBlock block, int offset, char terminator, string comparand, int comparandOffset, bool ignoreCase, MemoryBlock.FastComparisonResult expectedResult, int expectedFirstDifferenceIndex) { int actualFirstDifferenceIndex; var actualResult = block.Utf8NullTerminatedFastCompare(offset, comparand, comparandOffset, out actualFirstDifferenceIndex, terminator, ignoreCase); Assert.Equal(expectedResult, actualResult); Assert.Equal(expectedFirstDifferenceIndex, actualFirstDifferenceIndex); }
public unsafe void Utf8NullTerminatedFastCompare() { byte[] heap; MetadataStringDecoder decoder = MetadataStringDecoder.DefaultUTF8; const bool HonorCase = false; const bool IgnoreCase = true; const char terminator_0 = '\0'; const char terminator_F = 'F'; const char terminator_X = 'X'; const char terminator_x = 'x'; fixed (byte* heapPtr = (heap = new byte[] { (byte)'F', 0, (byte)'X', (byte)'Y', /* U+12345 (\ud808\udf45) */ 0xf0, 0x92, 0x8d, 0x85 })) { var block = new MemoryBlock(heapPtr, heap.Length); TestUtf8NullTerminatedFastCompare(block, 0, terminator_0, "F", 0, HonorCase, MemoryBlock.FastComparisonResult.Equal, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_0, "f", 0, IgnoreCase, MemoryBlock.FastComparisonResult.Equal, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_F, "", 0, IgnoreCase, MemoryBlock.FastComparisonResult.Equal, 0); TestUtf8NullTerminatedFastCompare(block, 0, terminator_F, "*", 1, IgnoreCase, MemoryBlock.FastComparisonResult.Equal, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_0, "FF", 0, HonorCase, MemoryBlock.FastComparisonResult.TextStartsWithBytes, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_0, "fF", 0, IgnoreCase, MemoryBlock.FastComparisonResult.TextStartsWithBytes, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_0, "F\0", 0, HonorCase, MemoryBlock.FastComparisonResult.TextStartsWithBytes, 1); TestUtf8NullTerminatedFastCompare(block, 0, terminator_X, "F\0", 0, HonorCase, MemoryBlock.FastComparisonResult.TextStartsWithBytes, 1); TestUtf8NullTerminatedFastCompare(block, 2, terminator_0, "X", 0, HonorCase, MemoryBlock.FastComparisonResult.BytesStartWithText, 1); TestUtf8NullTerminatedFastCompare(block, 2, terminator_0, "x", 0, IgnoreCase, MemoryBlock.FastComparisonResult.BytesStartWithText, 1); TestUtf8NullTerminatedFastCompare(block, 2, terminator_x, "XY", 0, IgnoreCase, MemoryBlock.FastComparisonResult.BytesStartWithText, 2); TestUtf8NullTerminatedFastCompare(block, 3, terminator_0, "yZ", 0, IgnoreCase, MemoryBlock.FastComparisonResult.Unequal, 1); TestUtf8NullTerminatedFastCompare(block, 4, terminator_0, "a", 0, HonorCase, MemoryBlock.FastComparisonResult.Unequal, 0); TestUtf8NullTerminatedFastCompare(block, 4, terminator_0, "\ud808", 0, HonorCase, MemoryBlock.FastComparisonResult.Inconclusive, 0); TestUtf8NullTerminatedFastCompare(block, 4, terminator_0, "\ud808\udf45", 0, HonorCase, MemoryBlock.FastComparisonResult.Inconclusive, 0); } }
private static unsafe void TestComparison(MemoryBlock block, int offset, string value, string heapSubstr, MetadataStringDecoder decoder, bool ignoreCase) { // equals: bool actualEq = block.Utf8NullTerminatedEquals(offset, value, decoder, terminator: '\0', ignoreCase: ignoreCase); bool expectedEq = string.Equals(heapSubstr, value, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); Assert.Equal(expectedEq, actualEq); // starts with: bool actualSW = block.Utf8NullTerminatedStartsWith(offset, value, decoder, terminator: '\0', ignoreCase: ignoreCase); bool expectedSW = heapSubstr.StartsWith(value, ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal); Assert.Equal(actualSW, expectedSW); }
internal ConstantTableReader( int numberOfRows, bool declaredSorted, int hasConstantRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsHasConstantRefSizeSmall = hasConstantRefSize == 2; _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; _TypeOffset = 0; _ParentOffset = _TypeOffset + sizeof(Byte) + 1; // Alignment here (+1)... _ValueOffset = _ParentOffset + hasConstantRefSize; this.RowSize = _ValueOffset + blobHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); if (!declaredSorted && !CheckSorted()) { Throw.TableNotSorted(TableIndex.Constant); } }
public unsafe void PeekReference() { var table = new byte[] { 0xff, 0xff, 0xff, 0x00, // offset 0 0xff, 0xff, 0xff, 0x01, // offset 4 0xff, 0xff, 0xff, 0x1f, // offset 8 0xff, 0xff, 0xff, 0x2f, // offset 12 0xff, 0xff, 0xff, 0xff, // offset 16 }; fixed (byte* tablePtr = table) { var block = new MemoryBlock(tablePtr, table.Length); Assert.Equal(0x0000ffff, block.PeekReference(0, smallRefSize: true)); Assert.Equal(0x0000ffff, block.PeekHeapReference(0, smallRefSize: true)); Assert.Equal(0x0000ffffu, block.PeekReferenceUnchecked(0, smallRefSize: true)); Assert.Equal(0x00ffffff, block.PeekReference(0, smallRefSize: false)); Assert.Throws<BadImageFormatException>(() => block.PeekReference(4, smallRefSize: false)); Assert.Throws<BadImageFormatException>(() => block.PeekReference(16, smallRefSize: false)); Assert.Equal(0x1fffffff, block.PeekHeapReference(8, smallRefSize: false)); Assert.Throws<BadImageFormatException>(() => block.PeekHeapReference(12, smallRefSize: false)); Assert.Throws<BadImageFormatException>(() => block.PeekHeapReference(16, smallRefSize: false)); Assert.Equal(0x01ffffffu, block.PeekReferenceUnchecked(4, smallRefSize: false)); Assert.Equal(0x1fffffffu, block.PeekReferenceUnchecked(8, smallRefSize: false)); Assert.Equal(0x2fffffffu, block.PeekReferenceUnchecked(12, smallRefSize: false)); Assert.Equal(0xffffffffu, block.PeekReferenceUnchecked(16, smallRefSize: false)); } }
private unsafe void TestSearch(string heapValue, int offset, string[] values) { byte[] heap; fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes(heapValue))) { int actual = new MemoryBlock(heapPtr, heap.Length).BinarySearch(values, offset); string heapSubstr = GetStringHeapValue(heapValue, offset); int expected = Array.BinarySearch(values, heapSubstr); Assert.Equal(expected, actual); } }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> /// <exception cref="ArgumentOutOfRangeException"><paramref name="length"/> is not positive.</exception> /// <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> 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 // worry about the image (stream) being empty and can handle all image errors by catching BadImageFormatException. if (length < 0) { throw new ArgumentOutOfRangeException(nameof(length)); } if (metadata == null) { throw new ArgumentNullException(nameof(metadata)); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(SR.MetadataStringDecoderEncodingMustBeUtf8, nameof(utf8Decoder)); } if (!BitConverter.IsLittleEndian) { Throw.LitteEndianArchitectureRequired(); } this.Block = new MemoryBlock(metadata, length); _options = options; this.UTF8Decoder = utf8Decoder; var headerReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref headerReader, out _versionString); _metadataKind = GetMetadataKind(_versionString); var streamHeaders = this.ReadStreamHeaders(ref headerReader); // storage header and stream headers: MemoryBlock metadataTableStream; MemoryBlock standalonePdbStream; this.InitializeStreamReaders(ref this.Block, streamHeaders, out _metadataStreamKind, out metadataTableStream, out standalonePdbStream); int[] externalTableRowCountsOpt; if (standalonePdbStream.Length > 0) { ReadStandalonePortablePdbStream(standalonePdbStream, out _debugMetadataHeader, out externalTableRowCountsOpt); } else { externalTableRowCountsOpt = null; } var tableReader = new BlobReader(metadataTableStream); HeapSizes heapSizes; int[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref tableReader, out heapSizes, out metadataTableRowCounts, out _sortedTables); this.InitializeTableReaders(tableReader.GetMemoryBlockAt(0, tableReader.RemainingBytes), heapSizes, metadataTableRowCounts, externalTableRowCountsOpt); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (standalonePdbStream.Length == 0 && this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(SR.Format(SR.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.NamespaceCache = new NamespaceCache(this); if (_metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
private void InitializeTableReaders(MemoryBlock metadataTablesMemoryBlock, HeapSizes heapSizes, int[] rowCounts, int[] externalRowCountsOpt) { // Size of reference tags in each table. this.TableRowCounts = rowCounts; // TODO (https://github.com/dotnet/corefx/issues/2061): // Shouldn't XxxPtr table be always the same size or smaller than the corresponding Xxx table? // Compute ref sizes for tables that can have pointer tables int fieldRefSizeSorted = GetReferenceSize(rowCounts, TableIndex.FieldPtr) > SmallIndexSize ? LargeIndexSize : GetReferenceSize(rowCounts, TableIndex.Field); int methodRefSizeSorted = GetReferenceSize(rowCounts, TableIndex.MethodPtr) > SmallIndexSize ? LargeIndexSize : GetReferenceSize(rowCounts, TableIndex.MethodDef); int paramRefSizeSorted = GetReferenceSize(rowCounts, TableIndex.ParamPtr) > SmallIndexSize ? LargeIndexSize : GetReferenceSize(rowCounts, TableIndex.Param); int eventRefSizeSorted = GetReferenceSize(rowCounts, TableIndex.EventPtr) > SmallIndexSize ? LargeIndexSize : GetReferenceSize(rowCounts, TableIndex.Event); int propertyRefSizeSorted = GetReferenceSize(rowCounts, TableIndex.PropertyPtr) > SmallIndexSize ? LargeIndexSize : GetReferenceSize(rowCounts, TableIndex.Property); // Compute the coded token ref sizes int typeDefOrRefRefSize = ComputeCodedTokenSize(TypeDefOrRefTag.LargeRowSize, rowCounts, TypeDefOrRefTag.TablesReferenced); int hasConstantRefSize = ComputeCodedTokenSize(HasConstantTag.LargeRowSize, rowCounts, HasConstantTag.TablesReferenced); int hasCustomAttributeRefSize = ComputeCodedTokenSize(HasCustomAttributeTag.LargeRowSize, rowCounts, HasCustomAttributeTag.TablesReferenced); int hasFieldMarshalRefSize = ComputeCodedTokenSize(HasFieldMarshalTag.LargeRowSize, rowCounts, HasFieldMarshalTag.TablesReferenced); int hasDeclSecurityRefSize = ComputeCodedTokenSize(HasDeclSecurityTag.LargeRowSize, rowCounts, HasDeclSecurityTag.TablesReferenced); int memberRefParentRefSize = ComputeCodedTokenSize(MemberRefParentTag.LargeRowSize, rowCounts, MemberRefParentTag.TablesReferenced); int hasSemanticsRefSize = ComputeCodedTokenSize(HasSemanticsTag.LargeRowSize, rowCounts, HasSemanticsTag.TablesReferenced); int methodDefOrRefRefSize = ComputeCodedTokenSize(MethodDefOrRefTag.LargeRowSize, rowCounts, MethodDefOrRefTag.TablesReferenced); int memberForwardedRefSize = ComputeCodedTokenSize(MemberForwardedTag.LargeRowSize, rowCounts, MemberForwardedTag.TablesReferenced); int implementationRefSize = ComputeCodedTokenSize(ImplementationTag.LargeRowSize, rowCounts, ImplementationTag.TablesReferenced); int customAttributeTypeRefSize = ComputeCodedTokenSize(CustomAttributeTypeTag.LargeRowSize, rowCounts, CustomAttributeTypeTag.TablesReferenced); int resolutionScopeRefSize = ComputeCodedTokenSize(ResolutionScopeTag.LargeRowSize, rowCounts, ResolutionScopeTag.TablesReferenced); int typeOrMethodDefRefSize = ComputeCodedTokenSize(TypeOrMethodDefTag.LargeRowSize, rowCounts, TypeOrMethodDefTag.TablesReferenced); // Compute HeapRef Sizes int stringHeapRefSize = (heapSizes & HeapSizes.StringHeapLarge) == HeapSizes.StringHeapLarge ? LargeIndexSize : SmallIndexSize; int guidHeapRefSize = (heapSizes & HeapSizes.GuidHeapLarge) == HeapSizes.GuidHeapLarge ? LargeIndexSize : SmallIndexSize; int blobHeapRefSize = (heapSizes & HeapSizes.BlobHeapLarge) == HeapSizes.BlobHeapLarge ? LargeIndexSize : SmallIndexSize; // Populate the Table blocks int totalRequiredSize = 0; this.ModuleTable = new ModuleTableReader(rowCounts[(int)TableIndex.Module], stringHeapRefSize, guidHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ModuleTable.Block.Length; this.TypeRefTable = new TypeRefTableReader(rowCounts[(int)TableIndex.TypeRef], resolutionScopeRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeRefTable.Block.Length; this.TypeDefTable = new TypeDefTableReader(rowCounts[(int)TableIndex.TypeDef], fieldRefSizeSorted, methodRefSizeSorted, typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeDefTable.Block.Length; this.FieldPtrTable = new FieldPtrTableReader(rowCounts[(int)TableIndex.FieldPtr], GetReferenceSize(rowCounts, TableIndex.Field), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldPtrTable.Block.Length; this.FieldTable = new FieldTableReader(rowCounts[(int)TableIndex.Field], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldTable.Block.Length; this.MethodPtrTable = new MethodPtrTableReader(rowCounts[(int)TableIndex.MethodPtr], GetReferenceSize(rowCounts, TableIndex.MethodDef), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodPtrTable.Block.Length; this.MethodDefTable = new MethodTableReader(rowCounts[(int)TableIndex.MethodDef], paramRefSizeSorted, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodDefTable.Block.Length; this.ParamPtrTable = new ParamPtrTableReader(rowCounts[(int)TableIndex.ParamPtr], GetReferenceSize(rowCounts, TableIndex.Param), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ParamPtrTable.Block.Length; this.ParamTable = new ParamTableReader(rowCounts[(int)TableIndex.Param], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ParamTable.Block.Length; this.InterfaceImplTable = new InterfaceImplTableReader(rowCounts[(int)TableIndex.InterfaceImpl], IsDeclaredSorted(TableMask.InterfaceImpl), GetReferenceSize(rowCounts, TableIndex.TypeDef), typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.InterfaceImplTable.Block.Length; this.MemberRefTable = new MemberRefTableReader(rowCounts[(int)TableIndex.MemberRef], memberRefParentRefSize, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MemberRefTable.Block.Length; this.ConstantTable = new ConstantTableReader(rowCounts[(int)TableIndex.Constant], IsDeclaredSorted(TableMask.Constant), hasConstantRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ConstantTable.Block.Length; this.CustomAttributeTable = new CustomAttributeTableReader(rowCounts[(int)TableIndex.CustomAttribute], IsDeclaredSorted(TableMask.CustomAttribute), hasCustomAttributeRefSize, customAttributeTypeRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.CustomAttributeTable.Block.Length; this.FieldMarshalTable = new FieldMarshalTableReader(rowCounts[(int)TableIndex.FieldMarshal], IsDeclaredSorted(TableMask.FieldMarshal), hasFieldMarshalRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldMarshalTable.Block.Length; this.DeclSecurityTable = new DeclSecurityTableReader(rowCounts[(int)TableIndex.DeclSecurity], IsDeclaredSorted(TableMask.DeclSecurity), hasDeclSecurityRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.DeclSecurityTable.Block.Length; this.ClassLayoutTable = new ClassLayoutTableReader(rowCounts[(int)TableIndex.ClassLayout], IsDeclaredSorted(TableMask.ClassLayout), GetReferenceSize(rowCounts, TableIndex.TypeDef), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ClassLayoutTable.Block.Length; this.FieldLayoutTable = new FieldLayoutTableReader(rowCounts[(int)TableIndex.FieldLayout], IsDeclaredSorted(TableMask.FieldLayout), GetReferenceSize(rowCounts, TableIndex.Field), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldLayoutTable.Block.Length; this.StandAloneSigTable = new StandAloneSigTableReader(rowCounts[(int)TableIndex.StandAloneSig], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.StandAloneSigTable.Block.Length; this.EventMapTable = new EventMapTableReader(rowCounts[(int)TableIndex.EventMap], GetReferenceSize(rowCounts, TableIndex.TypeDef), eventRefSizeSorted, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventMapTable.Block.Length; this.EventPtrTable = new EventPtrTableReader(rowCounts[(int)TableIndex.EventPtr], GetReferenceSize(rowCounts, TableIndex.Event), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventPtrTable.Block.Length; this.EventTable = new EventTableReader(rowCounts[(int)TableIndex.Event], typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventTable.Block.Length; this.PropertyMapTable = new PropertyMapTableReader(rowCounts[(int)TableIndex.PropertyMap], GetReferenceSize(rowCounts, TableIndex.TypeDef), propertyRefSizeSorted, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyMapTable.Block.Length; this.PropertyPtrTable = new PropertyPtrTableReader(rowCounts[(int)TableIndex.PropertyPtr], GetReferenceSize(rowCounts, TableIndex.Property), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyPtrTable.Block.Length; this.PropertyTable = new PropertyTableReader(rowCounts[(int)TableIndex.Property], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyTable.Block.Length; this.MethodSemanticsTable = new MethodSemanticsTableReader(rowCounts[(int)TableIndex.MethodSemantics], IsDeclaredSorted(TableMask.MethodSemantics), GetReferenceSize(rowCounts, TableIndex.MethodDef), hasSemanticsRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodSemanticsTable.Block.Length; this.MethodImplTable = new MethodImplTableReader(rowCounts[(int)TableIndex.MethodImpl], IsDeclaredSorted(TableMask.MethodImpl), GetReferenceSize(rowCounts, TableIndex.TypeDef), methodDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodImplTable.Block.Length; this.ModuleRefTable = new ModuleRefTableReader(rowCounts[(int)TableIndex.ModuleRef], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ModuleRefTable.Block.Length; this.TypeSpecTable = new TypeSpecTableReader(rowCounts[(int)TableIndex.TypeSpec], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeSpecTable.Block.Length; this.ImplMapTable = new ImplMapTableReader(rowCounts[(int)TableIndex.ImplMap], IsDeclaredSorted(TableMask.ImplMap), GetReferenceSize(rowCounts, TableIndex.ModuleRef), memberForwardedRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ImplMapTable.Block.Length; this.FieldRvaTable = new FieldRVATableReader(rowCounts[(int)TableIndex.FieldRva], IsDeclaredSorted(TableMask.FieldRva), GetReferenceSize(rowCounts, TableIndex.Field), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldRvaTable.Block.Length; this.EncLogTable = new EnCLogTableReader(rowCounts[(int)TableIndex.EncLog], metadataTablesMemoryBlock, totalRequiredSize, _metadataStreamKind); totalRequiredSize += this.EncLogTable.Block.Length; this.EncMapTable = new EnCMapTableReader(rowCounts[(int)TableIndex.EncMap], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EncMapTable.Block.Length; this.AssemblyTable = new AssemblyTableReader(rowCounts[(int)TableIndex.Assembly], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyTable.Block.Length; this.AssemblyProcessorTable = new AssemblyProcessorTableReader(rowCounts[(int)TableIndex.AssemblyProcessor], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyProcessorTable.Block.Length; this.AssemblyOSTable = new AssemblyOSTableReader(rowCounts[(int)TableIndex.AssemblyOS], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyOSTable.Block.Length; this.AssemblyRefTable = new AssemblyRefTableReader(rowCounts[(int)TableIndex.AssemblyRef], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize, _metadataKind); totalRequiredSize += this.AssemblyRefTable.Block.Length; this.AssemblyRefProcessorTable = new AssemblyRefProcessorTableReader(rowCounts[(int)TableIndex.AssemblyRefProcessor], GetReferenceSize(rowCounts, TableIndex.AssemblyRef), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyRefProcessorTable.Block.Length; this.AssemblyRefOSTable = new AssemblyRefOSTableReader(rowCounts[(int)TableIndex.AssemblyRefOS], GetReferenceSize(rowCounts, TableIndex.AssemblyRef), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyRefOSTable.Block.Length; this.FileTable = new FileTableReader(rowCounts[(int)TableIndex.File], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FileTable.Block.Length; this.ExportedTypeTable = new ExportedTypeTableReader(rowCounts[(int)TableIndex.ExportedType], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ExportedTypeTable.Block.Length; this.ManifestResourceTable = new ManifestResourceTableReader(rowCounts[(int)TableIndex.ManifestResource], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ManifestResourceTable.Block.Length; this.NestedClassTable = new NestedClassTableReader(rowCounts[(int)TableIndex.NestedClass], IsDeclaredSorted(TableMask.NestedClass), GetReferenceSize(rowCounts, TableIndex.TypeDef), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.NestedClassTable.Block.Length; this.GenericParamTable = new GenericParamTableReader(rowCounts[(int)TableIndex.GenericParam], IsDeclaredSorted(TableMask.GenericParam), typeOrMethodDefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.GenericParamTable.Block.Length; this.MethodSpecTable = new MethodSpecTableReader(rowCounts[(int)TableIndex.MethodSpec], methodDefOrRefRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodSpecTable.Block.Length; this.GenericParamConstraintTable = new GenericParamConstraintTableReader(rowCounts[(int)TableIndex.GenericParamConstraint], IsDeclaredSorted(TableMask.GenericParamConstraint), GetReferenceSize(rowCounts, TableIndex.GenericParam), typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.GenericParamConstraintTable.Block.Length; // debug tables: // Type-system metadata tables may be stored in a separate (external) metadata file. // We need to use the row counts of the external tables when referencing them. // Debug tables are local to the current metadata image and type system metadata tables are external and precede all debug tables. var combinedRowCounts = (externalRowCountsOpt != null) ? CombineRowCounts(rowCounts, externalRowCountsOpt, firstLocalTableIndex: TableIndex.Document) : rowCounts; int methodRefSizeCombined = GetReferenceSize(combinedRowCounts, TableIndex.MethodDef); int hasCustomDebugInformationRefSizeCombined = ComputeCodedTokenSize(HasCustomDebugInformationTag.LargeRowSize, combinedRowCounts, HasCustomDebugInformationTag.TablesReferenced); this.DocumentTable = new DocumentTableReader(rowCounts[(int)TableIndex.Document], guidHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.DocumentTable.Block.Length; this.MethodDebugInformationTable = new MethodDebugInformationTableReader(rowCounts[(int)TableIndex.MethodDebugInformation], GetReferenceSize(rowCounts, TableIndex.Document), blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodDebugInformationTable.Block.Length; this.LocalScopeTable = new LocalScopeTableReader(rowCounts[(int)TableIndex.LocalScope], IsDeclaredSorted(TableMask.LocalScope), methodRefSizeCombined, GetReferenceSize(rowCounts, TableIndex.ImportScope), GetReferenceSize(rowCounts, TableIndex.LocalVariable), GetReferenceSize(rowCounts, TableIndex.LocalConstant), metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.LocalScopeTable.Block.Length; this.LocalVariableTable = new LocalVariableTableReader(rowCounts[(int)TableIndex.LocalVariable], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.LocalVariableTable.Block.Length; this.LocalConstantTable = new LocalConstantTableReader(rowCounts[(int)TableIndex.LocalConstant], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.LocalConstantTable.Block.Length; this.ImportScopeTable = new ImportScopeTableReader(rowCounts[(int)TableIndex.ImportScope], GetReferenceSize(rowCounts, TableIndex.ImportScope), blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ImportScopeTable.Block.Length; this.StateMachineMethodTable = new StateMachineMethodTableReader(rowCounts[(int)TableIndex.StateMachineMethod], IsDeclaredSorted(TableMask.StateMachineMethod), methodRefSizeCombined, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.StateMachineMethodTable.Block.Length; this.CustomDebugInformationTable = new CustomDebugInformationTableReader(rowCounts[(int)TableIndex.CustomDebugInformation], IsDeclaredSorted(TableMask.CustomDebugInformation), hasCustomDebugInformationRefSizeCombined, guidHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.CustomDebugInformationTable.Block.Length; if (totalRequiredSize > metadataTablesMemoryBlock.Length) { throw new BadImageFormatException(SR.MetadataTablesTooSmall); } }
// internal for testing internal static void ReadStandalonePortablePdbStream(MemoryBlock block, out DebugMetadataHeader debugMetadataHeader, out int[] externalTableRowCounts) { var reader = new BlobReader(block); const int PdbIdSize = 20; byte[] pdbId = reader.ReadBytes(PdbIdSize); // ECMA-335 15.4.1.2: // The entry point to an application shall be static. // This entry point method can be a global method or it can appear inside a type. // The entry point method shall either accept no arguments or a vector of strings. // The return type of the entry point method shall be void, int32, or unsigned int32. // The entry point method cannot be defined in a generic class. uint entryPointToken = reader.ReadUInt32(); int entryPointRowId = (int)(entryPointToken & TokenTypeIds.RIDMask); if (entryPointToken != 0 && ((entryPointToken & TokenTypeIds.TypeMask) != TokenTypeIds.MethodDef || entryPointRowId == 0)) { throw new BadImageFormatException(string.Format(SR.InvalidEntryPointToken, entryPointToken)); } ulong externalTableMask = reader.ReadUInt64(); // EnC & Ptr tables can't be referenced from standalone PDB metadata: const ulong validTables = (ulong)TableMask.ValidPortablePdbExternalTables; if ((externalTableMask & ~validTables) != 0) { throw new BadImageFormatException(string.Format(SR.UnknownTables, (TableMask)externalTableMask)); } externalTableRowCounts = ReadMetadataTableRowCounts(ref reader, externalTableMask); debugMetadataHeader = new DebugMetadataHeader( ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref pdbId), MethodDefinitionHandle.FromRowId(entryPointRowId)); }
internal DeclSecurityTableReader( int numberOfRows, bool declaredSorted, int hasDeclSecurityRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsHasDeclSecurityRefSizeSmall = hasDeclSecurityRefSize == 2; _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; _ActionOffset = 0; _ParentOffset = _ActionOffset + sizeof(UInt16); _PermissionSetOffset = _ParentOffset + hasDeclSecurityRefSize; this.RowSize = _PermissionSetOffset + blobHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); if (!declaredSorted && !CheckSorted()) { Throw.TableNotSorted(TableIndex.DeclSecurity); } }
internal FieldMarshalTableReader( int numberOfRows, bool declaredSorted, int hasFieldMarshalRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsHasFieldMarshalRefSizeSmall = hasFieldMarshalRefSize == 2; _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; _ParentOffset = 0; _NativeTypeOffset = _ParentOffset + hasFieldMarshalRefSize; this.RowSize = _NativeTypeOffset + blobHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, this.RowSize * numberOfRows); if (!declaredSorted && !CheckSorted()) { Throw.TableNotSorted(TableIndex.FieldMarshal); } }
internal TypeRefTableReader( int numberOfRows, int resolutionScopeRefSize, int stringHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsResolutionScopeRefSizeSmall = resolutionScopeRefSize == 2; _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; _ResolutionScopeOffset = 0; _NameOffset = _ResolutionScopeOffset + resolutionScopeRefSize; _NamespaceOffset = _NameOffset + stringHeapRefSize; this.RowSize = _NamespaceOffset + stringHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); }
internal CustomAttributeTableReader( int numberOfRows, bool declaredSorted, int hasCustomAttributeRefSize, int customAttributeTypeRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsHasCustomAttributeRefSizeSmall = hasCustomAttributeRefSize == 2; _IsCustomAttributeTypeRefSizeSmall = customAttributeTypeRefSize == 2; _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; _ParentOffset = 0; _TypeOffset = _ParentOffset + hasCustomAttributeRefSize; _ValueOffset = _TypeOffset + customAttributeTypeRefSize; this.RowSize = _ValueOffset + blobHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); this.PtrTable = null; if (!declaredSorted && !CheckSorted()) { this.PtrTable = this.Block.BuildPtrTable( numberOfRows, this.RowSize, _ParentOffset, _IsHasCustomAttributeRefSizeSmall); } }
private unsafe void TestComparisons(string heapValue, int offset, string value, bool unicode = false) { byte[] heap; MetadataStringDecoder decoder = MetadataStringDecoder.DefaultUTF8; fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes(heapValue))) { var block = new MemoryBlock(heapPtr, heap.Length); string heapSubstr = GetStringHeapValue(heapValue, offset); // compare: if (!unicode) { int actualCmp = block.CompareUtf8NullTerminatedStringWithAsciiString(offset, value); int expectedCmp = StringComparer.Ordinal.Compare(heapSubstr, value); Assert.Equal(Math.Sign(expectedCmp), Math.Sign(actualCmp)); } // equals: bool actualEq = block.Utf8NullTerminatedEquals(offset, value, decoder); bool expectedEq = StringComparer.Ordinal.Equals(heapSubstr, value); Assert.Equal(expectedEq, actualEq); // starts with: bool actualSW = block.Utf8NullTerminatedStartsWith(offset, value, decoder); bool expectedSW = heapSubstr.StartsWith(value, StringComparison.Ordinal); Assert.Equal(actualSW, expectedSW); } }
public unsafe void ComparisonToInvalidByteSequenceMatchesFallback() { MetadataStringDecoder decoder = MetadataStringDecoder.DefaultUTF8; // dangling lead byte byte[] buffer; fixed (byte* ptr = (buffer = new byte[] { 0xC0 })) { var block = new MemoryBlock(ptr, buffer.Length); Assert.False(block.Utf8NullTerminatedStartsWith(0, new string((char)0xC0, 1), decoder)); Assert.False(block.Utf8NullTerminatedEquals(0, new string((char)0xC0, 1), decoder)); Assert.True(block.Utf8NullTerminatedStartsWith(0, "\uFFFD", decoder)); Assert.True(block.Utf8NullTerminatedEquals(0, "\uFFFD", decoder)); } // overlong encoding fixed (byte* ptr = (buffer = new byte[] { (byte)'a', 0xC0, 0xAF, (byte)'b', 0x0 })) { var block = new MemoryBlock(ptr, buffer.Length); Assert.False(block.Utf8NullTerminatedStartsWith(0, "a\\", decoder)); Assert.False(block.Utf8NullTerminatedEquals(0, "a\\b", decoder)); Assert.True(block.Utf8NullTerminatedStartsWith(0, "a\uFFFD", decoder)); Assert.True(block.Utf8NullTerminatedEquals(0, "a\uFFFD\uFFFDb", decoder)); } }
private unsafe static EnCMapTableReader CreateEncMapTable(int[] tokens) { GCHandle handle = GCHandle.Alloc(tokens, GCHandleType.Pinned); var block = new MemoryBlock((byte*)handle.AddrOfPinnedObject(), tokens.Length * sizeof(uint)); return new EnCMapTableReader(tokens.Length, block, containingBlockOffset: 0); }
public unsafe void BuildPtrTable_LargeRefs() { const int rowSize = 6; const int secondColumnOffset = 2; var table = new byte[] { 0xAA, 0xAA, 0x10, 0x00, 0x05, 0x00, 0xBB, 0xBB, 0x10, 0x00, 0x04, 0x00, 0xCC, 0xCC, 0x10, 0x00, 0x02, 0x01, 0xDD, 0xDD, 0x10, 0x00, 0x02, 0x00, 0xEE, 0xEE, 0x10, 0x00, 0x01, 0x01, }; int rowCount = table.Length / rowSize; fixed (byte* tablePtr = table) { var block = new MemoryBlock(tablePtr, table.Length); Assert.Equal(0x00040010, block.PeekReference(8, smallRefSize: false)); var actual = block.BuildPtrTable(rowCount, rowSize, secondColumnOffset, isReferenceSmall: false); var expected = new int[] { 4, 2, 1, 5, 3 }; Assert.Equal(expected, actual); } }
private void InitializeStreamReaders(ref MemoryBlock metadataRoot, StreamHeader[] streamHeaders, out MemoryBlock metadataTableStream) { metadataTableStream = default(MemoryBlock); foreach (StreamHeader streamHeader in streamHeaders) { switch (streamHeader.Name) { case COR20Constants.StringStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForStringStream); } this.StringStream = new StringStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size), this.metadataKind); break; case COR20Constants.BlobStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForBlobStream); } this.BlobStream = new BlobStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size), this.metadataKind); break; case COR20Constants.GUIDStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForGUIDStream); } this.GuidStream = new GuidStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size)); break; case COR20Constants.UserStringStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForBlobStream); } this.UserStringStream = new UserStringStreamReader(metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size)); break; case COR20Constants.CompressedMetadataTableStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); } this.metadataStreamKind = MetadataStreamKind.Compressed; metadataTableStream = metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size); break; case COR20Constants.UncompressedMetadataTableStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); } this.metadataStreamKind = MetadataStreamKind.Uncompressed; metadataTableStream = metadataRoot.GetMemoryBlockAt((int)streamHeader.Offset, streamHeader.Size); break; case COR20Constants.MinimalDeltaMetadataTableStreamName: if (metadataRoot.Length < streamHeader.Offset + streamHeader.Size) { throw new BadImageFormatException(MetadataResources.NotEnoughSpaceForMetadataStream); } // the content of the stream is ignored this.IsMinimalDelta = true; break; default: // Skip unknown streams. Some obfuscators insert invalid streams. continue; } } if (IsMinimalDelta && metadataStreamKind != MetadataStreamKind.Uncompressed) { throw new BadImageFormatException(MetadataResources.InvalidMetadataStreamFormat); } }
public unsafe void ValidatePeekReferenceSize() { byte[] buffer = new byte[8] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }; fixed (byte* bufferPtr = buffer) { var block = new MemoryBlock(bufferPtr, buffer.Length); // small ref size always fits in 16 bits Assert.Equal(0xFFFF, block.PeekReference(0, smallRefSize: true)); Assert.Equal(0xFFFF, block.PeekReference(4, smallRefSize: true)); Assert.Equal(0xFFFFU, block.PeekTaggedReference(0, smallRefSize: true)); Assert.Equal(0xFFFFU, block.PeekTaggedReference(4, smallRefSize: true)); Assert.Equal(0x01FFU, block.PeekTaggedReference(6, smallRefSize: true)); // large ref size throws on > RIDMask when tagged variant is not used. Assert.Throws<BadImageFormatException>(() => block.PeekReference(0, smallRefSize: false)); Assert.Throws<BadImageFormatException>(() => block.PeekReference(4, smallRefSize: false)); // large ref size does not throw when Tagged variant is used. Assert.Equal(0xFFFFFFFFU, block.PeekTaggedReference(0, smallRefSize: false)); Assert.Equal(0x01FFFFFFU, block.PeekTaggedReference(4, smallRefSize: false)); // bounds check applies in all cases Assert.Throws<BadImageFormatException>(() => block.PeekReference(7, smallRefSize: true)); Assert.Throws<BadImageFormatException>(() => block.PeekReference(5, smallRefSize: false)); } }
internal MemberRefTableReader( int numberOfRows, int memberRefParentRefSize, int stringHeapRefSize, int blobHeapRefSize, MemoryBlock containingBlock, int containingBlockOffset ) { this.NumberOfRows = numberOfRows; _IsMemberRefParentRefSizeSmall = memberRefParentRefSize == 2; _IsStringHeapRefSizeSmall = stringHeapRefSize == 2; _IsBlobHeapRefSizeSmall = blobHeapRefSize == 2; _ClassOffset = 0; _NameOffset = _ClassOffset + memberRefParentRefSize; _SignatureOffset = _NameOffset + stringHeapRefSize; this.RowSize = _SignatureOffset + blobHeapRefSize; this.Block = containingBlock.GetMemoryBlockAt(containingBlockOffset, (int)(this.RowSize * numberOfRows)); }
/// <summary> /// Creates a metadata reader from the metadata stored at the given memory location. /// </summary> /// <remarks> /// The memory is owned by the caller and it must be kept memory alive and unmodified throughout the lifetime of the <see cref="MetadataReader"/>. /// Use <see cref="PEReaderExtensions.GetMetadataReader(PortableExecutable.PEReader, MetadataReaderOptions, MetadataStringDecoder)"/> to obtain /// metadata from a PE image. /// </remarks> public unsafe MetadataReader(byte* metadata, int length, MetadataReaderOptions options, MetadataStringDecoder utf8Decoder) { if (length <= 0) { throw new ArgumentOutOfRangeException("length"); } if (metadata == null) { throw new ArgumentNullException("metadata"); } if (utf8Decoder == null) { utf8Decoder = MetadataStringDecoder.DefaultUTF8; } if (!(utf8Decoder.Encoding is UTF8Encoding)) { throw new ArgumentException(MetadataResources.MetadataStringDecoderEncodingMustBeUtf8, "utf8Decoder"); } if (!BitConverter.IsLittleEndian) { throw new PlatformNotSupportedException(MetadataResources.LitteEndianArchitectureRequired); } this.Block = new MemoryBlock(metadata, length); this.options = options; this.utf8Decoder = utf8Decoder; BlobReader memReader = new BlobReader(this.Block); this.ReadMetadataHeader(ref memReader); // storage header and stream headers: MemoryBlock metadataTableStream; var streamHeaders = this.ReadStreamHeaders(ref memReader); this.InitializeStreamReaders(ref this.Block, streamHeaders, out metadataTableStream); memReader = new BlobReader(metadataTableStream); uint[] metadataTableRowCounts; this.ReadMetadataTableHeader(ref memReader, out metadataTableRowCounts); this.InitializeTableReaders(memReader.GetMemoryBlockAt(0, memReader.RemainingBytes), metadataTableRowCounts); // This previously could occur in obfuscated assemblies but a check was added to prevent // it getting to this point Debug.Assert(this.AssemblyTable.NumberOfRows <= 1); // Although the specification states that the module table will have exactly one row, // the native metadata reader would successfully read files containing more than one row. // Such files exist in the wild and may be produced by obfuscators. if (this.ModuleTable.NumberOfRows < 1) { throw new BadImageFormatException(string.Format(MetadataResources.ModuleTableInvalidNumberOfRows, this.ModuleTable.NumberOfRows)); } // read this.namespaceCache = new NamespaceCache(this); if (this.metadataKind != MetadataKind.Ecma335) { this.WinMDMscorlibRef = FindMscorlibAssemblyRefNoProjection(); } }
public unsafe void ReadFromMemoryBlock() { byte[] buffer = new byte[4] { 0, 1, 0, 2 }; fixed (byte* bufferPtr = buffer) { var block = new MemoryBlock(bufferPtr, buffer.Length); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(Int32.MaxValue)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(-1)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt32(Int32.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(-1)); Assert.Throws<BadImageFormatException>(() => block.PeekUInt16(Int32.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(-1, null, stringDecoder, out bytesRead)); Assert.Throws<BadImageFormatException>(() => block.PeekUtf8NullTerminated(Int32.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(block.Length, -1)); Assert.Throws<BadImageFormatException>(() => block.GetMemoryBlockAt(-1, block.Length)); Assert.Equal("\u0001", block.PeekUtf8NullTerminated(1, null, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 2); Assert.Equal("\u0002", block.PeekUtf8NullTerminated(3, null, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 1); Assert.Equal("", block.PeekUtf8NullTerminated(4, null, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 0); byte[] helloPrefix = Encoding.UTF8.GetBytes("Hello"); Assert.Equal("Hello\u0001", block.PeekUtf8NullTerminated(1, helloPrefix, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 2); Assert.Equal("Hello\u0002", block.PeekUtf8NullTerminated(3, helloPrefix, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 1); Assert.Equal("Hello", block.PeekUtf8NullTerminated(4, helloPrefix, stringDecoder, out bytesRead)); Assert.Equal(bytesRead, 0); } }
private void InitializeTableReaders(MemoryBlock metadataTablesMemoryBlock, uint[] compressedRowCounts) { // Only sizes of tables present in metadata are recorded in rowCountCompressedArray. // This array contains a slot for each possible table, not just those that are present in the metadata. uint[] rowCounts = new uint[TableIndexExtensions.Count]; // Size of reference tags in each table. int[] referenceSizes = new int[TableIndexExtensions.Count]; ulong validTables = (ulong)this.MetadataTableHeader.ValidTables; int compressedRowCountIndex = 0; for (int i = 0; i < TableIndexExtensions.Count; i++) { bool fitsSmall; if ((validTables & 1UL) != 0) { uint rowCount = compressedRowCounts[compressedRowCountIndex++]; rowCounts[i] = rowCount; fitsSmall = rowCount < MetadataStreamConstants.LargeTableRowCount; } else { fitsSmall = true; } referenceSizes[i] = (fitsSmall && !IsMinimalDelta) ? SmallIndexSize : LargeIndexSize; validTables >>= 1; } this.TableRowCounts = rowCounts; // Compute ref sizes for tables that can have pointer tables for it int fieldRefSize = referenceSizes[(int)TableIndex.FieldPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Field]; int methodRefSize = referenceSizes[(int)TableIndex.MethodPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.MethodDef]; int paramRefSize = referenceSizes[(int)TableIndex.ParamPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Param]; int eventRefSize = referenceSizes[(int)TableIndex.EventPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Event]; int propertyRefSize = referenceSizes[(int)TableIndex.PropertyPtr] > SmallIndexSize ? LargeIndexSize : referenceSizes[(int)TableIndex.Property]; // Compute the coded token ref sizes int typeDefOrRefRefSize = ComputeCodedTokenSize(TypeDefOrRefTag.LargeRowSize, rowCounts, TypeDefOrRefTag.TablesReferenced); int hasConstantRefSize = ComputeCodedTokenSize(HasConstantTag.LargeRowSize, rowCounts, HasConstantTag.TablesReferenced); int hasCustomAttributeRefSize = ComputeCodedTokenSize(HasCustomAttributeTag.LargeRowSize, rowCounts, HasCustomAttributeTag.TablesReferenced); int hasFieldMarshalRefSize = ComputeCodedTokenSize(HasFieldMarshalTag.LargeRowSize, rowCounts, HasFieldMarshalTag.TablesReferenced); int hasDeclSecurityRefSize = ComputeCodedTokenSize(HasDeclSecurityTag.LargeRowSize, rowCounts, HasDeclSecurityTag.TablesReferenced); int memberRefParentRefSize = ComputeCodedTokenSize(MemberRefParentTag.LargeRowSize, rowCounts, MemberRefParentTag.TablesReferenced); int hasSemanticsRefSize = ComputeCodedTokenSize(HasSemanticsTag.LargeRowSize, rowCounts, HasSemanticsTag.TablesReferenced); int methodDefOrRefRefSize = ComputeCodedTokenSize(MethodDefOrRefTag.LargeRowSize, rowCounts, MethodDefOrRefTag.TablesReferenced); int memberForwardedRefSize = ComputeCodedTokenSize(MemberForwardedTag.LargeRowSize, rowCounts, MemberForwardedTag.TablesReferenced); int implementationRefSize = ComputeCodedTokenSize(ImplementationTag.LargeRowSize, rowCounts, ImplementationTag.TablesReferenced); int customAttributeTypeRefSize = ComputeCodedTokenSize(CustomAttributeTypeTag.LargeRowSize, rowCounts, CustomAttributeTypeTag.TablesReferenced); int resolutionScopeRefSize = ComputeCodedTokenSize(ResolutionScopeTag.LargeRowSize, rowCounts, ResolutionScopeTag.TablesReferenced); int typeOrMethodDefRefSize = ComputeCodedTokenSize(TypeOrMethodDefTag.LargeRowSize, rowCounts, TypeOrMethodDefTag.TablesReferenced); // Compute HeapRef Sizes int stringHeapRefSize = (this.MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.StringHeapLarge) == HeapSizeFlag.StringHeapLarge ? LargeIndexSize : SmallIndexSize; int guidHeapRefSize = (this.MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.GuidHeapLarge) == HeapSizeFlag.GuidHeapLarge ? LargeIndexSize : SmallIndexSize; int blobHeapRefSize = (this.MetadataTableHeader.HeapSizeFlags & HeapSizeFlag.BlobHeapLarge) == HeapSizeFlag.BlobHeapLarge ? LargeIndexSize : SmallIndexSize; // Populate the Table blocks int totalRequiredSize = 0; this.ModuleTable = new ModuleTableReader(rowCounts[(int)TableIndex.Module], stringHeapRefSize, guidHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ModuleTable.Block.Length; this.TypeRefTable = new TypeRefTableReader(rowCounts[(int)TableIndex.TypeRef], resolutionScopeRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeRefTable.Block.Length; this.TypeDefTable = new TypeDefTableReader(rowCounts[(int)TableIndex.TypeDef], fieldRefSize, methodRefSize, typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeDefTable.Block.Length; this.FieldPtrTable = new FieldPtrTableReader(rowCounts[(int)TableIndex.FieldPtr], referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldPtrTable.Block.Length; this.FieldTable = new FieldTableReader(rowCounts[(int)TableIndex.Field], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldTable.Block.Length; this.MethodPtrTable = new MethodPtrTableReader(rowCounts[(int)TableIndex.MethodPtr], referenceSizes[(int)TableIndex.MethodDef], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodPtrTable.Block.Length; this.MethodDefTable = new MethodTableReader(rowCounts[(int)TableIndex.MethodDef], paramRefSize, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodDefTable.Block.Length; this.ParamPtrTable = new ParamPtrTableReader(rowCounts[(int)TableIndex.ParamPtr], referenceSizes[(int)TableIndex.Param], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ParamPtrTable.Block.Length; this.ParamTable = new ParamTableReader(rowCounts[(int)TableIndex.Param], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ParamTable.Block.Length; this.InterfaceImplTable = new InterfaceImplTableReader(rowCounts[(int)TableIndex.InterfaceImpl], IsDeclaredSorted(TableMask.InterfaceImpl), referenceSizes[(int)TableIndex.TypeDef], typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.InterfaceImplTable.Block.Length; this.MemberRefTable = new MemberRefTableReader(rowCounts[(int)TableIndex.MemberRef], memberRefParentRefSize, stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MemberRefTable.Block.Length; this.ConstantTable = new ConstantTableReader(rowCounts[(int)TableIndex.Constant], IsDeclaredSorted(TableMask.Constant), hasConstantRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ConstantTable.Block.Length; this.CustomAttributeTable = new CustomAttributeTableReader(rowCounts[(int)TableIndex.CustomAttribute], IsDeclaredSorted(TableMask.CustomAttribute), hasCustomAttributeRefSize, customAttributeTypeRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.CustomAttributeTable.Block.Length; this.FieldMarshalTable = new FieldMarshalTableReader(rowCounts[(int)TableIndex.FieldMarshal], IsDeclaredSorted(TableMask.FieldMarshal), hasFieldMarshalRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldMarshalTable.Block.Length; this.DeclSecurityTable = new DeclSecurityTableReader(rowCounts[(int)TableIndex.DeclSecurity], IsDeclaredSorted(TableMask.DeclSecurity), hasDeclSecurityRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.DeclSecurityTable.Block.Length; this.ClassLayoutTable = new ClassLayoutTableReader(rowCounts[(int)TableIndex.ClassLayout], IsDeclaredSorted(TableMask.ClassLayout), referenceSizes[(int)TableIndex.TypeDef], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ClassLayoutTable.Block.Length; this.FieldLayoutTable = new FieldLayoutTableReader(rowCounts[(int)TableIndex.FieldLayout], IsDeclaredSorted(TableMask.FieldLayout), referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldLayoutTable.Block.Length; this.StandAloneSigTable = new StandAloneSigTableReader(rowCounts[(int)TableIndex.StandAloneSig], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.StandAloneSigTable.Block.Length; this.EventMapTable = new EventMapTableReader(rowCounts[(int)TableIndex.EventMap], referenceSizes[(int)TableIndex.TypeDef], eventRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventMapTable.Block.Length; this.EventPtrTable = new EventPtrTableReader(rowCounts[(int)TableIndex.EventPtr], referenceSizes[(int)TableIndex.Event], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventPtrTable.Block.Length; this.EventTable = new EventTableReader(rowCounts[(int)TableIndex.Event], typeDefOrRefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EventTable.Block.Length; this.PropertyMapTable = new PropertyMapTableReader(rowCounts[(int)TableIndex.PropertyMap], referenceSizes[(int)TableIndex.TypeDef], propertyRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyMapTable.Block.Length; this.PropertyPtrTable = new PropertyPtrTableReader(rowCounts[(int)TableIndex.PropertyPtr], referenceSizes[(int)TableIndex.Property], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyPtrTable.Block.Length; this.PropertyTable = new PropertyTableReader(rowCounts[(int)TableIndex.Property], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.PropertyTable.Block.Length; this.MethodSemanticsTable = new MethodSemanticsTableReader(rowCounts[(int)TableIndex.MethodSemantics], IsDeclaredSorted(TableMask.MethodSemantics), referenceSizes[(int)TableIndex.MethodDef], hasSemanticsRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodSemanticsTable.Block.Length; this.MethodImplTable = new MethodImplTableReader(rowCounts[(int)TableIndex.MethodImpl], IsDeclaredSorted(TableMask.MethodImpl), referenceSizes[(int)TableIndex.TypeDef], methodDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodImplTable.Block.Length; this.ModuleRefTable = new ModuleRefTableReader(rowCounts[(int)TableIndex.ModuleRef], stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ModuleRefTable.Block.Length; this.TypeSpecTable = new TypeSpecTableReader(rowCounts[(int)TableIndex.TypeSpec], blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.TypeSpecTable.Block.Length; this.ImplMapTable = new ImplMapTableReader(rowCounts[(int)TableIndex.ImplMap], IsDeclaredSorted(TableMask.ImplMap), referenceSizes[(int)TableIndex.ModuleRef], memberForwardedRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ImplMapTable.Block.Length; this.FieldRvaTable = new FieldRVATableReader(rowCounts[(int)TableIndex.FieldRva], IsDeclaredSorted(TableMask.FieldRva), referenceSizes[(int)TableIndex.Field], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FieldRvaTable.Block.Length; this.EncLogTable = new EnCLogTableReader(rowCounts[(int)TableIndex.EncLog], metadataTablesMemoryBlock, totalRequiredSize, this.metadataStreamKind); totalRequiredSize += this.EncLogTable.Block.Length; this.EncMapTable = new EnCMapTableReader(rowCounts[(int)TableIndex.EncMap], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.EncMapTable.Block.Length; this.AssemblyTable = new AssemblyTableReader(rowCounts[(int)TableIndex.Assembly], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyTable.Block.Length; this.AssemblyProcessorTable = new AssemblyProcessorTableReader(rowCounts[(int)TableIndex.AssemblyProcessor], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyProcessorTable.Block.Length; this.AssemblyOSTable = new AssemblyOSTableReader(rowCounts[(int)TableIndex.AssemblyOS], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyOSTable.Block.Length; this.AssemblyRefTable = new AssemblyRefTableReader((int)rowCounts[(int)TableIndex.AssemblyRef], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize, this.metadataKind); totalRequiredSize += this.AssemblyRefTable.Block.Length; this.AssemblyRefProcessorTable = new AssemblyRefProcessorTableReader(rowCounts[(int)TableIndex.AssemblyRefProcessor], referenceSizes[(int)TableIndex.AssemblyRef], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyRefProcessorTable.Block.Length; this.AssemblyRefOSTable = new AssemblyRefOSTableReader(rowCounts[(int)TableIndex.AssemblyRefOS], referenceSizes[(int)TableIndex.AssemblyRef], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.AssemblyRefOSTable.Block.Length; this.FileTable = new FileTableReader(rowCounts[(int)TableIndex.File], stringHeapRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.FileTable.Block.Length; this.ExportedTypeTable = new ExportedTypeTableReader(rowCounts[(int)TableIndex.ExportedType], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ExportedTypeTable.Block.Length; this.ManifestResourceTable = new ManifestResourceTableReader(rowCounts[(int)TableIndex.ManifestResource], implementationRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.ManifestResourceTable.Block.Length; this.NestedClassTable = new NestedClassTableReader(rowCounts[(int)TableIndex.NestedClass], IsDeclaredSorted(TableMask.NestedClass), referenceSizes[(int)TableIndex.TypeDef], metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.NestedClassTable.Block.Length; this.GenericParamTable = new GenericParamTableReader(rowCounts[(int)TableIndex.GenericParam], IsDeclaredSorted(TableMask.GenericParam), typeOrMethodDefRefSize, stringHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.GenericParamTable.Block.Length; this.MethodSpecTable = new MethodSpecTableReader(rowCounts[(int)TableIndex.MethodSpec], methodDefOrRefRefSize, blobHeapRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.MethodSpecTable.Block.Length; this.GenericParamConstraintTable = new GenericParamConstraintTableReader(rowCounts[(int)TableIndex.GenericParamConstraint], IsDeclaredSorted(TableMask.GenericParamConstraint), referenceSizes[(int)TableIndex.GenericParam], typeDefOrRefRefSize, metadataTablesMemoryBlock, totalRequiredSize); totalRequiredSize += this.GenericParamConstraintTable.Block.Length; if (totalRequiredSize > metadataTablesMemoryBlock.Length) { throw new BadImageFormatException(MetadataResources.MetadataTablesTooSmall); } }
private unsafe void TestComparisons(string heapValue, int offset, string value, bool unicode = false, bool ignoreCase = false) { byte[] heap; MetadataStringDecoder decoder = MetadataStringDecoder.DefaultUTF8; fixed (byte* heapPtr = (heap = Encoding.UTF8.GetBytes(heapValue))) { var block = new MemoryBlock(heapPtr, heap.Length); string heapSubstr = GetStringHeapValue(heapValue, offset); // compare: if (!unicode) { int actualCmp = block.CompareUtf8NullTerminatedStringWithAsciiString(offset, value); int expectedCmp = StringComparer.Ordinal.Compare(heapSubstr, value); Assert.Equal(Math.Sign(expectedCmp), Math.Sign(actualCmp)); } if (!ignoreCase) { TestComparison(block, offset, value, heapSubstr, decoder, ignoreCase: true); } TestComparison(block, offset, value, heapSubstr, decoder, ignoreCase); } }