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