[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: [Libevent-users] a bug of libevent(2.1.4-alpha) IOCP: socket is closed twice when bufferevent is freed



On Thu, Nov 20, 2014 at 03:06:59PM +0800, jason wrote:
> I ran into a strange situation where some new connections were randomly
> closed just after many client connections were closed. I finally get the
> reason after diving into source code and debugging for several hours.
> 
>  
> 
> When bufferevent is freed, the internal socket is closed at be_async_ctrl().
> 
> 
> Call stack:
> 
> >       51CY.exe!be_async_ctrl(bufferevent * bev, bufferevent_ctrl_op op,
> bufferevent_ctrl_data * data)  Line 673  C
> 
>        51CY.exe!bufferevent_cancel_all_(bufferevent * bev)  Line 884 + 0x15
> bytes     C
> 
>        51CY.exe!bufferevent_free(bufferevent * bufev)  Line 786 + 0x9 bytes
> C
> 
>        51CY.exe!be_filter_unlink(bufferevent * bev)  Line 234 + 0xf bytes
> C
> 
>        51CY.exe!bufferevent_decref_and_unlock_(bufferevent * bufev)  Line
> 696 + 0xf bytes      C
> 
>        51CY.exe!bufferevent_free(bufferevent * bufev)  Line 787 + 0x9 bytes
> C
> 
>  
> 
> Bufferevent_free() also forwards a event callback to event_base.
> 
> Call stack:
> 
> >       51CY.exe!event_callback_finalize_many_(event_base * base, int n_cbs,
> event_callback * * evcbs, void (event_callback *, void *)* cb)  Line 2210
> C
> 
>        51CY.exe!bufferevent_decref_and_unlock_(bufferevent * bufev)  Line
> 713 + 0x18 bytes   C
> 
>        51CY.exe!bufferevent_free(bufferevent * bufev)  Line 787 + 0x9 bytes
> C
> 
>  
> 
> The same socket is secondly closed when the event callback is invoked in the
> next event_base loop.
> 
> Callstack:
> 
> >       51CYClient.exe!evutil_closesocket(int sock)  Line 425 C
> 
>        51CYClient.exe!be_async_destruct(bufferevent * bev)  Line 386 + 0x9
> bytes     C
> 
>        51CYClient.exe!bufferevent_finalize_cb_(event_callback * evcb, void *
> arg_)  Line 734 + 0xf bytes C
> 
>        51CYClient.exe!event_process_active_single_queue(event_base * base,
> evcallback_list * activeq, int max_to_process, const timeval * endtime)
> Line 1604 + 0xe bytes  C
> 
>        51CYClient.exe!event_process_active(event_base * base)  Line 1668 +
> 0x14 bytes  C
> 
>        51CYClient.exe!event_base_loop(event_base * base, int flags)  Line
> 1890 + 0x9 bytes     C
> 
>  
> 
> So socket of new connection will be closed by this mean if the new socket
> handle value equals to the old one.

Hi Jason,

If I understand you correctly, the following patch must helps, could
please verify this?

diff --git a/bufferevent_async.c b/bufferevent_async.c
index f32573e..6395e57 100644
--- a/bufferevent_async.c
+++ b/bufferevent_async.c
@@ -381,9 +381,10 @@ be_async_destruct(struct bufferevent *bev)
 	bev_async_del_write(bev_async);
 
 	fd = evbuffer_overlapped_get_fd_(bev->input);
-	if (bev_p->options & BEV_OPT_CLOSE_ON_FREE) {
-		/* XXXX possible double-close */
+	if (fd != (evutil_socket_t)INVALID_SOCKET &&
+		(bev_p->options & BEV_OPT_CLOSE_ON_FREE)) {
 		evutil_closesocket(fd);
+		evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
 	}
 }
 
@@ -671,6 +672,7 @@ be_async_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op,
 		if (fd != (evutil_socket_t)INVALID_SOCKET &&
 		    (bev_a->bev.options & BEV_OPT_CLOSE_ON_FREE)) {
 			closesocket(fd);
+			evbuffer_overlapped_set_fd_(bev->input, INVALID_SOCKET);
 		}
 		bev_a->ok = 0;
 		return 0;

(You email client could make patch un appliable I think, based on you
incoming email, if so would happen, let me know, I will resend as an
attachment).
***********************************************************************
To unsubscribe, send an e-mail to majordomo@xxxxxxxxxxxxx with
unsubscribe libevent-users    in the body.