dotnet: SqlDataReader.ReadAsync and NextResultAsync cause unobserved task exception even when awaited

It’s now been fourteen months, two new versions of .NET (4.6.2, 4.7) and many monthly rollups later. Please update us with an ETA for this fix.

I reached out on Twitter and GitHub on multiple occasions to try and get some break in the silence. It took 4.5 months for you to respond the first time. (What was worse, no notification email was sent- I typically get them, and I checked spam- so I had no way to know you had responded till I checked a couple weeks later.) Now it’s been another 7.5 months of silence since another person and I asked when the fix is rolling out. This is a fairly critical bug which has been afflicting our development and production code with real customers.

It won’t take much to restore good faith. Please understand that silence is not amusing.

@terrajobst instructed me to move this from https://connect.microsoft.com/VisualStudio/feedback/details/2592987 to GitHub so that he can point the correct people to it. Thanks Immo!


Posted by @jnm2 on 4/15/2016

Edit: because the attachments I’m uploading are not showing up, here is Program.cs: https://gist.github.com/jnm2/a5ab5c49e3ec4525367229f0e94e6b31

Edit 2: Because people were confused about the finalizer thread, here’s a WinForms app: https://github.com/jnm2/misc-codesamples/blob/master/Bug reports/.NET/SqlDataReader.NextResultAsync bug.zip?raw=true

Edit 3: The same defect plagues ReadAsync! https://github.com/jnm2/misc-codesamples/blob/master/Bug reports/.NET/SqlDataReader.ReadAsync bug.zip?raw=true

There are two stages to this bug.

In stage 1, SqlDataReader.NextResultAsync does not handle a SqlException properly. It leaves a second internal Task with no references, available to garbage collection, whose exception has not been observed even though NextResultAsync is being awaited properly. Failure is imminent.

In stage 2, the application causes a GC. In practice this is via loading new windows and data, but to be more deterministic about it the sample uses GC.Collect() or while (true) await Task.Yield(); All three of these are equivalent; the sole purpose is to cause a GC. When the GC happens, it detects and collects the second internal Task object that NextResultAsync created and runs the finalizer which throws the task’s exception via TaskSchedule.UnobservedTaskException.

I hypothesize, looking at the reference source, that the async retry code makes a mistake as it juggles Task objects. But you would know best.

=============================================

SqlDataReader.NextResultAsync is causing unobserved task exceptions when it is properly awaited:

using (var command = new SqlCommand("select null; select * from dbo.NonexistentTable;", connection))
{
    try
    {
        using (var reader = await command.ExecuteReaderAsync()) // ExecuteReaderAsync does not exhibit the bug, so we have the first result set cause no problems
            while (await reader.NextResultAsync()) { } // NextResultAsync will fail and exhibit the bug
    }
    catch (SqlException ex)
    {
        // ex is definitely observed by the await and caught, but it will show up in TaskScheduler.UnobservedTaskException as though we hadn't handled it
    }
}

Complete repro attached.

The impact is that instead of expected errors being handled and quietly logged, they trigger our application’s unexpected error recovery mode. It’s a valid assumption that if there is a real unobserved exception, the error should be reported and the software should be shut down.

With SqlDataReader.NextResultAsync acting this way, our application can’t tell the difference between expected SqlExceptions and critical SqlExceptions. (That is, handled exceptions and unhandled exceptions.)

I’m running Windows 10 x64 and .NET 4.6.1.


Posted by Microsoft on 4/15/2016

Thank you for your feedback, we are currently reviewing the issue you have submitted. If you require immediate assistance with this issue, please contact product support at http://support.microsoft.com/oas/default.aspx?prid=15694.


Posted by @jnm2 on 4/19/2016

Guys, I’ve uploaded Program.cs with no errors multiple times but it’s not showing up under attachments. Why not?


Posted by @jnm2 on 4/19/2016

I added github links for the samples. The multiple trial attachments should be deleted.

Also added more information to clarify what’s happening. Hopefully this makes it easier to focus on the core facts.


Posted by @jnm2 on 8/9/2016

I discovered the same fault in ReadAsync. Updated. Also, it’s been a few months. 4.6.2 has come and gone. Please get back to me about this.


Posted by @corivera on 8/24/2016

The fix should be available with the next batch of .NET fixes in October.


Posted by @jnm2 on 9/7/2016

That is good news! Thank you! It would have helped us immensely to receive some type of acknowledgment sooner than 4 months so that we’d know how to plan around this, but better late than never.

Does the fix include ReadAsync as well? I assume so, but I need to double check.


Posted by @corivera on 9/9/2016

Yes, the fix also affects ReadAsync. The bug was in an underlying method called by both functions.


Posted by @jnm2 on 9/9/2016

What do we look for to know when the fix is available to our customers? A Windows Update KB#?


Posted by @corivera on 9/12/2016

Yes, this will be released as a Windows .NET hotfix.


Posted by @corivera on 9/12/2016

Correction, this will be released as part of a general Windows .NET update, not a specific hotfix for this one issue.


Posted by @corivera on 9/28/2016

Update: The fix for this issue will not be included in the .NET October update. Instead, the fix will be included in the next version update of .NET framework.


Posted by Frode G on 10/30/2016

When will the next version update of .NET framework be? This bug affects our application as well. We are catching unobserved exceptions now and sets as observed. Hope that prevents IIS recycles. Looking forward for a fix.


Posted by @jnm2 on 12/14/2016

It’s now been eight months, one new version of .NET and three monthly rollups later. Please update us with an ETA for this fix.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 36 (36 by maintainers)

Most upvoted comments

The rollup will be pushed broadly with the next .NET Security and Quality payload, which will likely be released in September.

@jnm2 The fix for this issue is part of that July preview rollup, although it isn’t listed as part of the Data fixes.

Can you give us a sense of when this fix will land? I see other ADO stuff in https://blogs.msdn.microsoft.com/dotnet/2017/07/24/net-framework-july-2017-preview-of-quality-rollup/.

Small update, we’ll only be porting this fix to 4.6.x versions, since we haven’t had any requests for a fix in 4.5.2.