fix null ref in SqlDataReader#4159
Conversation
The bug: At SqlDataReader.cs:2140, when buffer is null and bufferIndex < 0, the condition (bufferIndex < 0) is true, so execution enters the block. But buffer.Length in the exception constructor throws NullReferenceException since buffer is null. This only affects the PLP + SequentialAccess path in GetChars. The other GetChars/GetBytes paths at lines 1760 and 1891 don't have the buffer != null && guard, so they'd NRE on the condition itself (different issue, but buffer is expected non-null there). The fix (SqlDataReader.cs:2140): Changed buffer.Length to buffer?.Length ?? 0 so it reports size 0 when buffer is null. The test (DataReaderTest.cs): Added GetCharsSequentialAccess_NullBufferNegativeBufferIndex_ThrowsArgumentOutOfRange which calls reader.GetChars(0, 0, null, -1, 0) with CommandBehavior.SequentialAccess on an NVARCHAR(MAX) column and asserts it throws ArgumentOutOfRangeException with paramName: "bufferIndex" — without the fix this throws NullReferenceException instead.
|
/azp run |
|
Azure Pipelines successfully started running 2 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Fixes a NullReferenceException in SqlDataReader.GetChars when called in the PLP + CommandBehavior.SequentialAccess path with buffer == null and a negative bufferIndex, ensuring the intended ArgumentOutOfRangeException is thrown instead.
Changes:
- Update
SqlDataReader.GetChars(PLP + SequentialAccess) to avoid dereferencingbuffer.Lengthwhenbufferis null while constructing the argument exception. - Add a regression test covering
GetCharswith SequentialAccess + PLP,buffer == null, and negativebufferIndex. - Add additional tests for non-sequential
GetCharsandGetBytesnull-buffer + negativebufferIndexbehavior (currently inconsistent with implementation).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDataReader.cs |
Prevents NRE when building the invalid bufferIndex exception in the PLP + SequentialAccess GetChars path; also adds some redundant null-guards in exception-path validation. |
src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/DataReaderTest/DataReaderTest.cs |
Adds a regression test for the sequential PLP scenario and two additional tests that currently don’t match product behavior when buffer == null. |
paulmedynski
left a comment
There was a problem hiding this comment.
Please address the Copilot comments.
…DataReader.GetChars
|
/azp run |
|
Azure Pipelines successfully started running 2 pipeline(s). |
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## main #4159 +/- ##
===========================================
- Coverage 74.27% 64.20% -10.07%
===========================================
Files 279 272 -7
Lines 42980 65763 +22783
===========================================
+ Hits 31922 42222 +10300
- Misses 11058 23541 +12483
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
The bug: At SqlDataReader.cs:2140, when buffer is null and bufferIndex < 0, the condition (bufferIndex < 0) is true, so execution enters the block. But buffer.Length in the exception constructor throws NullReferenceException since buffer is null.
This only affects the PLP + SequentialAccess path in GetChars. The other GetChars/GetBytes paths at lines 1760 and 1891 don't have the buffer != null && guard, so they'd NRE on the condition itself (different issue, but buffer is expected non-null there).
The fix (SqlDataReader.cs:2140): Changed buffer.Length to buffer?.Length ?? 0 so it reports size 0 when buffer is null.
The test (DataReaderTest.cs): Added GetCharsSequentialAccess_NullBufferNegativeBufferIndex_ThrowsArgumentOutOfRange which calls reader.GetChars(0, 0, null, -1, 0) with CommandBehavior.SequentialAccess on an NVARCHAR(MAX) column and asserts it throws ArgumentOutOfRangeException with paramName: "bufferIndex" — without the fix this throws NullReferenceException instead.