Ensure ListenerSecondary buffer isn't double freed or freed too early

- Call buf_init in StartAsync so we have access to a KestrelThread
This commit is contained in:
Stephen Halter 2015-11-04 15:45:14 -08:00
parent 74f08c16df
commit fff28990fe
1 changed files with 26 additions and 9 deletions

View File

@ -3,6 +3,7 @@
using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Server.Kestrel.Infrastructure;
@ -24,7 +25,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
protected ListenerSecondary(ServiceContext serviceContext) : base(serviceContext)
{
_ptr = Marshal.AllocHGlobal(4);
_buf = Thread.Loop.Libuv.buf_init(_ptr, 4);
}
UvPipeHandle DispatchPipe { get; set; }
@ -36,6 +36,8 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
RequestDelegate application)
{
_pipeName = pipeName;
_buf = thread.Loop.Libuv.buf_init(_ptr, 4);
ServerAddress = address;
Thread = thread;
Application = application;
@ -93,10 +95,10 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
DispatchPipe.ReadStart(
(handle, status2, state) => ((ListenerSecondary)state)._buf,
(handle, status2, state) =>
{
var listener = ((ListenerSecondary)state);
listener.ReadStartCallback(handle, status2, listener._ptr);
}, this);
{
var listener = ((ListenerSecondary)state);
listener.ReadStartCallback(handle, status2, listener._ptr);
}, this);
tcs.SetResult(0);
}
@ -119,7 +121,6 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
}
DispatchPipe.Dispose();
Marshal.FreeHGlobal(ptr);
return;
}
@ -150,17 +151,33 @@ namespace Microsoft.AspNet.Server.Kestrel.Http
/// </summary>
protected abstract UvStreamHandle CreateAcceptSocket();
private void FreeBuffer()
{
var ptr = Interlocked.Exchange(ref _ptr, IntPtr.Zero);
if (ptr != IntPtr.Zero)
{
Marshal.FreeHGlobal(_ptr);
}
}
public void Dispose()
{
Marshal.FreeHGlobal(_ptr);
// Ensure the event loop is still running.
// If the event loop isn't running and we try to wait on this Post
// to complete, then KestrelEngine will never be disposed and
// the exception that stopped the event loop will never be surfaced.
if (Thread.FatalError == null)
{
Thread.Send(listener => ((ListenerSecondary)listener).DispatchPipe.Dispose(), this);
Thread.Send(state =>
{
var listener = (ListenerSecondary)state;
listener.DispatchPipe.Dispose();
listener.FreeBuffer();
}, this);
}
else
{
FreeBuffer();
}
}
}