Skip to content

Commit 0bab8a0

Browse files
authored
Reduce "unsafe" by replacing byte* pointer usage with ReadOnlySpan<byte> (#3106)
1 parent eae54dd commit 0bab8a0

12 files changed

+133
-89
lines changed

ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System;
2+
using System.Buffers.Binary;
23
using System.Collections.Generic;
34
using System.Collections.Immutable;
45
using System.Linq;
@@ -384,11 +385,13 @@ public static IEnumerable<MethodSpecificationHandle> GetMethodSpecifications(thi
384385
yield return Read(row);
385386
}
386387

387-
unsafe (Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association) Read(int row)
388+
(Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association) Read(int row)
388389
{
389-
byte* ptr = metadata.MetadataPointer + offset + rowSize * row;
390-
int methodDef = methodSmall ? *(ushort*)(ptr + 2) : (int)*(uint*)(ptr + 2);
391-
int assocDef = assocSmall ? *(ushort*)(ptr + assocOffset) : (int)*(uint*)(ptr + assocOffset);
390+
var span = metadata.AsReadOnlySpan();
391+
var methodDefSpan = span.Slice(offset + rowSize * row + 2);
392+
int methodDef = methodSmall ? BinaryPrimitives.ReadUInt16LittleEndian(methodDefSpan) : (int)BinaryPrimitives.ReadUInt32LittleEndian(methodDefSpan);
393+
var assocSpan = span.Slice(assocOffset);
394+
int assocDef = assocSmall ? BinaryPrimitives.ReadUInt16LittleEndian(assocSpan) : (int)BinaryPrimitives.ReadUInt32LittleEndian(assocSpan);
392395
EntityHandle propOrEvent;
393396
if ((assocDef & 0x1) == 1)
394397
{
@@ -398,7 +401,7 @@ public static IEnumerable<MethodSpecificationHandle> GetMethodSpecifications(thi
398401
{
399402
propOrEvent = MetadataTokens.EventDefinitionHandle(assocDef >> 1);
400403
}
401-
return (MetadataTokens.Handle(0x18000000 | (row + 1)), (MethodSemanticsAttributes)(*(ushort*)ptr), MetadataTokens.MethodDefinitionHandle(methodDef), propOrEvent);
404+
return (MetadataTokens.Handle(0x18000000 | (row + 1)), (MethodSemanticsAttributes)(BinaryPrimitives.ReadUInt16LittleEndian(span)), MetadataTokens.MethodDefinitionHandle(methodDef), propOrEvent);
402405
}
403406
}
404407

@@ -411,9 +414,9 @@ public static IEnumerable<EntityHandle> GetFieldLayouts(this MetadataReader meta
411414
}
412415
}
413416

414-
public unsafe static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout(this MetadataReader metadata, EntityHandle fieldLayoutHandle)
417+
public static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout(this MetadataReader metadata, EntityHandle fieldLayoutHandle)
415418
{
416-
byte* startPointer = metadata.MetadataPointer;
419+
var startPointer = metadata.AsReadOnlySpan();
417420
int offset = metadata.GetTableMetadataOffset(TableIndex.FieldLayout);
418421
int rowSize = metadata.GetTableRowSize(TableIndex.FieldLayout);
419422
int rowCount = metadata.GetTableRowCount(TableIndex.FieldLayout);
@@ -422,14 +425,31 @@ public unsafe static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout
422425
bool small = metadata.GetTableRowCount(TableIndex.Field) <= ushort.MaxValue;
423426
for (int row = rowCount - 1; row >= 0; row--)
424427
{
425-
byte* ptr = startPointer + offset + rowSize * row;
426-
uint rowNo = small ? *(ushort*)(ptr + 4) : *(uint*)(ptr + 4);
428+
ReadOnlySpan<byte> ptr = startPointer.Slice(offset + rowSize * row);
429+
var rowNoSpan = ptr.Slice(4);
430+
uint rowNo = small ? BinaryPrimitives.ReadUInt16LittleEndian(rowNoSpan) : BinaryPrimitives.ReadUInt32LittleEndian(rowNoSpan);
427431
if (fieldRowNo == rowNo)
428432
{
429-
return (*(int*)ptr, MetadataTokens.FieldDefinitionHandle(fieldRowNo));
433+
return (BinaryPrimitives.ReadInt32LittleEndian(ptr), MetadataTokens.FieldDefinitionHandle(fieldRowNo));
430434
}
431435
}
432436
return (0, default);
433437
}
438+
439+
public static ReadOnlySpan<byte> AsReadOnlySpan(this MetadataReader metadataReader)
440+
{
441+
unsafe
442+
{
443+
return new(metadataReader.MetadataPointer, metadataReader.MetadataLength);
444+
}
445+
}
446+
447+
public static BlobReader AsBlobReader(this MetadataReader metadataReader)
448+
{
449+
unsafe
450+
{
451+
return new(metadataReader.MetadataPointer, metadataReader.MetadataLength);
452+
}
453+
}
434454
}
435455
}

ILSpy/Metadata/CorTables/ClassLayoutTableTreeNode.cs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
using System;
20+
using System.Buffers.Binary;
1921
using System.Collections.Generic;
2022
using System.Reflection.Metadata;
2123
using System.Reflection.Metadata.Ecma335;
@@ -38,7 +40,7 @@ public ClassLayoutTableTreeNode(PEFile module)
3840

3941
public override object Icon => Images.Literal;
4042

41-
public unsafe override bool View(ViewModels.TabPageModel tabPage)
43+
public override bool View(ViewModels.TabPageModel tabPage)
4244
{
4345
tabPage.Title = Text.ToString();
4446
tabPage.SupportsLanguageSwitching = false;
@@ -49,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
4951
var list = new List<ClassLayoutEntry>();
5052

5153
var length = metadata.GetTableRowCount(TableIndex.ClassLayout);
52-
byte* ptr = metadata.MetadataPointer;
54+
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
5355
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
5456
ClassLayoutEntry scrollTargetEntry = default;
5557

@@ -80,15 +82,15 @@ readonly struct ClassLayout
8082
public readonly EntityHandle Parent;
8183
public readonly uint ClassSize;
8284

83-
public unsafe ClassLayout(byte* ptr, int typeDefSize)
85+
public ClassLayout(ReadOnlySpan<byte> ptr, int typeDefSize)
8486
{
85-
PackingSize = (ushort)Helpers.GetValue(ptr, 2);
86-
ClassSize = (uint)Helpers.GetValue(ptr + 2, 4);
87-
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValue(ptr + 6, typeDefSize));
87+
PackingSize = BinaryPrimitives.ReadUInt16LittleEndian(ptr);
88+
ClassSize = BinaryPrimitives.ReadUInt32LittleEndian(ptr.Slice(2, 4));
89+
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(6, typeDefSize)));
8890
}
8991
}
9092

91-
unsafe struct ClassLayoutEntry
93+
struct ClassLayoutEntry
9294
{
9395
readonly PEFile module;
9496
readonly MetadataReader metadata;
@@ -117,15 +119,15 @@ public void OnParentClick()
117119
[ColumnInfo("X8", Kind = ColumnKind.Other)]
118120
public uint ClassSize => classLayout.ClassSize;
119121

120-
public ClassLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
122+
public ClassLayoutEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
121123
{
122124
this.module = module;
123125
this.metadata = module.Metadata;
124126
this.RID = row;
125127
var rowOffset = metadata.GetTableMetadataOffset(TableIndex.ClassLayout)
126128
+ metadata.GetTableRowSize(TableIndex.ClassLayout) * (row - 1);
127129
this.Offset = metadataOffset + rowOffset;
128-
this.classLayout = new ClassLayout(ptr + rowOffset, metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4);
130+
this.classLayout = new ClassLayout(ptr.Slice(rowOffset), metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4);
129131
this.parentTooltip = null;
130132
}
131133
}

ILSpy/Metadata/CorTables/EventMapTableTreeNode.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
using System;
1920
using System.Collections.Generic;
2021
using System.Reflection.Metadata;
2122
using System.Reflection.Metadata.Ecma335;
@@ -38,7 +39,7 @@ public EventMapTableTreeNode(PEFile module)
3839

3940
public override object Icon => Images.Literal;
4041

41-
public unsafe override bool View(ViewModels.TabPageModel tabPage)
42+
public override bool View(ViewModels.TabPageModel tabPage)
4243
{
4344
tabPage.Title = Text.ToString();
4445
tabPage.SupportsLanguageSwitching = false;
@@ -50,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
5051
EventMapEntry scrollTargetEntry = default;
5152

5253
var length = metadata.GetTableRowCount(TableIndex.EventMap);
53-
byte* ptr = metadata.MetadataPointer;
54+
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
5455
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
5556
for (int rid = 1; rid <= length; rid++)
5657
{
@@ -79,14 +80,14 @@ readonly struct EventMap
7980
public readonly TypeDefinitionHandle Parent;
8081
public readonly EventDefinitionHandle EventList;
8182

82-
public unsafe EventMap(byte* ptr, int typeDefSize, int eventDefSize)
83+
public EventMap(ReadOnlySpan<byte> ptr, int typeDefSize, int eventDefSize)
8384
{
84-
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValue(ptr, typeDefSize));
85-
EventList = MetadataTokens.EventDefinitionHandle(Helpers.GetValue(ptr + typeDefSize, eventDefSize));
85+
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(0, typeDefSize)));
86+
EventList = MetadataTokens.EventDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(typeDefSize, eventDefSize)));
8687
}
8788
}
8889

89-
unsafe struct EventMapEntry
90+
struct EventMapEntry
9091
{
9192
readonly PEFile module;
9293
readonly MetadataReader metadata;
@@ -120,7 +121,7 @@ public void OnEventListClick()
120121
string eventListTooltip;
121122
public string EventListTooltip => GenerateTooltip(ref eventListTooltip, module, eventMap.EventList);
122123

123-
public EventMapEntry(PEFile module, byte* ptr, int metadataOffset, int row)
124+
public EventMapEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
124125
{
125126
this.module = module;
126127
this.metadata = module.Metadata;
@@ -130,7 +131,7 @@ public EventMapEntry(PEFile module, byte* ptr, int metadataOffset, int row)
130131
this.Offset = metadataOffset + rowOffset;
131132
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4;
132133
int eventDefSize = metadata.GetTableRowCount(TableIndex.Event) < ushort.MaxValue ? 2 : 4;
133-
this.eventMap = new EventMap(ptr + rowOffset, typeDefSize, eventDefSize);
134+
this.eventMap = new EventMap(ptr.Slice(rowOffset), typeDefSize, eventDefSize);
134135
this.parentTooltip = null;
135136
this.eventListTooltip = null;
136137
}

ILSpy/Metadata/CorTables/FieldLayoutTableTreeNode.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
using System;
20+
using System.Buffers.Binary;
1921
using System.Collections.Generic;
2022
using System.Reflection.Metadata;
2123
using System.Reflection.Metadata.Ecma335;
@@ -38,7 +40,7 @@ public FieldLayoutTableTreeNode(PEFile module)
3840

3941
public override object Icon => Images.Literal;
4042

41-
public unsafe override bool View(ViewModels.TabPageModel tabPage)
43+
public override bool View(ViewModels.TabPageModel tabPage)
4244
{
4345
tabPage.Title = Text.ToString();
4446
tabPage.SupportsLanguageSwitching = false;
@@ -50,7 +52,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
5052
FieldLayoutEntry scrollTargetEntry = default;
5153

5254
var length = metadata.GetTableRowCount(TableIndex.FieldLayout);
53-
byte* ptr = metadata.MetadataPointer;
55+
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
5456
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
5557
for (int rid = 1; rid <= length; rid++)
5658
{
@@ -79,14 +81,14 @@ readonly struct FieldLayout
7981
public readonly int Offset;
8082
public readonly FieldDefinitionHandle Field;
8183

82-
public unsafe FieldLayout(byte* ptr, int fieldDefSize)
84+
public FieldLayout(ReadOnlySpan<byte> ptr, int fieldDefSize)
8385
{
84-
Offset = Helpers.GetValue(ptr, 4);
85-
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValue(ptr + 4, fieldDefSize));
86+
Offset = BinaryPrimitives.ReadInt32LittleEndian(ptr);
87+
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(4, fieldDefSize)));
8688
}
8789
}
8890

89-
unsafe struct FieldLayoutEntry
91+
struct FieldLayoutEntry
9092
{
9193
readonly PEFile module;
9294
readonly MetadataReader metadata;
@@ -112,7 +114,7 @@ public void OnFieldClick()
112114
[ColumnInfo("X8", Kind = ColumnKind.Other)]
113115
public int FieldOffset => fieldLayout.Offset;
114116

115-
public FieldLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
117+
public FieldLayoutEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
116118
{
117119
this.module = module;
118120
this.metadata = module.Metadata;
@@ -121,7 +123,7 @@ public FieldLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
121123
+ metadata.GetTableRowSize(TableIndex.FieldLayout) * (row - 1);
122124
this.Offset = metadataOffset + rowOffset;
123125
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4;
124-
this.fieldLayout = new FieldLayout(ptr + rowOffset, fieldDefSize);
126+
this.fieldLayout = new FieldLayout(ptr.Slice(rowOffset), fieldDefSize);
125127
this.fieldTooltip = null;
126128
}
127129
}

ILSpy/Metadata/CorTables/FieldMarshalTableTreeNode.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
using System;
1920
using System.Collections.Generic;
2021
using System.Reflection.Metadata;
2122
using System.Reflection.Metadata.Ecma335;
@@ -38,7 +39,7 @@ public FieldMarshalTableTreeNode(PEFile module)
3839

3940
public override object Icon => Images.Literal;
4041

41-
public unsafe override bool View(ViewModels.TabPageModel tabPage)
42+
public override bool View(ViewModels.TabPageModel tabPage)
4243
{
4344
tabPage.Title = Text.ToString();
4445
tabPage.SupportsLanguageSwitching = false;
@@ -50,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
5051
FieldMarshalEntry scrollTargetEntry = default;
5152

5253
var length = metadata.GetTableRowCount(TableIndex.FieldMarshal);
53-
byte* ptr = metadata.MetadataPointer;
54+
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
5455
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
5556
for (int rid = 1; rid <= length; rid++)
5657
{
@@ -79,14 +80,14 @@ readonly struct FieldMarshal
7980
public readonly BlobHandle NativeType;
8081
public readonly EntityHandle Parent;
8182

82-
public unsafe FieldMarshal(byte* ptr, int blobHeapSize, int hasFieldMarshalRefSize)
83+
public FieldMarshal(ReadOnlySpan<byte> ptr, int blobHeapSize, int hasFieldMarshalRefSize)
8384
{
84-
Parent = Helpers.FromHasFieldMarshalTag((uint)Helpers.GetValue(ptr, hasFieldMarshalRefSize));
85-
NativeType = MetadataTokens.BlobHandle(Helpers.GetValue(ptr + hasFieldMarshalRefSize, blobHeapSize));
85+
Parent = Helpers.FromHasFieldMarshalTag((uint)Helpers.GetValueLittleEndian(ptr, hasFieldMarshalRefSize));
86+
NativeType = MetadataTokens.BlobHandle(Helpers.GetValueLittleEndian(ptr.Slice(hasFieldMarshalRefSize, blobHeapSize)));
8687
}
8788
}
8889

89-
unsafe struct FieldMarshalEntry
90+
struct FieldMarshalEntry
9091
{
9192
readonly PEFile module;
9293
readonly MetadataReader metadata;
@@ -112,7 +113,7 @@ public void OnParentClick()
112113
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
113114
public int NativeType => MetadataTokens.GetHeapOffset(fieldMarshal.NativeType);
114115

115-
public FieldMarshalEntry(PEFile module, byte* ptr, int metadataOffset, int row)
116+
public FieldMarshalEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
116117
{
117118
this.module = module;
118119
this.metadata = module.Metadata;
@@ -122,7 +123,7 @@ public FieldMarshalEntry(PEFile module, byte* ptr, int metadataOffset, int row)
122123
this.Offset = metadataOffset + rowOffset;
123124
int hasFieldMarshalRefSize = metadata.ComputeCodedTokenSize(32768, TableMask.Field | TableMask.Param);
124125
int blobHeapSize = metadata.GetHeapSize(HeapIndex.Blob) < ushort.MaxValue ? 2 : 4;
125-
this.fieldMarshal = new FieldMarshal(ptr + rowOffset, blobHeapSize, hasFieldMarshalRefSize);
126+
this.fieldMarshal = new FieldMarshal(ptr.Slice(rowOffset), blobHeapSize, hasFieldMarshalRefSize);
126127
this.parentTooltip = null;
127128
}
128129
}

ILSpy/Metadata/CorTables/FieldRVATableTreeNode.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
1717
// DEALINGS IN THE SOFTWARE.
1818

19+
using System;
20+
using System.Buffers.Binary;
1921
using System.Collections.Generic;
2022
using System.Reflection.Metadata;
2123
using System.Reflection.Metadata.Ecma335;
@@ -38,7 +40,7 @@ public FieldRVATableTreeNode(PEFile module)
3840

3941
public override object Icon => Images.Literal;
4042

41-
public unsafe override bool View(ViewModels.TabPageModel tabPage)
43+
public override bool View(ViewModels.TabPageModel tabPage)
4244
{
4345
tabPage.Title = Text.ToString();
4446
tabPage.SupportsLanguageSwitching = false;
@@ -50,7 +52,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
5052
FieldRVAEntry scrollTargetEntry = default;
5153

5254
var length = metadata.GetTableRowCount(TableIndex.FieldRva);
53-
byte* ptr = metadata.MetadataPointer;
55+
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
5456
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
5557
for (int rid = 1; rid <= length; rid++)
5658
{
@@ -79,14 +81,14 @@ readonly struct FieldRVA
7981
public readonly int Offset;
8082
public readonly FieldDefinitionHandle Field;
8183

82-
public unsafe FieldRVA(byte* ptr, int fieldDefSize)
84+
public FieldRVA(ReadOnlySpan<byte> ptr, int fieldDefSize)
8385
{
84-
Offset = Helpers.GetValue(ptr, 4);
85-
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValue(ptr + 4, fieldDefSize));
86+
Offset = BinaryPrimitives.ReadInt32LittleEndian(ptr);
87+
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(4, fieldDefSize)));
8688
}
8789
}
8890

89-
unsafe struct FieldRVAEntry
91+
struct FieldRVAEntry
9092
{
9193
readonly PEFile module;
9294
readonly MetadataReader metadata;
@@ -112,7 +114,7 @@ public void OnFieldClick()
112114
[ColumnInfo("X8", Kind = ColumnKind.Other)]
113115
public int FieldOffset => fieldRVA.Offset;
114116

115-
public FieldRVAEntry(PEFile module, byte* ptr, int metadataOffset, int row)
117+
public FieldRVAEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
116118
{
117119
this.module = module;
118120
this.metadata = module.Metadata;
@@ -121,7 +123,7 @@ public FieldRVAEntry(PEFile module, byte* ptr, int metadataOffset, int row)
121123
+ metadata.GetTableRowSize(TableIndex.FieldRva) * (row - 1);
122124
this.Offset = metadataOffset + rowOffset;
123125
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4;
124-
this.fieldRVA = new FieldRVA(ptr + rowOffset, fieldDefSize);
126+
this.fieldRVA = new FieldRVA(ptr.Slice(rowOffset), fieldDefSize);
125127
this.fieldTooltip = null;
126128
}
127129
}

0 commit comments

Comments
 (0)