@masshacker, yes that does look like the same bug. It’s a data race so it can be quite hard to reproduce.
Here’s what Address Sanitizer has to say about the crash site:
AddressSanitizer: heap-use-after-free on address 0x000123a3d048 at pc 0x00010510b2b0 bp 0x00016b291e10 sp 0x00016b291e08
READ of size 1 at 0x000123a3d048 thread T1
#0 0x10510b2ac in juce::URLConnectionState::didComplete(NSError*)+0x29c (/private/var/containers/Bundle/Application/FDC30A7A-DDAE-4531-9405-6FF374BCAAFD/JUCETest.app/JUCETest:arm64+0x1005172ac)
#1 0x1051016a8 in juce::URLConnectionState::DelegateClass::didCompleteWithError(objc_object*, objc_selector*, NSURLConnection*, NSURLSessionTask*, NSError*)+0x90 (/private/var/containers/Bundle/Application/FDC30A7A-DDAE-4531-9405-6FF374BCAAFD/JUCETest.app/JUCETest:arm64+0x10050d6a8)
(...rest of stack trace removed...)
It says the problem is heap-use-after-free in juce::URLConnectionState::didComplete().
The line of code that it crashes on is accessing the member variable URLConnectionStateBase::isBeingDeleted
void didComplete (NSError* error)
{
// ...code removed for clarity...
if (isBeingDeleted)
return;
// ...code removed for clarity...
}
Now let’s look at who freed the URLConnectionStateBase object:
0x000123a3d048 is located 712 bytes inside of 720-byte region [0x000123a3cd80,0x000123a3d050)
freed by thread T8 here:
#0 0x107ea622c in wrap__ZdlPv+0x74 (/private/var/containers/Bundle/Application/FDC30A7A-DDAE-4531-9405-6FF374BCAAFD/JUCETest.app/Frameworks/libclang_rt.asan_ios_dynamic.dylib:arm64e+0x6222c)
#1 0x1050fbf3c in juce::URLConnectionState::~URLConnectionState()+0x64 (/private/var/containers/Bundle/Application/FDC30A7A-DDAE-4531-9405-6FF374BCAAFD/JUCETest.app/JUCETest:arm64+0x100507f3c)
(...rest of stack trace removed...)
It says that the allocation was freed by URLConnectionState::~URLConnectionState(), which is the place you would expect.
One of the trickiest aspects of understanding this bug is the realization that [session finishTasksAndInvalidate] isn’t a blocking call.
Here’s what the docs say:
“-finishTasksAndInvalidate returns immediately and existing tasks will be allowed to run to completion. New tasks may not be created. The session will continue to make delegate callbacks until URLSession:didBecomeInvalidWithError: has been issued.”
So it seems clear that it’s a data race between the delegate callback and the destructor.