-
Notifications
You must be signed in to change notification settings - Fork 23
Description
In the rare occasions that we do enter the first if block, Array.Resize creates a new array internally which 'arr' is then referencing. After the resize call, 'arr' and 'segment.Array' are NOT the same array. The exception is then thrown when creating "a new segment so count is right" because the array being passed in has not been resized, so 'Count + 1' leads to the "Argument_InvalidOffLen" ArgumentException.
Pasting the code for easy reference:
protected EResult Send(HSteamNetConnection steamConnection, ArraySegment<byte> segment, byte channelId)
{
/* Have to resize array to include channel index
* if array isn't large enough to fit it. This is because
* we don't know what channel data comes in on so
* the channel has to be packed into the data sent.
* Odds of the array having to resize are extremely low
* so while this is not ideal, it's still very low risk. */
if ((segment.Array.Length - 1) <= (segment.Offset + segment.Count))
{
byte[] arr = segment.Array;
Array.Resize(ref arr, arr.Length + 1);
arr[arr.Length - 1] = channelId;
}
//If large enough just increase the segment and set the channel byte.
else
{
segment.Array[segment.Offset + segment.Count] = channelId;
}
//Make a new segment so count is right.
segment = new ArraySegment<byte>(segment.Array, segment.Offset, segment.Count + 1);
//...
}We fixed it locally by creating a new segment with the resized array and moving the final segment creation inside the else block since we already set the correct size otherwise:
if ((segment.Array.Length - 1) <= (segment.Offset + segment.Count))
{
byte[] arr = segment.Array;
Array.Resize(ref arr, arr.Length + 1);
arr[arr.Length - 1] = channelId;
// create a new segment with the resized array
segment = new ArraySegment<byte>(arr, segment.Offset, segment.Count + 1);
}
//If large enough just increase the segment and set the channel byte.
else
{
segment.Array[segment.Offset + segment.Count] = channelId;
//Make a new segment so count is right.
segment = new ArraySegment<byte>(segment.Array, segment.Offset, segment.Count + 1);
}It's very easy to reproduce the issue by enabling the latency simulator, as the segments being passed in all have the same length as their array and execution will always go through the if block.