Skip to content

Commit 5d4827a

Browse files
authored
CSHARP-5614: Fix deserialization of primitive arrays on Big Endian systems (#1683)
1 parent cc69339 commit 5d4827a

File tree

1 file changed

+23
-20
lines changed

1 file changed

+23
-20
lines changed

src/MongoDB.Bson/Serialization/Serializers/PrimitivesArrayReader.cs

Lines changed: 23 additions & 20 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.Runtime.CompilerServices;
45
using MongoDB.Bson.IO;
@@ -73,7 +74,8 @@ private static T[] ReadBsonArray<T>(
7374
using var buffer = ThreadStaticBuffer.RentBuffer(array.Length);
7475

7576
var bytes = buffer.Bytes;
76-
array.GetBytes(0, bytes, 0, array.Length);
77+
array.GetBytes(0, bytes, 0, array.Length);
78+
var span = bytes.AsSpan();
7779

7880
var result = new List<T>();
7981

@@ -82,10 +84,10 @@ private static T[] ReadBsonArray<T>(
8284

8385
while (index < maxIndex)
8486
{
85-
ValidateBsonType(bsonDataType);
87+
ValidateBsonType(bsonDataType, span);
8688

8789
// Skip name
88-
while (bytes[index] != 0) { index++; };
90+
while (span[index] != 0) { index++; }
8991
index++; // Skip string terminating 0
9092

9193
T value = default;
@@ -95,85 +97,86 @@ private static T[] ReadBsonArray<T>(
9597
{
9698
case ConversionType.DoubleToSingle:
9799
{
98-
var v = (float)BitConverter.ToDouble(bytes, index);
100+
var v = (float)BinaryPrimitivesCompat.ReadDoubleLittleEndian(span.Slice(index));
99101

100102
value = Unsafe.As<float, T>(ref v);
101103
break;
102104
}
103105
case ConversionType.DoubleToDouble:
104106
{
105-
var v = BitConverter.ToDouble(bytes, index);
107+
var v = BinaryPrimitivesCompat.ReadDoubleLittleEndian(span.Slice(index));
108+
106109
value = Unsafe.As<double, T>(ref v);
107110
break;
108111
}
109112
case ConversionType.Decimal128ToDecimal128:
110113
{
111-
var lowBits = (ulong)BitConverter.ToInt64(bytes, index);
112-
var highBits = (ulong)BitConverter.ToInt64(bytes, index + 8);
114+
var lowBits = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(index));
115+
var highBits = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(index + 8));
113116
var v = Decimal128.ToDecimal(Decimal128.FromIEEEBits(highBits, lowBits));
114117

115118
value = Unsafe.As<decimal, T>(ref v);
116119
break;
117120
}
118121
case ConversionType.BoolToBool:
119122
{
120-
var v = bytes[index] != 0;
123+
var v = span[index] != 0;
121124

122125
value = Unsafe.As<bool, T>(ref v);
123126
break;
124127
}
125128
case ConversionType.Int32ToInt8:
126129
{
127-
var v = (sbyte)BitConverter.ToInt32(bytes, index);
130+
var v = (sbyte)BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
128131
value = Unsafe.As<sbyte, T>(ref v);
129132

130133
break;
131134
}
132135
case ConversionType.Int32ToUInt8:
133136
{
134-
var v = (byte)BitConverter.ToInt32(bytes, index);
137+
var v = (byte)BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
135138
value = Unsafe.As<byte, T>(ref v);
136139
break;
137140
}
138141
case ConversionType.Int32ToInt16:
139142
{
140-
var v = (short)BitConverter.ToInt32(bytes, index);
143+
var v = (short)BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
141144
value = Unsafe.As<short, T>(ref v);
142145
break;
143146
}
144147
case ConversionType.Int32ToUInt16:
145148
{
146-
var v = (ushort)BitConverter.ToInt32(bytes, index);
149+
var v = (ushort)BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
147150
value = Unsafe.As<ushort, T>(ref v);
148151
break;
149152
}
150153
case ConversionType.Int32ToChar:
151154
{
152-
var v = BitConverter.ToChar(bytes, index);
155+
var v = (char)(ushort)BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
153156
value = Unsafe.As<char, T>(ref v);
154157
break;
155158
}
156159
case ConversionType.Int32ToInt32:
157160
{
158-
var v = BitConverter.ToInt32(bytes, index);
161+
var v = BinaryPrimitives.ReadInt32LittleEndian(span.Slice(index));
159162
value = Unsafe.As<int, T>(ref v);
160163
break;
161164
}
162165
case ConversionType.Int32ToUInt32:
163166
{
164-
var v = BitConverter.ToUInt32(bytes, index);
167+
var v = BinaryPrimitives.ReadUInt32LittleEndian(span.Slice(index));
165168
value = Unsafe.As<uint, T>(ref v);
166169
break;
167170
}
168171
case ConversionType.Int64ToInt64:
169172
{
170-
var v = BitConverter.ToInt64(bytes, index);
173+
var v = BinaryPrimitives.ReadInt64LittleEndian(span.Slice(index));
171174
value = Unsafe.As<long, T>(ref v);
172175
break;
173176
}
174177
case ConversionType.Int64ToUInt64:
175178
{
176-
var v = BitConverter.ToUInt64(bytes, index);
179+
var v = BinaryPrimitives.ReadUInt64LittleEndian(span.Slice(index));
177180
value = Unsafe.As<ulong, T>(ref v);
178181
break;
179182
}
@@ -186,13 +189,13 @@ private static T[] ReadBsonArray<T>(
186189
index += bsonDataSize;
187190
}
188191

189-
ValidateBsonType(BsonType.EndOfDocument);
192+
ValidateBsonType(BsonType.EndOfDocument, span);
190193

191194
return result.ToArray();
192195

193-
void ValidateBsonType(BsonType bsonType)
196+
void ValidateBsonType(BsonType bsonType, Span<byte> span)
194197
{
195-
if ((BsonType)bytes[index] != bsonType)
198+
if ((BsonType)span[index] != bsonType)
196199
{
197200
throw new InvalidOperationException();
198201
}

0 commit comments

Comments
 (0)