diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index bc7cd362a8..a73e24a098 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -4,8 +4,10 @@ using System; using System.Diagnostics; +using System.Linq; using System.Runtime.InteropServices; using System.Security; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.Common; @@ -359,7 +361,7 @@ public bool TryReadByteArray(Span buff, int len) public bool TryReadByteArray(Span buff, int len, out int totalRead) { totalRead = 0; - + int inBytesPacketStart = _inBytesPacket; #if DEBUG if (_snapshot != null && _snapshot.DoPend()) { @@ -396,9 +398,27 @@ public bool TryReadByteArray(Span buff, int len, out int totalRead) Debug.Assert(bytesToRead > 0, "0 byte read in TryReadByteArray"); if (!buff.IsEmpty) { - ReadOnlySpan copyFrom = new ReadOnlySpan(_inBuff, _inBytesUsed, bytesToRead); - Span copyTo = buff.Slice(totalRead, bytesToRead); - copyFrom.CopyTo(copyTo); + ReadOnlySpan copyFrom = ReadOnlySpan.Empty; + try + { + copyFrom = new ReadOnlySpan(_inBuff, _inBytesUsed, bytesToRead); + Span copyTo = buff.Slice(totalRead, bytesToRead); + copyFrom.CopyTo(copyTo); + } + catch (Exception ex) + { + string debugmsg = "\n" + + $"inBytesPacketStart = {inBytesPacketStart}\n" + + $"bytesToRead = Math.Min({len}, Math.Min({_inBytesPacket}, {_inBytesRead} - {_inBytesUsed}));\n" + + $"_inBuff.Length = {_inBuff.Length}\n" + + $"buff.Length = {buff.Length}\n" + + $"copyFrom = new ReadOnlySpan({_inBuff.Length}, {_inBytesUsed}, {bytesToRead})\n" + + $"copyTo = buff.Slice({totalRead}, {bytesToRead});\n" + + $"lengths= {inBytesPacketStart}\n"+ + ex.Message; + Console.WriteLine(debugmsg); + throw new Exception(debugmsg); + } } totalRead += bytesToRead; @@ -465,6 +485,11 @@ internal bool TryReadChar(out char value) Span buffer = stackalloc byte[2]; if (((_inBytesUsed + 2) > _inBytesRead) || (_inBytesPacket < 2)) { + if (_inBytesPacket < 0) + { + throw new Exception($"TryReadChar(0) _inBytesPacket {_inBytesPacket}\n" + + $" if ((({_inBytesUsed} + 2) > {_inBytesRead}) || ({_inBytesPacket} < 2))"); + } // If the char isn't fully in the buffer, or if it isn't fully in the packet, // then use ReadByteArray since the logic is there to take care of that. if (!TryReadByteArray(buffer, 2)) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index d8171c63b6..5f8ed19ca0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -10,6 +10,7 @@ using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security; +using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.Data.Common; @@ -449,7 +450,6 @@ public bool TryReadByteArray(Span buff, int len, out int totalRead) { TdsParser.ReliabilitySection.Assert("unreliable call to ReadByteArray"); // you need to setup for a thread abort somewhere before you call this method totalRead = 0; - #if DEBUG if (_snapshot != null && _snapshot.DoPend()) { diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs index e32b84d672..993bf36806 100644 --- a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/TdsParserStateObject.cs @@ -439,14 +439,16 @@ internal bool TryStartNewRow(bool isNullCompressed, int nullBitmapColumnsCount = internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out int charsCopied) { charsCopied = 0; + int count = 0; while (charsCopied < charsCount) { // check if the current buffer contains some bytes we need to copy and copy them // in a block int bytesToRead = Math.Min( (charsCount - charsCopied) * 2, - unchecked((_inBytesRead - _inBytesUsed) & (int)0xFFFFFFFE) // it the result is odd take off the 0 to make it even + unchecked((_inBytesRead - _inBytesUsed) & (int)0xFFFFFFFE) // if the result is odd take off the 0 to make it even ); + if (bytesToRead > 0) { Buffer.BlockCopy( @@ -456,6 +458,13 @@ internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out in (charsOffset + charsCopied) * 2, // offset in bytes, bytesToRead ); + + if ((_inBytesPacket - bytesToRead) < 0) + { + throw new Exception($"TryReadChars() {count} _inBytesPacket {_inBytesPacket}\n" + + $" bytesToRead = Math.Min(({charsCount} - {charsCopied}) * 2, unchecked(({_inBytesRead} - {_inBytesUsed}) & (int)0xFFFFFFFE)"); + } + charsCopied = bytesToRead / 2; _inBytesUsed += bytesToRead; _inBytesPacket -= bytesToRead; @@ -477,6 +486,7 @@ internal bool TryReadChars(char[] chars, int charsOffset, int charsCount, out in return false; } } + count += 1; } return true; }