No, the crash does not happen across DLL reload. It's during the same session. I have spent a fair bit of time debugging it, but it's not giving me a whole lot to work with. That being said, I'm definitely open to tips on how to debug it better if there's something I'm missing.
I'll walk through what's happening and provide the stack trace to better illustrate it.
Here is the timer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 | struct bbTimer {
fsr32 duration;
fsr32 interval;
fsr32 t, ti;
bool active;
std::function<void(bbTimer*)> callback;
bbTimer(fsr32 duration, fsr32 interval);
bbTimer(fsr32 duration, fsr32 interval, void(*func)(bbTimer*));
bbTimer(const bbTimer ©);
bbTimer& operator=(const bbTimer&);
template <typename F>
bbTimer(fsr32 duration, fsr32 interval, F func)
: bbTimer(duration, interval)
{
callback = func;
}
void start();
void stop();
};
|
I can create a timer like this:
| bbTimer timer(2.f, bbTimeInterval60FPS);
timer.callback = [](bbTimer *t) {
printf("hi, %f\n", t->t);
};
timer.start();
|
Calling start on the timer adds itself to the timers list:
| void
bbTimer::start() {
active = true;
timers.push_back(*this);
}
|
The timers list is my own custom implementation of a cache-friendly linked list that can use memory that I pass to it. (Just to reiterate, if I
don't initialize the timers list with the allocated memory from the platform layer so it uses malloc/free for each node, everything works fine in both debug and release configurations.)
push_back ends up calling allocate_and_init_node, which triggers the copy-assignment operator of bbTimer:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | template <typename T, typename Allocator>
typename fsList<T, Allocator>::nodeType*
fsList<T, Allocator>::allocate_and_init_node(const T& data, nodeType *next, nodeType *prev)
{
nodeType *node = (nodeType *)_allocator.allocate(sizeof(nodeType));
if (node) {
fs_memclear(node, sizeof(nodeType));
node->data = data; <<<<<<<<<<<<<<<<<<< Copy-assignment here!
node->next = next;
node->prev = prev;
}
return node;
}
bbTimer&
bbTimer::operator=(const bbTimer &rhs)
{
if (this != &rhs) {
duration = rhs.duration; <<<<<<<<<<<<<<< Crashes here!
interval = rhs.interval;
active = rhs.active;
t = rhs.t;
ti = rhs.ti;
callback = rhs.callback;
}
return (*this);
}
|
Here is the stack trace:
link
And here is the stack trace in assembly (looks like it's on a mov instruction):
link
In terms of serialization, you're absolutely right, it won't work with std::function for the same reason it won't for function pointers. So there's no firm reason why I need to allocate the list with the game memory (I made this assumption earlier when I didn't realize it wouldn't work). However, even though I can fix it pretty easily by just using malloc/free for each node, I still want to get to the bottom of this problem so I can actually understand what is wrong. (And so I don't do it again! :p)
Thanks for your help!