From: Stephen Toub Date: Wed, 22 Mar 2017 06:09:22 +0000 (-0400) Subject: Fix leak in Task.WaitAny(..., int) (dotnet/coreclr#10331) X-Git-Tag: submit/tizen/20210909.063632~11030^2~7618 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=195450160a9bc744d4c91f4f8c02b0523048018a;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Fix leak in Task.WaitAny(..., int) (dotnet/coreclr#10331) WaitAny is effectively built on top of WhenAny, creating a continuation from the supplied tasks and then blocking on that continuation. When a timeout is provided, it blocks with that timeout. But if it doesn't complete within the timeout, it ends up leaking the continuations it created into the constituent tasks. The fix is simply to force the returned continuation to complete, such that its continuation logic does all of the appropriate cleanup. Commit migrated from https://github.com/dotnet/coreclr/commit/d6e9a08a70dab11ddc845fb0ccf36aa436e9ebec --- diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs index b9f58c0..8e2e6a4 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/Task.cs @@ -5029,6 +5029,10 @@ namespace System.Threading.Tasks signaledTaskIndex = Array.IndexOf(tasks, firstCompleted.Result); Debug.Assert(signaledTaskIndex >= 0); } + else + { + TaskFactory.CommonCWAnyLogicCleanup(firstCompleted); + } } // We need to prevent the tasks array from being GC'ed until we come out of the wait. diff --git a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs index 9f6f505..e193d0e 100644 --- a/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs +++ b/src/coreclr/src/mscorlib/src/System/Threading/Tasks/TaskFactory.cs @@ -2372,7 +2372,8 @@ namespace System.Threading.Tasks { Contract.Requires(tasks != null); - // Create a promise task to be returned to the user + // Create a promise task to be returned to the user. + // (If this logic ever changes, also update CommonCWAnyLogicCleanup.) var promise = new CompleteOnInvokePromise(tasks); // At the completion of any of the tasks, complete the promise. @@ -2420,6 +2421,17 @@ namespace System.Threading.Tasks return promise; } + /// + /// Cleans up the operations performed by CommonCWAnyLogic in a case where + /// the created continuation task is being discarded. + /// + /// The task returned from CommonCWAnyLogic. + internal static void CommonCWAnyLogicCleanup(Task continuation) + { + // Force cleanup of the promise (e.g. removing continuations from each + // constituent task), by completing the promise with any value. + ((CompleteOnInvokePromise)continuation).Invoke(null); + } /// /// Creates a continuation Task