Skip to content

SqlDataRecord.SetBytes fails to set length, incorrectly preserving data from a previous call #3957

@wjrogers

Description

@wjrogers

Describe the bug

Suppose you are using IEnumerable<SqlDataRecord> as the value of a table-valued SqlParameter and re-using the same SqlDataRecord instance for each item. One of the fields is type VARBINARY(MAX), and you use the SetBytes method to copy data into the field. After the first call to SetBytes, a subsequent call that copies fewer bytes will write to the existing buffer without setting the field's length, causing the remaining stale buffered bytes from the first call to get copied to the server, too.

To reproduce

#!/usr/bin/env dotnet run
#:package Microsoft.Data.SqlClient@6.*

using Microsoft.Data.SqlClient.Server;
using System.Data;
using System.Data.SqlTypes;
using System.Text;

var columns = new SqlMetaData[]
{
    new("Data", SqlDbType.VarBinary, SqlMetaData.Max),
};

var rec = new SqlDataRecord(columns);
var buffer = new byte[4096];

// write first record value
SetBytes(rec, 0, buffer, "Two Words");
ReadBytesToConsole(rec, 0, buffer); // writes "Two Words"

// write second record value
SetBytes(rec, 0, buffer, "One");
ReadBytesToConsole(rec, 0, buffer); // writes "One Words"

// write third record value using SqlBytes, which avoids the bug
var sqlBytes = new SqlBytes(Encoding.UTF8.GetBytes("Three"));
rec.SetSqlBytes(0, sqlBytes);
ReadBytesToConsole(rec, 0, buffer); // writes "Three"

static void SetBytes(SqlDataRecord rec, int ordinal, byte[] buffer, string value)
{
    int length = Encoding.UTF8.GetBytes(value, buffer);
    rec.SetBytes(ordinal, 0, buffer, 0, length);
}

static void ReadBytesToConsole(SqlDataRecord rec, int ordinal, byte[] buffer)
{
    var length = rec.GetBytes(ordinal, 0, buffer, 0, buffer.Length);
    var s = Encoding.UTF8.GetString(buffer, 0, int.CreateChecked(length));
    Console.WriteLine(s);
}

Expected behavior

The program should output:

Two Words
One
Three

Further technical details

Microsoft.Data.SqlClient version: 6.1.4
.NET target: .NET 10.0
SQL Server version: N/A
Operating system: Windows 11 Pro 26200.7840

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions