diff options
author | justremotephone <justremotephone@gmail.com> | 2019-03-06 03:07:29 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-03-06 03:07:29 +0300 |
commit | eb3f7312bd4da3e6ca1e072c06fcb3f1338ad974 (patch) | |
tree | 13bc472ae77512daa74af3512c35dd20d36094b0 /mcs/class/System.ServiceModel | |
parent | 24c637dd2651bb1ea137e872291dc5163dedf50d (diff) |
[System.ServiceModel] Fix a race condition in HttpRequestChannel. (#13304)
Concurrent request completions could cause following exception:
```
FATAL UNHANDLED EXCEPTION: System.ArgumentOutOfRangeException:
Index was out of range. Must be non-negative and less than
the size of the collection.
Parameter name: index
at System.Collections.Generic.List`1[T].RemoveAt (System.Int32 index) [0x00009] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Collections.Generic.List`1[T].Remove (T item) [0x0000c] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.ServiceModel.Channels.HttpRequestChannel+HttpChannelRequestAsyncResult.Cleanup () [0x00011] in <28c4695205ef47378f5370502b066592>:0
at System.ServiceModel.Channels.HttpRequestChannel+HttpChannelRequestAsyncResult.set_IsCompleted (System.Boolean value) [0x00034] in <28c4695205ef47378f5370502b066592>:0
at System.ServiceModel.Channels.HttpRequestChannel+HttpChannelRequestAsyncResult.Complete (System.Exception ex) [0x0001a] in <28c4695205ef47378f5370502b066592>:0
at System.ServiceModel.Channels.HttpRequestChannel+<>c__DisplayClass7_1.<BeginProcessRequest>b__0 (System.IAsyncResult r) [0x000bd] in <28c4695205ef47378f5370502b066592>:0
This stack was captured after some changes in AwaitTaskContinuation.RunOrScheduleAction.
Unfortunately the current implementation of AwaitTaskContinuation.RunOrScheduleAction re-throws the above
exception with a wrong stack:
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction (System.Action action, System.Boolean allowInlining, System.Threading.Tasks.Task& currentTask) [0x00023] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.FinishContinuations () [0x00052] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.FinishStageThree () [0x0003c] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.FinishStageTwo () [0x000a1] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.Finish (System.Boolean bUserDelegateExecuted) [0x00003] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.TrySetException (System.Object exceptionObject) [0x00023] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[TResult].SetException (System.Exception exception) [0x00029] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Net.HttpWebRequest+<RunWithTimeoutWorker>d__241`1[T].MoveNext () [0x000e0] in <3e9b3e26c4694baab3f689687ad40612>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext (System.Object stateMachine) [0x00000] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.ExecutionContext.RunInternal (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00071] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.ExecutionContext.Run (System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, System.Object state, System.Boolean preserveSyncCtx) [0x00000] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.Run () [0x00024] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction (System.Action action, System.Boolean allowInlining, System.Threading.Tasks.Task& currentTask) [0x00023] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.FinishContinuations () [0x00052] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task.FinishStageThree () [0x0003c] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Threading.Tasks.Task`1[TResult].TrySetResult (TResult result) [0x0004f] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1[TResult].SetResult (TResult result) [0x0003d] in <4a8a0eaa024f41829d3435c07e5c7edb>:0
at System.Net.ServicePointScheduler+<WaitAsync>d__45.MoveNext () [0x000f7] in <3e9b3e26c4694baab3f689687ad40612>:0
at System.Runtime.CompilerServices.AsyncMethodBuilderCore+MoveNextRunner.InvokeMoveNext (System.Object stateMachine) [0x00000] in <4a8a0
```
On an Android Xamarin installation this causes an app crash. Since no user code is active the exception cannot be caught.
Diffstat (limited to 'mcs/class/System.ServiceModel')
-rw-r--r-- | mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs | 30 |
1 files changed, 25 insertions, 5 deletions
diff --git a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs index 4e4d73f9fb1..c5a96fe3314 100644 --- a/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs +++ b/mcs/class/System.ServiceModel/System.ServiceModel.Channels/HttpRequestChannel.cs @@ -41,7 +41,8 @@ namespace System.ServiceModel.Channels { HttpChannelFactory<IRequestChannel> source; - List<WebRequest> web_requests = new List<WebRequest> (); + object locker = new object(); + List<WebRequest> web_requests = new List<WebRequest> (); //synced by locker // Constructor @@ -86,7 +87,12 @@ namespace System.ServiceModel.Channels } var web_request = (HttpWebRequest) HttpWebRequest.Create (destination); - web_requests.Add (web_request); + + lock (locker) + { + web_requests.Add (web_request); + } + result.WebRequest = web_request; web_request.Method = "POST"; web_request.ContentType = Encoder.ContentType; @@ -350,9 +356,20 @@ namespace System.ServiceModel.Channels protected override void OnAbort () { - foreach (var web_request in web_requests.ToArray ()) + WebRequest[] current_web_requests; + + lock (locker) + { + current_web_requests = web_requests.ToArray(); + } + + foreach (var web_request in current_web_requests) web_request.Abort (); - web_requests.Clear (); + + lock(locker) + { + web_requests.Clear (); + } } // Close @@ -497,7 +514,10 @@ namespace System.ServiceModel.Channels void Cleanup () { - owner.web_requests.Remove (WebRequest); + lock (owner.locker) + { + owner.web_requests.Remove (WebRequest); + } } } } |