From 8480bdda831e4d18c1979f40badb1bc985e78865 Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Thu, 21 Jan 2016 18:15:50 +0000
Subject: Ensure that BoostTimers can't fire after stop()

Code review makes me think that if the timer fires at the same time as
stop() is called, it would be possible for the clearing of events from
the loop to happen before the event is put into the loop, leading to
the sort of crashes we've seen with timers firing and access exceptions.
I can't reproduce those to know if this fixes them, and I'm not even sure
I'm not being dense thinking this patch fixes a real issue.

Test-Information:
Unit tests pass

Change-Id: I76337d5556a9c3902d5c2f4da754ae657810d436

diff --git a/Swiften/Network/BoostTimer.cpp b/Swiften/Network/BoostTimer.cpp
index 30f5180..c30fe32 100644
--- a/Swiften/Network/BoostTimer.cpp
+++ b/Swiften/Network/BoostTimer.cpp
@@ -15,7 +15,7 @@
 namespace Swift {
 
 BoostTimer::BoostTimer(int milliseconds, boost::shared_ptr<boost::asio::io_service> service, EventLoop* eventLoop) :
-		timeout(milliseconds), ioService(service), eventLoop(eventLoop) {
+		timeout(milliseconds), ioService(service), eventLoop(eventLoop), shuttingDown(false) {
 		timer.reset(new boost::asio::deadline_timer(*service));
 }
 
@@ -29,6 +29,7 @@ BoostTimer::~BoostTimer() {
 void BoostTimer::start() {
 	{
 		boost::mutex::scoped_lock lockTimer(timerMutex);
+		shuttingDown = false;
 		timer->expires_from_now(boost::posix_time::milliseconds(timeout));
 		timer->async_wait(boost::bind(&BoostTimer::handleTimerTick, shared_from_this(), boost::asio::placeholders::error));
 	}
@@ -37,9 +38,10 @@ void BoostTimer::start() {
 void BoostTimer::stop() {
 	{
 		boost::mutex::scoped_lock lockTimer(timerMutex);
+		shuttingDown = true;
 		timer->cancel();
+		eventLoop->removeEventsFromOwner(shared_from_this());
 	}
-	eventLoop->removeEventsFromOwner(shared_from_this());
 }
 
 void BoostTimer::handleTimerTick(const boost::system::error_code& error) {
@@ -47,7 +49,13 @@ void BoostTimer::handleTimerTick(const boost::system::error_code& error) {
 		assert(error == boost::asio::error::operation_aborted);
 	}
 	else {
-		eventLoop->postEvent(boost::bind(boost::ref(onTick)), shared_from_this());
+		{
+			boost::mutex::scoped_lock lockTimer(timerMutex);
+			if (shuttingDown) {
+				return;
+			}
+			eventLoop->postEvent(boost::bind(boost::ref(onTick)), shared_from_this());
+		}
 	}
 }
 
diff --git a/Swiften/Network/BoostTimer.h b/Swiften/Network/BoostTimer.h
index a246b75..3227031 100644
--- a/Swiften/Network/BoostTimer.h
+++ b/Swiften/Network/BoostTimer.h
@@ -43,5 +43,6 @@ namespace Swift {
 			boost::scoped_ptr<boost::asio::deadline_timer> timer;
 			boost::mutex timerMutex;
 			EventLoop* eventLoop;
+			bool shuttingDown;
 	};
 }
-- 
cgit v0.10.2-6-g49f6