Skip to content

Filter fatal exceptions from Task.FromException in async paths#4437

Open
cheenamalhotra wants to merge 1 commit into
mainfrom
dev/cheena/dev-automation-fix-fatal-exception-wrapp
Open

Filter fatal exceptions from Task.FromException in async paths#4437
cheenamalhotra wants to merge 1 commit into
mainfrom
dev/cheena/dev-automation-fix-fatal-exception-wrapp

Conversation

@cheenamalhotra

@cheenamalhotra cheenamalhotra commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

Multiple sites in SqlBulkCopy, SqlDataReader.InvokeAsyncCall, SqlCommand.Reader, and SqlCommand.Xml catch Exception broadly and wrap it in Task.FromException<T>() or TrySetException() without filtering fatal exceptions. This means OutOfMemoryException, StackOverflowException, ThreadAbortException, etc. get silently captured into faulted Tasks instead of propagating synchronously.

Changes

File Fix
SqlBulkCopy.cs Added when (ADP.IsCatchableExceptionType(ex)) filter to 8 catch blocks that wrap exceptions into Task.FromException or TrySetException
SqlDataReader.cs (InvokeAsyncCall) Added when (ADP.IsCatchableExceptionType(ex)) exception filter
SqlCommand.Reader.cs Added when (ADP.IsCatchableExceptionType(e)) exception filter
SqlCommand.Xml.cs Added when (ADP.IsCatchableExceptionType(e)) exception filter

Precedent

This matches the existing pattern already used in SqlDataReader at multiple other sites (e.g., ReadNextAsync, IsDBNullAsync, GetFieldValueAsync):

catch (Exception ex) when (ADP.IsCatchableExceptionType(ex))
{
    return Task.FromException<bool>(ex);
}

What was NOT changed

Sites in task continuations / callbacks (TdsParserStateObject SNI callbacks, AsyncHelper continuations, SqlCommand retry continuations) were intentionally left unchanged. In those contexts, rethrowing would crash the unobserved-task handler or the thread-pool thread; the TrySetException call is the correct behavior since the exception originated asynchronously.

Similarly, sites in SqlSequentialTextReader and SqlSequentialStream that call TrySetException and then rethrow were left unchanged — the fatal exception already propagates.

Testing

  • Build verified on net8.0 (0 warnings, 0 errors)
  • No new tests needed — this is a defensive guard that only affects behavior under fatal runtime conditions

Copilot AI review requested due to automatic review settings July 10, 2026 03:02
@cheenamalhotra cheenamalhotra requested a review from a team as a code owner July 10, 2026 03:02
@github-project-automation github-project-automation Bot moved this to To triage in SqlClient Board Jul 10, 2026
@cheenamalhotra cheenamalhotra added this to the 7.1.0-preview3 milestone Jul 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens async error-handling paths in Microsoft.Data.SqlClient by ensuring “fatal” exceptions (e.g., OutOfMemoryException, ThreadAbortException, etc.) are not silently converted into faulted Tasks via Task.FromException, aligning behavior with existing ADP.IsCatchableExceptionType patterns in the codebase.

Changes:

  • Add an exception filter to SqlDataReader.InvokeAsyncCall to avoid wrapping non-catchable exceptions via Task.FromException<T>.
  • Add an ADP.IsCatchableExceptionType guard in SqlBulkCopy before returning Task.FromException<bool>(ex) for async bulk copy.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlDataReader.cs Adds an exception filter around Task.FromException<T>(ex) in InvokeAsyncCall.
src/Microsoft.Data.SqlClient/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs Adds a catchability guard before returning Task.FromException<bool>(ex) in the async bulk copy path.

Fatal exceptions (OOM, StackOverflow, ThreadAbort, NullReference,
AccessViolation) must not be wrapped in Task.FromException or
TrySetException — they should propagate synchronously. Add
ADP.IsCatchableExceptionType guards matching the existing pattern
used elsewhere in SqlDataReader.

Sites fixed:
- SqlBulkCopy.cs: 8 catch blocks guarded with exception filter
- SqlDataReader.cs (InvokeAsyncCall): exception filter added
- SqlCommand.Reader.cs: exception filter added
- SqlCommand.Xml.cs: exception filter added

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 10, 2026 03:10
@cheenamalhotra cheenamalhotra force-pushed the dev/cheena/dev-automation-fix-fatal-exception-wrapp branch from 1b34de8 to 33de935 Compare July 10, 2026 03:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 64.28571% with 5 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.06%. Comparing base (fdebcd2) to head (33de935).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...Client/src/Microsoft/Data/SqlClient/SqlBulkCopy.cs 72.72% 3 Missing ⚠️
.../src/Microsoft/Data/SqlClient/SqlCommand.Reader.cs 0.00% 1 Missing ⚠️
...ent/src/Microsoft/Data/SqlClient/SqlCommand.Xml.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4437      +/-   ##
==========================================
- Coverage   65.83%   64.06%   -1.78%     
==========================================
  Files         287      282       -5     
  Lines       43763    66661   +22898     
==========================================
+ Hits        28812    42704   +13892     
- Misses      14951    23957    +9006     
Flag Coverage Δ
CI-SqlClient ?
PR-SqlClient-Project 64.06% <64.28%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@cheenamalhotra cheenamalhotra moved this from To triage to In review in SqlClient Board Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

4 participants