diff options
Diffstat (limited to 'src/timer.cpp')
-rw-r--r-- | src/timer.cpp | 42 |
1 files changed, 38 insertions, 4 deletions
diff --git a/src/timer.cpp b/src/timer.cpp index 6be7aa06c..e7635c528 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -14,15 +14,22 @@ #include "inspircd.h" #include "timer.h" +TimerManager::TimerManager() : CantDeleteHere(false) +{ +} + void TimerManager::TickTimers(time_t TIME) { + this->CantDeleteHere = true; timerlist::iterator found = Timers.find(TIME); if (found != Timers.end()) { timergroup* x = found->second; - /* - * There are pending timers to trigger + /* There are pending timers to trigger. + * WARNING: Timers may delete themselves from within + * their own Tick methods! see the comment below in + * the DelTimer method. */ for (timergroup::iterator y = x->begin(); y != x->end(); y++) { @@ -41,10 +48,30 @@ void TimerManager::TickTimers(time_t TIME) Timers.erase(found); DELETE(x); } + + this->CantDeleteHere = false; } void TimerManager::DelTimer(InspTimer* T) { + if (this->CantDeleteHere) + { + /* If a developer tries to delete a timer from within its own Tick method, + * then chances are this is just going to totally fuck over the timergroup + * and timerlist iterators and cause a crash. Thanks to peavey and Bricker + * for noticing this bug. + * If we're within the tick loop when the DelTimer is called (signified + * by the var 'CantDeleteHere') then we simply return for non-repeating + * timers, and cancel the repeat on repeating timers. We can do this because + * we know that the timer tick loop will safely delete the timer for us + * anyway and therefore we avoid stack corruption. + */ + if (T->GetRepeat()) + T->CancelRepeat(); + else + return; + } + timerlist::iterator found = Timers.find(T->GetTimer()); if (found != Timers.end()) @@ -58,15 +85,16 @@ void TimerManager::DelTimer(InspTimer* T) DELETE(n); x->erase(y); if (!x->size()) + { Timers.erase(found); + } return; } } } } -/* - * Because some muppets may do odd things, and their ircd may lock up due +/** Because some muppets may do odd things, and their ircd may lock up due * to crappy 3rd party modules, or they may change their system time a bit, * this accounts for shifts of up to 120 secs by looking behind for missed * timers and executing them. This is only executed once every 5 secs. @@ -75,6 +103,10 @@ void TimerManager::DelTimer(InspTimer* T) */ void TimerManager::TickMissedTimers(time_t TIME) { + /** See comment above in TickTimers + */ + this->CantDeleteHere = true; + for (time_t n = TIME-1; n > TIME-120; n--) { timerlist::iterator found = Timers.find(n); @@ -99,6 +131,8 @@ void TimerManager::TickMissedTimers(time_t TIME) DELETE(x); } } + + this->CantDeleteHere = false; } void TimerManager::AddTimer(InspTimer* T, long secs_from_now) |