From 0b94b222c9be38d47aed0469196bab9e7c4a490d Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:02:08 -0800 Subject: [PATCH 1/9] Slicing and copying on ByteMemory should not throw if length is zero --- src/absil/bytes.fs | 53 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index 89556fc968..db966d1eaa 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -66,6 +66,10 @@ type ByteMemory () = type ByteArrayMemory(bytes: byte[], offset, length) = inherit ByteMemory() + let checkLengthForStream () = + if length = 0 then + raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) + do if length < 0 || length > bytes.Length then raise (ArgumentOutOfRangeException("length")) @@ -99,21 +103,28 @@ type ByteArrayMemory(bytes: byte[], offset, length) = System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count) override _.Slice(pos, count) = - ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory + if count = 0 then + ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory + else + ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory override _.CopyTo stream = - stream.Write(bytes, offset, length) + if length > 0 then + stream.Write(bytes, offset, length) override _.Copy(srcOffset, dest, destOffset, count) = - Array.blit bytes (offset + srcOffset) dest destOffset count + if count > 0 then + Array.blit bytes (offset + srcOffset) dest destOffset count override _.ToArray() = Array.sub bytes offset length override _.AsStream() = + checkLengthForStream () new MemoryStream(bytes, offset, length) :> Stream override _.AsReadOnlyStream() = + checkLengthForStream () new MemoryStream(bytes, offset, length, false) :> Stream [] @@ -154,6 +165,10 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = if i < 0 || i >= length then raise (ArgumentOutOfRangeException("i")) + let checkLengthForStream () = + if length = 0 then + raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) + do if length < 0 then raise (ArgumentOutOfRangeException("length")) @@ -192,27 +207,37 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = uint16(Marshal.ReadInt16(NativePtr.toNativeInt addr + nativeint pos)) override _.Slice(pos, count) = - check pos - check (pos + count - 1) - RawByteMemory(NativePtr.add addr pos, count, hold) :> ByteMemory + if count = 0 then + ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory + else + check pos + check (pos + count - 1) + RawByteMemory(NativePtr.add addr pos, count, hold) :> ByteMemory override x.CopyTo stream = - use stream2 = x.AsStream() - stream2.CopyTo stream + if length > 0 then + use stream2 = x.AsStream() + stream2.CopyTo stream override _.Copy(srcOffset, dest, destOffset, count) = - check srcOffset - Marshal.Copy(NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count) + if count > 0 then + check srcOffset + Marshal.Copy(NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count) override _.ToArray() = - let res = Array.zeroCreate length - Marshal.Copy(NativePtr.toNativeInt addr, res, 0, res.Length) - res + if length > 0 then + let res = Array.zeroCreate length + Marshal.Copy(NativePtr.toNativeInt addr, res, 0, res.Length) + res + else + Array.empty override _.AsStream() = + checkLengthForStream () new SafeUnmanagedMemoryStream(addr, int64 length, hold) :> Stream override _.AsReadOnlyStream() = + checkLengthForStream () new SafeUnmanagedMemoryStream(addr, int64 length, int64 length, FileAccess.Read, hold) :> Stream [] @@ -244,6 +269,8 @@ type ByteMemory with member x.AsReadOnly() = ReadOnlyByteMemory x + static member Empty = ByteArrayMemory(null, 0, 0) + static member CreateMemoryMappedFile(bytes: ReadOnlyByteMemory) = let length = int64 bytes.Length let mmf = From fcb8157f186978ec3f454f1ddc912fbe28e5ce29 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:10:27 -0800 Subject: [PATCH 2/9] Added slice count check --- src/absil/bytes.fs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index db966d1eaa..dad61db7fc 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -70,6 +70,10 @@ type ByteArrayMemory(bytes: byte[], offset, length) = if length = 0 then raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) + let checkReadCount count = + if count <= 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) + do if length < 0 || length > bytes.Length then raise (ArgumentOutOfRangeException("length")) @@ -84,6 +88,7 @@ type ByteArrayMemory(bytes: byte[], offset, length) = override _.Length = length override _.ReadBytes(pos, count) = + checkReadCount count Array.sub bytes (offset + pos) count override _.ReadInt32 pos = @@ -100,13 +105,17 @@ type ByteArrayMemory(bytes: byte[], offset, length) = ((uint16 bytes.[finalOffset + 1]) <<< 8) override _.ReadUtf8String(pos, count) = + checkReadCount count System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count) override _.Slice(pos, count) = - if count = 0 then - ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory - else + if count > 0 then ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory + else + if count < 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) + + ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory override _.CopyTo stream = if length > 0 then @@ -117,7 +126,10 @@ type ByteArrayMemory(bytes: byte[], offset, length) = Array.blit bytes (offset + srcOffset) dest destOffset count override _.ToArray() = - Array.sub bytes offset length + if length > 0 then + Array.sub bytes offset length + else + Array.empty override _.AsStream() = checkLengthForStream () @@ -165,6 +177,10 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = if i < 0 || i >= length then raise (ArgumentOutOfRangeException("i")) + let checkReadCount count = + if count <= 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) + let checkLengthForStream () = if length = 0 then raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) @@ -185,11 +201,13 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = override _.Length = length override _.ReadUtf8String(pos, count) = + checkReadCount count check pos check (pos + count - 1) System.Text.Encoding.UTF8.GetString(NativePtr.add addr pos, count) override _.ReadBytes(pos, count) = + checkReadCount count check pos check (pos + count - 1) let res = Bytes.zeroCreate count @@ -207,12 +225,14 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = uint16(Marshal.ReadInt16(NativePtr.toNativeInt addr + nativeint pos)) override _.Slice(pos, count) = - if count = 0 then - ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory - else + if count > 0 then check pos check (pos + count - 1) RawByteMemory(NativePtr.add addr pos, count, hold) :> ByteMemory + else + if count < 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) + ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory override x.CopyTo stream = if length > 0 then From 86ee8b0665abfc6201cc164d01259a5126ac37e3 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:11:55 -0800 Subject: [PATCH 3/9] Changed length check on stream creation --- src/absil/bytes.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index dad61db7fc..edb995aa7d 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -67,8 +67,8 @@ type ByteArrayMemory(bytes: byte[], offset, length) = inherit ByteMemory() let checkLengthForStream () = - if length = 0 then - raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) + if length <= 0 then + raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero or less.")) let checkReadCount count = if count <= 0 then @@ -182,8 +182,8 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) let checkLengthForStream () = - if length = 0 then - raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero.")) + if length <= 0 then + raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero or less.")) do if length < 0 then From 3c16fd5bacd674c2591bcf4f52fb830671aa7740 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:12:29 -0800 Subject: [PATCH 4/9] Remove empty --- src/absil/bytes.fs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index edb995aa7d..6d3fab122b 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -289,8 +289,6 @@ type ByteMemory with member x.AsReadOnly() = ReadOnlyByteMemory x - static member Empty = ByteArrayMemory(null, 0, 0) - static member CreateMemoryMappedFile(bytes: ReadOnlyByteMemory) = let length = int64 bytes.Length let mmf = From 8be248d574526af59bd98c9b867fa4a00b87a4c8 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:14:08 -0800 Subject: [PATCH 5/9] Minor format change --- src/absil/bytes.fs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index 6d3fab122b..0d55823f1d 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -114,7 +114,6 @@ type ByteArrayMemory(bytes: byte[], offset, length) = else if count < 0 then raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) - ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory override _.CopyTo stream = From 997d36baa2778d4ce717b4a666ed08e2ce42c585 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:18:02 -0800 Subject: [PATCH 6/9] Check length before using AsStream --- src/absil/ilreflect.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/absil/ilreflect.fs b/src/absil/ilreflect.fs index 9657cf1794..ab650e0faa 100644 --- a/src/absil/ilreflect.fs +++ b/src/absil/ilreflect.fs @@ -2076,8 +2076,9 @@ let buildModuleFragment cenv emEnv (asmB: AssemblyBuilder) (modB: ModuleBuilder) let attribs = (match r.Access with ILResourceAccess.Public -> ResourceAttributes.Public | ILResourceAccess.Private -> ResourceAttributes.Private) match r.Location with | ILResourceLocation.Local bytes -> - use stream = bytes.AsStream() - modB.DefineManifestResourceAndLog (r.Name, stream, attribs) + if bytes.Length > 0 then + use stream = bytes.AsStream() + modB.DefineManifestResourceAndLog (r.Name, stream, attribs) | ILResourceLocation.File (mr, _) -> asmB.AddResourceFileAndLog (r.Name, mr.Name, attribs) | ILResourceLocation.Assembly _ -> From bc2d57be06df7d2577a161fb9479292181062854 Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:27:17 -0800 Subject: [PATCH 7/9] Remove exception throwing from creating a stream --- src/absil/bytes.fs | 32 ++++++++++++++++---------------- src/absil/ilreflect.fs | 5 ++--- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index 0d55823f1d..4128eae480 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -66,10 +66,6 @@ type ByteMemory () = type ByteArrayMemory(bytes: byte[], offset, length) = inherit ByteMemory() - let checkLengthForStream () = - if length <= 0 then - raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero or less.")) - let checkReadCount count = if count <= 0 then raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) @@ -131,12 +127,16 @@ type ByteArrayMemory(bytes: byte[], offset, length) = Array.empty override _.AsStream() = - checkLengthForStream () - new MemoryStream(bytes, offset, length) :> Stream + if length > 0 then + new MemoryStream(bytes, offset, length) :> Stream + else + new MemoryStream([||], 0, 0, false) :> Stream override _.AsReadOnlyStream() = - checkLengthForStream () - new MemoryStream(bytes, offset, length, false) :> Stream + if length > 0 then + new MemoryStream(bytes, offset, length, false) :> Stream + else + new MemoryStream([||], 0, 0, false) :> Stream [] type SafeUnmanagedMemoryStream = @@ -180,10 +180,6 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = if count <= 0 then raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) - let checkLengthForStream () = - if length <= 0 then - raise (ArgumentOutOfRangeException("length", "Cannot create a stream with a length of zero or less.")) - do if length < 0 then raise (ArgumentOutOfRangeException("length")) @@ -252,12 +248,16 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = Array.empty override _.AsStream() = - checkLengthForStream () - new SafeUnmanagedMemoryStream(addr, int64 length, hold) :> Stream + if length > 0 then + new SafeUnmanagedMemoryStream(addr, int64 length, hold) :> Stream + else + new MemoryStream([||], 0, 0, false) :> Stream override _.AsReadOnlyStream() = - checkLengthForStream () - new SafeUnmanagedMemoryStream(addr, int64 length, int64 length, FileAccess.Read, hold) :> Stream + if length > 0 then + new SafeUnmanagedMemoryStream(addr, int64 length, int64 length, FileAccess.Read, hold) :> Stream + else + new MemoryStream([||], 0, 0, false) :> Stream [] type ReadOnlyByteMemory(bytes: ByteMemory) = diff --git a/src/absil/ilreflect.fs b/src/absil/ilreflect.fs index ab650e0faa..9657cf1794 100644 --- a/src/absil/ilreflect.fs +++ b/src/absil/ilreflect.fs @@ -2076,9 +2076,8 @@ let buildModuleFragment cenv emEnv (asmB: AssemblyBuilder) (modB: ModuleBuilder) let attribs = (match r.Access with ILResourceAccess.Public -> ResourceAttributes.Public | ILResourceAccess.Private -> ResourceAttributes.Private) match r.Location with | ILResourceLocation.Local bytes -> - if bytes.Length > 0 then - use stream = bytes.AsStream() - modB.DefineManifestResourceAndLog (r.Name, stream, attribs) + use stream = bytes.AsStream() + modB.DefineManifestResourceAndLog (r.Name, stream, attribs) | ILResourceLocation.File (mr, _) -> asmB.AddResourceFileAndLog (r.Name, mr.Name, attribs) | ILResourceLocation.Assembly _ -> From f4f3c43f47947f63aa0087e95ee1f79386ed5eed Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:33:48 -0800 Subject: [PATCH 8/9] Added checkCount --- src/absil/bytes.fs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index 4128eae480..7a73335129 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -70,6 +70,10 @@ type ByteArrayMemory(bytes: byte[], offset, length) = if count <= 0 then raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) + let checkCount count = + if count < 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) + do if length < 0 || length > bytes.Length then raise (ArgumentOutOfRangeException("length")) @@ -105,11 +109,10 @@ type ByteArrayMemory(bytes: byte[], offset, length) = System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count) override _.Slice(pos, count) = + checkCount count if count > 0 then ByteArrayMemory(bytes, offset + pos, count) :> ByteMemory else - if count < 0 then - raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory override _.CopyTo stream = @@ -117,6 +120,7 @@ type ByteArrayMemory(bytes: byte[], offset, length) = stream.Write(bytes, offset, length) override _.Copy(srcOffset, dest, destOffset, count) = + checkCount count if count > 0 then Array.blit bytes (offset + srcOffset) dest destOffset count @@ -180,6 +184,10 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = if count <= 0 then raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) + let checkCount count = + if count < 0 then + raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) + do if length < 0 then raise (ArgumentOutOfRangeException("length")) @@ -220,13 +228,12 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = uint16(Marshal.ReadInt16(NativePtr.toNativeInt addr + nativeint pos)) override _.Slice(pos, count) = + checkCount count if count > 0 then check pos check (pos + count - 1) RawByteMemory(NativePtr.add addr pos, count, hold) :> ByteMemory else - if count < 0 then - raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) ByteArrayMemory(Array.empty, 0, 0) :> ByteMemory override x.CopyTo stream = @@ -235,6 +242,7 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = stream2.CopyTo stream override _.Copy(srcOffset, dest, destOffset, count) = + checkCount count if count > 0 then check srcOffset Marshal.Copy(NativePtr.toNativeInt addr + nativeint srcOffset, dest, destOffset, count) From ac5ac7c62291ea617a98a9a41565847d97809e7d Mon Sep 17 00:00:00 2001 From: Will Smith Date: Sun, 19 Jan 2020 05:43:50 -0800 Subject: [PATCH 9/9] Remove checkReadCount --- src/absil/bytes.fs | 48 +++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/src/absil/bytes.fs b/src/absil/bytes.fs index 7a73335129..e1be17ef1d 100644 --- a/src/absil/bytes.fs +++ b/src/absil/bytes.fs @@ -66,10 +66,6 @@ type ByteMemory () = type ByteArrayMemory(bytes: byte[], offset, length) = inherit ByteMemory() - let checkReadCount count = - if count <= 0 then - raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) - let checkCount count = if count < 0 then raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) @@ -88,8 +84,11 @@ type ByteArrayMemory(bytes: byte[], offset, length) = override _.Length = length override _.ReadBytes(pos, count) = - checkReadCount count - Array.sub bytes (offset + pos) count + checkCount count + if count > 0 then + Array.sub bytes (offset + pos) count + else + Array.empty override _.ReadInt32 pos = let finalOffset = offset + pos @@ -105,8 +104,11 @@ type ByteArrayMemory(bytes: byte[], offset, length) = ((uint16 bytes.[finalOffset + 1]) <<< 8) override _.ReadUtf8String(pos, count) = - checkReadCount count - System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count) + checkCount count + if count > 0 then + System.Text.Encoding.UTF8.GetString(bytes, offset + pos, count) + else + String.Empty override _.Slice(pos, count) = checkCount count @@ -180,10 +182,6 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = if i < 0 || i >= length then raise (ArgumentOutOfRangeException("i")) - let checkReadCount count = - if count <= 0 then - raise (ArgumentOutOfRangeException("count", "Count is less than or equal to zero.")) - let checkCount count = if count < 0 then raise (ArgumentOutOfRangeException("count", "Count is less than zero.")) @@ -204,18 +202,24 @@ type RawByteMemory(addr: nativeptr, length: int, hold: obj) = override _.Length = length override _.ReadUtf8String(pos, count) = - checkReadCount count - check pos - check (pos + count - 1) - System.Text.Encoding.UTF8.GetString(NativePtr.add addr pos, count) + checkCount count + if count > 0 then + check pos + check (pos + count - 1) + System.Text.Encoding.UTF8.GetString(NativePtr.add addr pos, count) + else + String.Empty override _.ReadBytes(pos, count) = - checkReadCount count - check pos - check (pos + count - 1) - let res = Bytes.zeroCreate count - Marshal.Copy(NativePtr.toNativeInt addr + nativeint pos, res, 0, count) - res + checkCount count + if count > 0 then + check pos + check (pos + count - 1) + let res = Bytes.zeroCreate count + Marshal.Copy(NativePtr.toNativeInt addr + nativeint pos, res, 0, count) + res + else + Array.empty override _.ReadInt32 pos = check pos