8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 04:03:04 +01:00

Fixed bug CORE-5015 : AV in engine could happen when ON DISCONNECT trigger posted event

This commit is contained in:
hvlad 2015-11-12 14:13:33 +00:00
parent b8f65ccad4
commit 9d6b93176c

View File

@ -692,8 +692,8 @@ GlobalPtr<Mutex> GlobalPortLock::mtx;
class Callback FB_FINAL : public RefCntIface<IEventCallbackImpl<Callback, CheckStatusWrapper> >
{
public:
explicit Callback(Rvnt* aevent)
: event(aevent)
explicit Callback(Rdb* aRdb, Rvnt* aEvent)
: rdb(aRdb), event(aEvent)
{ }
// IEventCallback implementation
@ -709,21 +709,22 @@ public:
*
**************************************/
{
const bool allowCancel = event->rvnt_destroyed.compareExchange(0, 1);
if (!allowCancel)
return;
Rdb* rdb = event->rvnt_rdb;
rem_port* port = rdb->rdb_port->port_async;
if (!port)
if (!port || port->port_flags & PORT_detached)
return;
RefMutexGuard portGuard(*port->port_sync, FB_FUNCTION);
if (port->port_flags & PORT_detached)
return;
// hvlad: it is important to call IEvents::cancel() under protection
// of async port mutex to avoid crash in rem_port::que_events
const bool allowCancel = event->rvnt_destroyed.compareExchange(0, 1);
if (!allowCancel)
return;
if (allowCancel && event->rvnt_iface)
{
LocalStatus ls;
@ -758,6 +759,7 @@ public:
}
private:
Rdb* rdb;
Rvnt* event;
};
@ -2294,6 +2296,13 @@ static void aux_request( rem_port* port, /*P_REQ* request,*/ PACKET* send)
connected = aux_port->connect(send) != NULL;
if (connected)
aux_port->port_context = rdb;
else
{
aux_port->port_flags &= ~PORT_connecting;
fb_assert(port->port_async == aux_port);
port->port_async = NULL;
aux_port->disconnect();
}
}
catch (const Exception& ex)
{
@ -2868,12 +2877,15 @@ ISC_STATUS rem_port::end_database(P_RLSE* /*release*/, PACKET* sendL)
port_flags |= PORT_detached;
if (port_async)
{
port_async->port_flags |= PORT_detached;
rdb->rdb_iface = NULL;
RefMutexGuard portGuard(*port_async->port_sync, FB_FUNCTION);
while (rdb->rdb_events)
release_event(rdb->rdb_events);
}
while (rdb->rdb_events)
release_event(rdb->rdb_events);
rdb->rdb_iface = NULL;
while (rdb->rdb_requests)
release_request(rdb->rdb_requests);
@ -4616,7 +4628,7 @@ ISC_STATUS rem_port::que_events(P_EVENT * stuff, PACKET* sendL)
#endif
event->rvnt_next = rdb->rdb_events;
rdb->rdb_events = event;
event->rvnt_callback = FB_NEW Callback(event);
event->rvnt_callback = FB_NEW Callback(rdb, event);
}
event->rvnt_id = stuff->p_event_rid;