Bug Summary

File:src/libraries/tools/Timer.cc
Location:line 257, column 40
Description:Use of memory after it is freed

Annotated Source Code

1/*
2 * ORXONOX - the hottest 3D action shooter ever to exist
3 * > www.orxonox.net <
4 *
5 *
6 * License notice:
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 *
22 * Author:
23 * Fabian 'x3n' Landau
24 * Co-authors:
25 * ...
26 *
27 */
28
29/**
30 @file
31 @brief Implementation of the Timer class.
32*/
33
34#include "Timer.h"
35
36#include <set>
37
38#include <boost/bimap.hpp>
39
40#include "util/Clock.h"
41#include "core/CoreIncludes.h"
42#include "core/command/ConsoleCommandIncludes.h"
43#include "core/command/CommandExecutor.h"
44#include "core/command/Executor.h"
45#include "core/command/Functor.h"
46#include "tools/interfaces/TimeFactorListener.h"
47
48namespace orxonox
49{
50 SetConsoleCommand("delay", &delay)static orxonox::ConsoleCommand& __consolecommand_50 = (new
orxonox::SI_CC(new orxonox::ConsoleCommand("", "delay", orxonox
::createExecutor(orxonox::createFunctor(&delay)))))->getCommand
()
.argumentCompleter(1, autocompletion::command());
51 SetConsoleCommand("delayreal", &delayreal)static orxonox::ConsoleCommand& __consolecommand_51 = (new
orxonox::SI_CC(new orxonox::ConsoleCommand("", "delayreal", orxonox
::createExecutor(orxonox::createFunctor(&delayreal)))))->
getCommand()
.argumentCompleter(1, autocompletion::command());
52 SetConsoleCommand("killdelay", &killdelay)static orxonox::ConsoleCommand& __consolecommand_52 = (new
orxonox::SI_CC(new orxonox::ConsoleCommand("", "killdelay", orxonox
::createExecutor(orxonox::createFunctor(&killdelay)))))->
getCommand()
;
53 SetConsoleCommand("killdelays", &killdelays)static orxonox::ConsoleCommand& __consolecommand_53 = (new
orxonox::SI_CC(new orxonox::ConsoleCommand("", "killdelays",
orxonox::createExecutor(orxonox::createFunctor(&killdelays
)))))->getCommand()
;
54
55 static boost::bimap<unsigned int, Timer*> delaytimers;
56 static unsigned int delayHandleCounter = 0;
57
58 /**
59 @brief Console-command: Calls another console command after @a delay seconds (game time).
60 @param delay The delay in seconds
61 @param command The console command
62 @return The handle of the delayed command, can be used as argument for killdelay()
63 */
64 unsigned int delay(float delay, const std::string& command)
65 {
66 return addDelayedCommand(new Timer(), delay, command);
67 }
68
69 /**
70 @brief Console-command: Calls another console command after @a delay seconds (real time)
71 @param delay The delay in seconds
72 @param command The console command
73 @return The handle of the delayed command, can be used as argument for killdelay()
74 */
75 unsigned int delayreal(float delay, const std::string& command)
76 {
77 return addDelayedCommand(new RealTimer(), delay, command);
78 }
79
80 /**
81 @brief Helper function, used by delay() and delayreal() to add a delayed command.
82 @param timer The timer which will execute the command
83 @param delay The delay in seconds
84 @param command The console command
85 @return The handle of the delayed command, can be used as argument for killdelay()
86 */
87 unsigned int addDelayedCommand(Timer* timer, float delay, const std::string& command)
88 {
89 delaytimers.insert(boost::bimap<unsigned int, Timer*>::value_type(++delayHandleCounter, timer));
90
91 const ExecutorStaticPtr& delayexecutor = createExecutor(createFunctor(&executeDelayedCommand));
92 delayexecutor->setDefaultValues(timer, command);
93 timer->setTimer(delay, false, delayexecutor);
94
95 return delayHandleCounter;
96 }
97
98 /**
99 @brief Helper function for delay(), executes the command and destroys the timer.
100 @param timer The timer which called this function.
101 @param command The command to execute
102 */
103 void executeDelayedCommand(Timer* timer, const std::string& command)
104 {
105 CommandExecutor::execute(command);
106 delete timer;
107 delaytimers.right.erase(timer);
108 }
109
110 /**
111 @brief Console-command: Kills all scheduled commands that were delayed using delay().
112 */
113 void killdelays()
114 {
115 for (boost::bimap<unsigned int, Timer*>::left_map::iterator it = delaytimers.left.begin(); it != delaytimers.left.end(); ++it)
116 delete it->second;
117
118 delaytimers.clear();
119 }
120
121 /**
122 @brief Console-command: Kills a delayed command with given handle.
123 */
124 void killdelay(unsigned int handle)
125 {
126 boost::bimap<unsigned int, Timer*>::left_map::iterator it = delaytimers.left.find(handle);
127 if (it != delaytimers.left.end())
128 {
129 delete it->second;
130 delaytimers.left.erase(it);
131 }
132 }
133
134 RegisterClassNoArgs(Timer)orxonox::SI_I& _TimerIdentifier = (*new orxonox::SI_I(orxonox
::registerClass<Timer>("Timer", new orxonox::ClassFactoryNoArgs
<Timer>(), true)))
;
135
136 /**
137 @brief Constructor: Sets the default-values.
138 */
139 Timer::Timer()
140 {
141 this->init();
142 RegisterObject(Timer)if (ClassIdentifier<Timer>::getIdentifier()->initializeObject
(this)) return; else ((void)0)
;
143 }
144
145 /**
146 @brief Constructor: Initializes and starts the timer, which will call an executor after some time.
147 @param interval The timer-interval in seconds
148 @param bLoop If true, the executor gets called every @a interval seconds
149 @param executor The executor that will be called
150 @param bKillAfterCall If true, the timer will be deleted after the executor was called
151 */
152 Timer::Timer(float interval, bool bLoop, const ExecutorPtr& executor, bool bKillAfterCall)
153 {
154 this->init();
155 RegisterObject(Timer)if (ClassIdentifier<Timer>::getIdentifier()->initializeObject
(this)) return; else ((void)0)
;
156
157 this->setTimer(interval, bLoop, executor, bKillAfterCall);
158 }
159
160 Timer::Timer(float interval, bool bLoop, std::function<void ()> func, bool bKillAfterCall)
161 {
162 this->init();
163 RegisterObject(Timer)if (ClassIdentifier<Timer>::getIdentifier()->initializeObject
(this)) return; else ((void)0)
;
164
165 this->setTimer(interval, bLoop, func, bKillAfterCall);
166 }
167
168 /**
169 @brief Initializes the Timer
170 */
171 void Timer::init()
172 {
173 this->executor_ = nullptr;
174 this->interval_ = 0;
175 this->bLoop_ = false;
176 this->bActive_ = false;
177 this->bKillAfterCall_ = false;
178
179 this->time_ = 0;
180 }
181
182 /**
183 @brief Returns the current time factor of the game.
184 */
185 float Timer::getTimeFactor()
186 {
187 return TimeFactorListener::getTimeFactor();
188 }
189
190 /**
191 @brief Initializes and starts the timer, which will call an executor after some time.
192 @param interval The timer-interval in seconds
193 @param bLoop If true, the executor gets called every @a interval seconds
194 @param executor The executor that will be called
195 @param bKillAfterCall If true, the timer will be deleted after the executor was called
196 */
197 void Timer::setTimer(float interval, bool bLoop, const ExecutorPtr& executor, bool bKillAfterCall)
198 {
199 this->setInterval(interval);
200 this->bLoop_ = bLoop;
201 this->executor_ = executor;
202 this->bActive_ = true;
203 this->isStdFunction_ = false;
204
205 this->time_ = this->interval_;
206 this->bKillAfterCall_ = bKillAfterCall;
207
208 if(executor != nullptr)
209 executor->getFunctor()->setSafeMode(true);
210 }
211
212 void Timer::setTimer(float interval, bool bLoop, std::function<void ()> func, bool bKillAfterCall)
213 {
214 // Without the cast, the call would be ambiguous, because nullptr is castable to
215 // both, ExecutorPtr and std::function.
216 this->setTimer(interval, bLoop, static_cast<ExecutorPtr>(nullptr), bKillAfterCall);
217 this->function_ = func;
218 this->isStdFunction_ = true;
219 }
220
221 /**
222 @brief Calls the executor and destroys the timer if requested.
223 */
224 void Timer::run()
225 {
226 bool temp = this->bKillAfterCall_; // to avoid errors with bKillAfterCall_=false and an exutors which destroy the timer
227
228 if(this->isStdFunction_)
7
Taking true branch
229 this->function_();
230 else
231 (*this->executor_)();
232
233 if (temp)
8
Assuming 'temp' is not equal to 0
9
Taking true branch
234 delete this;
10
Memory is released
235 }
236
237 /**
238 @brief Updates the timer before the frames are rendered.
239 */
240 void Timer::tick(const Clock& time)
241 {
242 if (this->bActive_)
1
Taking true branch
243 {
244 // If active: Decrease the timer by the duration of the last frame
245 this->time_ -= static_cast<long long>(time.getDeltaTimeMicroseconds() * this->getTimeFactor());
246
247 if (this->time_ <= 0)
2
Taking true branch
248 {
249 // It's time to call the function
250 if (this->bLoop_ && !this->bKillAfterCall_)
3
Taking true branch
251 {
252 this->time_ += this->interval_; // Q: Why '+=' and not '='? A: Think about it. It's more accurate like that. Seriously.
253 while (this->time_ <= 0)
4
Loop condition is true. Entering loop body
5
Loop condition is true. Entering loop body
254 {
255 // The interval was shorter than one tick, so execute the function more than once
256 this->run();
6
Calling 'Timer::run'
11
Returning; memory was released
257 this->time_ += this->interval_;
12
Use of memory after it is freed
258 }
259 }
260 else
261 this->stopTimer(); // Stop the timer if we don't want to loop
262
263 this->run();
264 }
265 }
266 }
267
268 ///////////////
269 // RealTimer //
270 ///////////////
271
272 RegisterClassNoArgs(RealTimer)orxonox::SI_I& _RealTimerIdentifier = (*new orxonox::SI_I
(orxonox::registerClass<RealTimer>("RealTimer", new orxonox
::ClassFactoryNoArgs<RealTimer>(), true)))
;
273
274 /// @copydoc Timer::Timer
275 RealTimer::RealTimer()
276 {
277 RegisterObject(RealTimer)if (ClassIdentifier<RealTimer>::getIdentifier()->initializeObject
(this)) return; else ((void)0)
;
278 }
279
280 /// @copydoc Timer::Timer(float, bool, const ExecutorPtr&, bool)
281 RealTimer::RealTimer(float interval, bool bLoop, const ExecutorPtr& executor, bool bKillAfterCall) : Timer(interval, bLoop, executor, bKillAfterCall)
282 {
283 RegisterObject(RealTimer)if (ClassIdentifier<RealTimer>::getIdentifier()->initializeObject
(this)) return; else ((void)0)
;
284 }
285
286 /// Returns always 1 because RealTimer doesn't depend on the game time.
287 float RealTimer::getTimeFactor()
288 {
289 return 1;
290 }
291}