From d03796219f4c8138f3edb2c97768f782e831ef48 Mon Sep 17 00:00:00 2001 From: Matt Ward Date: Thu, 27 Jun 2019 12:26:15 +0100 Subject: [Core] Fix null ref if RunTarget called after Project is disposed Project.RunTarget now uses BindTask so the target will complete before the Project is disposed. This will also prevent a null reference exception that could occur when the MSBuildProject was accessed in RunMSBuildTarget when RunTarget is called after the Project is disposed. A TaskCancelationException is thrown if RunTarget is called after the Project has been disposed. Fixes VSTS #935875 - High exception count in MSBuild as run by the Android Designer Could not reproduce the above bug testing the designer. Assumption based on the exception callstack is that RunTarget is being called after the Project is disposed. --- .../core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs') diff --git a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs index e53cda474c..7e62055fe7 100644 --- a/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs +++ b/main/src/core/MonoDevelop.Core/MonoDevelop.Projects/Project.cs @@ -706,7 +706,7 @@ namespace MonoDevelop.Projects ctx.BuilderQueue = BuilderQueue.ShortOperations; ctx.LogVerbosity = MSBuildVerbosity.Quiet; - var evalResult = await project.RunTarget (monitor, dependsList, config.Selector, ctx); + var evalResult = await project.RunTargetInternal (monitor, dependsList, config.Selector, ctx); if (evalResult != null && evalResult.Items != null) { result = ProcessMSBuildItems (evalResult.Items, project); } @@ -1250,6 +1250,13 @@ namespace MonoDevelop.Projects /// Configuration to use to run the target /// public Task RunTarget (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context = null) + { + return BindTask (cancelToken => { + return RunTargetInternal (monitor.WithCancellationToken (cancelToken), target, configuration, context); + }); + } + + internal Task RunTargetInternal (ProgressMonitor monitor, string target, ConfigurationSelector configuration, TargetEvaluationContext context = null) { // Initialize the evaluation context. This initialization is shared with FastCheckNeedsBuild. // Extenders will override OnConfigureTargetEvaluationContext to add custom properties and do other @@ -1865,7 +1872,7 @@ namespace MonoDevelop.Projects protected override async Task OnBuild (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext operationContext) { var newContext = operationContext as TargetEvaluationContext ?? new TargetEvaluationContext (operationContext); - return (await RunTarget (monitor, "Build", configuration, newContext)).BuildResult; + return (await RunTargetInternal (monitor, "Build", configuration, newContext)).BuildResult; } async Task RunBuildTarget (ProgressMonitor monitor, ConfigurationSelector configuration, TargetEvaluationContext context) @@ -2250,7 +2257,7 @@ namespace MonoDevelop.Projects protected override async Task OnClean (ProgressMonitor monitor, ConfigurationSelector configuration, OperationContext buildSession) { var newContext = buildSession as TargetEvaluationContext ?? new TargetEvaluationContext (buildSession); - return (await RunTarget (monitor, "Clean", configuration, newContext)).BuildResult; + return (await RunTargetInternal (monitor, "Clean", configuration, newContext)).BuildResult; } Task RunCleanTarget (ProgressMonitor monitor, ConfigurationSelector configuration, TargetEvaluationContext context) -- cgit v1.2.3