Skip to content

Commit 452da0c

Browse files
TIHanbaronfel
authored andcommitted
Slicing and copying on ByteMemory should not throw if length is zero (#8282)
* Slicing and copying on ByteMemory should not throw if length is zero * Added slice count check * Changed length check on stream creation * Remove empty * Minor format change * Check length before using AsStream * Remove exception throwing from creating a stream * Added checkCount * Remove checkReadCount
1 parent e7555f2 commit 452da0c

File tree

1 file changed

+85
-29
lines changed

1 file changed

+85
-29
lines changed

src/absil/bytes.fs

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ type ByteMemory () =
6666
type ByteArrayMemory(bytes: byte[], offset, length) =
6767
inherit ByteMemory()
6868

69+
let checkCount count =
70+
if count < 0 then
71+
raise (ArgumentOutOfRangeException("count", "Count is less than zero."))
72+
6973
do
7074
if length < 0 || length > bytes.Length then
7175
raise (ArgumentOutOfRangeException("length"))
@@ -80,7 +84,11 @@ type ByteArrayMemory(bytes: byte[], offset, length) =
8084
override _.Length = length
8185

8286
override _.ReadBytes(pos, count) =
83-
Array.sub bytes (offset + pos) count
87+
checkCount count
88+
if count > 0 then
89+
Array.sub bytes (offset + pos) count
90+
else
91+
Array.empty
8492

8593
override _.ReadInt32 pos =
8694
let finalOffset = offset + pos
@@ -96,25 +104,45 @@ type ByteArrayMemory(bytes: byte[], offset, length) =
96104
((uint16 bytes.[finalOffset + 1]) <<< 8)
97105

98106
override _.ReadUtf8String(pos, count) =
99-
System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count)
107+
checkCount count
108+
if count > 0 then
109+
System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count)
110+
else
111+
String.Empty
100112

101113
override _.Slice(pos, count) =
102-
ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory
114+
checkCount count
115+
if count > 0 then
116+
ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory
117+
else
118+
ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory
103119

104120
override _.CopyTo stream =
105-
stream.Write(bytes, offset, length)
121+
if length > 0 then
122+
stream.Write(bytes, offset, length)
106123

107124
override _.Copy(srcOffset, dest, destOffset, count) =
108-
Array.blit bytes (offset + srcOffset) dest destOffset count
125+
checkCount count
126+
if count > 0 then
127+
Array.blit bytes (offset + srcOffset) dest destOffset count
109128

110129
override _.ToArray() =
111-
Array.sub bytes offset length
130+
if length > 0 then
131+
Array.sub bytes offset length
132+
else
133+
Array.empty
112134

113135
override _.AsStream() =
114-
new MemoryStream(bytes, offset, length) :> Stream
136+
if length > 0 then
137+
new MemoryStream(bytes, offset, length) :> Stream
138+
else
139+
new MemoryStream([||], 0, 0, false) :> Stream
115140

116141
override _.AsReadOnlyStream() =
117-
new MemoryStream(bytes, offset, length, false) :> Stream
142+
if length > 0 then
143+
new MemoryStream(bytes, offset, length, false) :> Stream
144+
else
145+
new MemoryStream([||], 0, 0, false) :> Stream
118146

119147
[<Sealed>]
120148
type SafeUnmanagedMemoryStream =
@@ -149,6 +177,10 @@ type RawByteMemory(addr: nativeptr<byte>, length: int, holder: obj) =
149177
if i < 0 || i >= length then
150178
raise (ArgumentOutOfRangeException("i"))
151179

180+
let checkCount count =
181+
if count < 0 then
182+
raise (ArgumentOutOfRangeException("count", "Count is less than zero."))
183+
152184
do
153185
if length < 0 then
154186
raise (ArgumentOutOfRangeException("length"))
@@ -165,16 +197,24 @@ type RawByteMemory(addr: nativeptr<byte>, length: int, holder: obj) =
165197
override _.Length = length
166198

167199
override _.ReadUtf8String(pos, count) =
168-
check pos
169-
check (pos + count - 1)
170-
System.Text.Encoding.UTF8.GetString(NativePtr.add addr pos, count)
200+
checkCount count
201+
if count > 0 then
202+
check pos
203+
check (pos + count - 1)
204+
System.Text.Encoding.UTF8.GetString(NativePtr.add addr pos, count)
205+
else
206+
String.Empty
171207

172-
override _.ReadBytes(pos, count) =
173-
check pos
174-
check (pos + count - 1)
175-
let res = Bytes.zeroCreate count
176-
Marshal.Copy(NativePtr.toNativeInt addr + nativeint pos, res, 0, count)
177-
res
208+
override _.ReadBytes(pos, count) =
209+
checkCount count
210+
if count > 0 then
211+
check pos
212+
check (pos + count - 1)
213+
let res = Bytes.zeroCreate count
214+
Marshal.Copy(NativePtr.toNativeInt addr + nativeint pos, res, 0, count)
215+
res
216+
else
217+
Array.empty
178218

179219
override _.ReadInt32 pos =
180220
check pos
@@ -187,28 +227,44 @@ type RawByteMemory(addr: nativeptr<byte>, length: int, holder: obj) =
187227
uint16(Marshal.ReadInt16(NativePtr.toNativeInt addr + nativeint pos))
188228

189229
override _.Slice(pos, count) =
190-
check pos
191-
check (pos + count - 1)
192-
RawByteMemory(NativePtr.add addr pos, count, holder) :> ByteMemory
230+
checkCount count
231+
if count > 0 then
232+
check pos
233+
check (pos + count - 1)
234+
RawByteMemory(NativePtr.add addr pos, count, holder) :> ByteMemory
235+
else
236+
ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory
193237

194238
override x.CopyTo stream =
195-
use stream2 = x.AsStream()
196-
stream2.CopyTo stream
239+
if length > 0 then
240+
use stream2 = x.AsStream()
241+
stream2.CopyTo stream
197242

198243
override _.Copy(srcOffset, dest, destOffset, count) =
199-
check srcOffset
200-
Marshal.Copy(NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count)
244+
checkCount count
245+
if count > 0 then
246+
check srcOffset
247+
Marshal.Copy(NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count)
201248

202249
override _.ToArray() =
203-
let res = Array.zeroCreate<byte> length
204-
Marshal.Copy(NativePtr.toNativeInt addr, res, 0, res.Length)
205-
res
250+
if length > 0 then
251+
let res = Array.zeroCreate<byte> length
252+
Marshal.Copy(NativePtr.toNativeInt addr, res, 0, res.Length)
253+
res
254+
else
255+
Array.empty
206256

207257
override _.AsStream() =
208-
new SafeUnmanagedMemoryStream(addr, int64 length, holder) :> Stream
258+
if length > 0 then
259+
new SafeUnmanagedMemoryStream(addr, int64 length, holder) :> Stream
260+
else
261+
new MemoryStream([||], 0, 0, false) :> Stream
209262

210263
override _.AsReadOnlyStream() =
211-
new SafeUnmanagedMemoryStream(addr, int64 length, int64 length, FileAccess.Read, holder) :> Stream
264+
if length > 0 then
265+
new SafeUnmanagedMemoryStream(addr, int64 length, int64 length, FileAccess.Read, holder) :> Stream
266+
else
267+
new MemoryStream([||], 0, 0, false) :> Stream
212268

213269
[<Struct;NoEquality;NoComparison>]
214270
type ReadOnlyByteMemory(bytes: ByteMemory) =

0 commit comments

Comments
 (0)