Skip to content

Commit 6b7b3f8

Browse files
committed
Fix garbage data in GetColumnSchema. Fixes #354
1 parent a89b15f commit 6b7b3f8

File tree

2 files changed

+20
-6
lines changed

2 files changed

+20
-6
lines changed

src/MySqlConnector/MySqlClient/Results/ResultSet.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public async Task<ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior)
2424
LastInsertId = 0;
2525
RecordsAffected = 0;
2626
State = ResultSetState.None;
27+
m_columnDefinitionPayloadUsedBytes = 0;
2728
m_dataLengths = null;
2829
m_dataOffsets = null;
2930
m_readBuffer.Clear();
@@ -83,14 +84,25 @@ public async Task<ResultSet> ReadResultSetHeaderAsync(IOBehavior ioBehavior)
8384
if (reader.BytesRemaining != 0)
8485
throw new MySqlException("Unexpected data at end of column_count packet; see https://github.com/mysql-net/MySqlConnector/issues/324");
8586

87+
// reserve adequate space to hold a copy of all column definitions (but note that this can be resized below if we guess too small)
88+
Array.Resize(ref m_columnDefinitionPayloads, columnCount * 96);
89+
8690
ColumnDefinitions = new ColumnDefinitionPayload[columnCount];
8791
m_dataOffsets = new int[columnCount];
8892
m_dataLengths = new int[columnCount];
8993

9094
for (var column = 0; column < ColumnDefinitions.Length; column++)
9195
{
9296
payload = await Session.ReceiveReplyAsync(ioBehavior, CancellationToken.None).ConfigureAwait(false);
93-
ColumnDefinitions[column] = ColumnDefinitionPayload.Create(payload);
97+
var arraySegment = payload.ArraySegment;
98+
99+
// 'Session.ReceiveReplyAsync' reuses a shared buffer; make a copy so that the column definitions can always be safely read at any future point
100+
if (m_columnDefinitionPayloadUsedBytes + arraySegment.Count > m_columnDefinitionPayloads.Length)
101+
Array.Resize(ref m_columnDefinitionPayloads, Math.Max(m_columnDefinitionPayloadUsedBytes + arraySegment.Count, m_columnDefinitionPayloadUsedBytes * 2));
102+
Buffer.BlockCopy(arraySegment.Array, arraySegment.Offset, m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes, arraySegment.Count);
103+
104+
ColumnDefinitions[column] = ColumnDefinitionPayload.Create(new ArraySegment<byte>(m_columnDefinitionPayloads, m_columnDefinitionPayloadUsedBytes, arraySegment.Count));
105+
m_columnDefinitionPayloadUsedBytes += arraySegment.Count;
94106
}
95107

96108
if (!Session.SupportsDeprecateEof)
@@ -421,6 +433,8 @@ public Row GetCurrentRow()
421433
public int RecordsAffected { get; private set; }
422434
public ResultSetState State { get; private set; }
423435

436+
byte[] m_columnDefinitionPayloads;
437+
int m_columnDefinitionPayloadUsedBytes;
424438
int[] m_dataLengths;
425439
int[] m_dataOffsets;
426440
readonly Queue<Row> m_readBuffer = new Queue<Row>();

src/MySqlConnector/Serialization/ColumnDefinitionPayload.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,9 @@ public string PhysicalName
7575

7676
public byte Decimals { get; private set; }
7777

78-
public static ColumnDefinitionPayload Create(PayloadData payload)
78+
public static ColumnDefinitionPayload Create(ArraySegment<byte> arraySegment)
7979
{
80-
var reader = new ByteArrayReader(payload.ArraySegment);
80+
var reader = new ByteArrayReader(arraySegment);
8181
SkipLengthEncodedByteString(ref reader); // catalog
8282
SkipLengthEncodedByteString(ref reader); // schema
8383
SkipLengthEncodedByteString(ref reader); // table
@@ -105,7 +105,7 @@ public static ColumnDefinitionPayload Create(PayloadData payload)
105105

106106
return new ColumnDefinitionPayload
107107
{
108-
OriginalPayload = payload,
108+
OriginalData = arraySegment,
109109
CharacterSet = characterSet,
110110
ColumnLength = columnLength,
111111
ColumnType = columnType,
@@ -122,7 +122,7 @@ private static void SkipLengthEncodedByteString(ref ByteArrayReader reader)
122122

123123
private void ReadNames()
124124
{
125-
var reader = new ByteArrayReader(OriginalPayload.ArraySegment);
125+
var reader = new ByteArrayReader(OriginalData);
126126
m_catalogName = Encoding.UTF8.GetString(reader.ReadLengthEncodedByteString());
127127
m_schemaName = Encoding.UTF8.GetString(reader.ReadLengthEncodedByteString());
128128
m_table = Encoding.UTF8.GetString(reader.ReadLengthEncodedByteString());
@@ -132,7 +132,7 @@ private void ReadNames()
132132
m_readNames = true;
133133
}
134134

135-
PayloadData OriginalPayload { get; set; }
135+
ArraySegment<byte> OriginalData { get; set; }
136136

137137
bool m_readNames;
138138
string m_name;

0 commit comments

Comments
 (0)