Hi,
I’m using realloc()
as part of a buffer reassignment for an AudioProcessor
, and I get a crash (sometimes in a totally different area, like realloc()
downstream of repaint()
) from the reallocation code.
I put the reallocation in a message thread using AsyncUpdater
, but this did not solve my issue. Is there a way to check for a lock before running reallocation code? I can’t see what else the issue could be.
Tips for best practice are appreciated!!
Edit: crash details
Summary
This is the stack trace I’ve got on the crash:
__GI_raise 0x00007f179af1e081
__GI_abort 0x00007f179af09535
__libc_message 0x00007f179af5fdc8
malloc_printerr 0x00007f179af6632a
_int_realloc 0x00007f179af6a25c
__GI___libc_realloc 0x00007f179af6b3cb
juce::HeapBlock<std::complex<float>, false>::realloc<int> juce_HeapBlock.h:293
STFT::updateFftSize STFT.h:123
and this is the realloc()
line that is crashing (not the actual throw()
):
/** Re-allocates a specified amount of memory.
The semantics of this method are the same as malloc() and calloc(), but it
uses realloc() to keep as much of the existing data as possible.
*/
template <typename SizeType>
void realloc (SizeType newNumElements, size_t elementSize = sizeof (ElementType))
{
data = static_cast<ElementType*> (data == nullptr ? std::malloc (static_cast<size_t> (newNumElements) * elementSize)
: std::realloc (data, static_cast<size_t> (newNumElements) * elementSize));
^^^ - crashes here
throwOnAllocationFailure();
}
Sweet, I got it.
Adding:
CriticalSection lock; // .h
const ScopedLock sl (lock); // .cpp - at start of reallocation method
seems to solve the issue
So you are reallocating asynchronous on the message thread and accessing the HeapBlock
on another thread (the audio thread?) simultaniously? If it’s like that than this sounds like a bad design. However, a good solution to this depends on the context.
A simple one is to create a CriticalSection
object that has to be locked by a ScopedLock
for every kind of access to the HeapBlock
. For many use-cases this is a good idea, but in case you are working on the audio thread, this could lead to the audio thread being blocked my the message thread that holds the lock but has a lower priority. This would be called a priority inversion and can lead to audio dropouts. In this case, I’d advise you to have two heap blocks, one that is accessed from the audio thread and one that is not. You can then safely resize the inactive block on the message thread or any other and copy over the content from the active one. When all is done, you can simply swap them, which is a short operation
1 Like
Yes, thank you!
Previously I had missed that I was using this reallocation directly on the audio thread, and yes, it caused issues. I had moved all the reallocation to the message thread, but still had the crash I originally posted.
The CriticalSection
and ScopedLock
solved the issue, thanks for pointing it out! Although I originally got the result straight from the open-sourced code I’m using 
Thanks for pointing out the swapping operation as well. It may come in useful, although, in my case right now - when CriticalSection
/ScopedLock
is used, does this prevent the AudioThread from trying to access the heaps being modified? (to avoid mid-resize accesses)
It prevents it in a nasty way: it will let the processBlock wait until you are finished doing your allocation!
That is exactly what PluginPenguin described as priority inversion.
An allocation can take an infinite amount of time, because the memory management needs to lock as well, so you have no idea for whom you are actually waiting.
1 Like
Alright, that makes sense. Thanks for pointing it out!