Skip to content

Calling JoinableTask.Task may throw InternalErrorException when obtained from a JoinableTaskCollection #410

@AArnott

Description

@AArnott

Bug description

The JoinableTask.Task property throws if wrappedTask == null, which it will be until its initialDelegate returns a Task to assign to that field. It might seem this is OK since JTF.RunAsync hasn't returned the object to the caller to observe and call the property on, but this is incorrect. The JoinableTask is observable even before the caller sees it from another thread that enumerates the contents of a JoinableTaskCollection that the original JoinableTaskFactory.RunAsync added the object to.

Repro steps

Here is a test that demonstrates the bug:

[Fact]
public async Task JoinableTask_TaskPropertyBeforeReturning()
{
    var unblockJoinableTask = new ManualResetEventSlim();
    var joinableTaskStarted = new AsyncManualResetEvent(allowInliningAwaiters: false);
    Task<int> observedWrappedTask = null;
    var assertingTask = Task.Run(async delegate
    {
        try
        {
            await joinableTaskStarted.WaitAsync();
            var observableJoinableTask = (JoinableTask<int>)this.joinableCollection.Single();
            observedWrappedTask = observableJoinableTask.Task;
        }
        finally
        {
            unblockJoinableTask.Set();
        }
    });
    var joinableTask = this.asyncPump.RunAsync(delegate
    {
        joinableTaskStarted.Set();

        // Synchronously block *BEFORE* yielding.
        unblockJoinableTask.Wait();
        return Task.FromResult(3);
    });

    await assertingTask; // observe failures.
    await joinableTask;
    Assert.Same(observedWrappedTask, joinableTask.Task);
    Assert.Equal(3, await observedWrappedTask);
}

Expected behavior

A Task is synthesized and returned from JoinableTask.Task.

Actual behavior

JoinableTask.Task throws:

Microsoft.Assumes+InternalErrorException : An internal error occurred. Please contact Microsoft Product Support Services.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions