Convert.ToBase64CharArray throws IndexOutOfRangeException when encoding a zero-length slice of a non-empty source array into the zero-length slice at the end of a destination array #92016
While writing a wrapper for Convert.ToBase64String to support Base64Url-encoding (slightly different character set, no padding), I encountered this bug:
var bytes = new byte[1];
var chars = new char[0];
Convert.ToBase64CharArray(bytes, 0, 0, chars, 0, Base64FormattingOptions.None).Dump(); // throws IndexOutOfRangeException
(The bug also exists in FX -- in fact, I encountered it there first.)
The issue is that the referenced line is trying to check for a zero-length conversion, but instead of checking length (the number of input bytes to be converted) it checks inArrayLength (the length of the array that the input bytes come from). As a result, if the source array itself has nonzero length, the check fails and the remainder of the method continues executing.
tries to take the address of outArray[offsetOut]. If offsetOut == outArray.Length (destination is the zero-length slice at the end of outArray -- which can most easily occur if outArray is the empty array and offsetOut is zero), then outArray[offsetOut] does not exist, and trying to take its address causes IndexOutOfRangeException to be thrown.
Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.
Issue Details
While writing a wrapper for Convert.ToBase64String to support Base64Url-encoding (slightly different character set, no padding), I encountered this bug:
```cs
var bytes = new byte[1];
var chars = new char[0];
Convert.ToBase64CharArray(bytes, 0, 0, chars, 0, Base64FormattingOptions.None).Dump(); // throws IndexOutOfRangeException
```
(The bug also exists in FX -- in fact, I encountered it there first.)
https://github.com/dotnet/runtime/blob/3eddabc26510e0df4bad31aa465177ca7cbbb391/src/libraries/System.Private.CoreLib/src/System/Convert.cs#L2400
The issue is that the referenced line is trying to check for a zero-length conversion, but instead of checking `length` (the number of input bytes to be converted) it checks `inArrayLength` (the length of the array that the input bytes come from). As a result, if the source array itself has nonzero length, the check fails and the remainder of the method continues executing.
In such instances, this line of code:
https://github.com/dotnet/runtime/blob/3eddabc26510e0df4bad31aa465177ca7cbbb391/src/libraries/System.Private.CoreLib/src/System/Convert.cs#L2418
tries to take the address of `outArray[offsetOut]`. If `offsetOut == outArray.Length` (destination is the zero-length slice at the end of `outArray` -- which can most easily occur if `outArray` is the empty array and `offsetOut` is zero), then `outArray[offsetOut]` does not exist, and trying to take its address causes `IndexOutOfRangeException` to be thrown.
While writing a wrapper for Convert.ToBase64String to support Base64Url-encoding (slightly different character set, no padding), I encountered this bug:
(The bug also exists in FX -- in fact, I encountered it there first.)
https://github.com/dotnet/runtime/blob/3eddabc26510e0df4bad31aa465177ca7cbbb391/src/libraries/System.Private.CoreLib/src/System/Convert.cs#L2400
The issue is that the referenced line is trying to check for a zero-length conversion, but instead of checking
length
(the number of input bytes to be converted) it checksinArrayLength
(the length of the array that the input bytes come from). As a result, if the source array itself has nonzero length, the check fails and the remainder of the method continues executing.In such instances, this line of code:
https://github.com/dotnet/runtime/blob/3eddabc26510e0df4bad31aa465177ca7cbbb391/src/libraries/System.Private.CoreLib/src/System/Convert.cs#L2418
tries to take the address of
outArray[offsetOut]
. IfoffsetOut == outArray.Length
(destination is the zero-length slice at the end ofoutArray
-- which can most easily occur ifoutArray
is the empty array andoffsetOut
is zero), thenoutArray[offsetOut]
does not exist, and trying to take its address causesIndexOutOfRangeException
to be thrown.