I have created an example of my class: https://github.com/ChoadPet/H.264-Decoding
When I build my application with DEBUG configuration everything is working fine, but when I archive RELEASE it's crashing on this line:
let status = VTDecompressionSessionDecodeFrame(session,
sampleBuffer: sampleBuffer,
flags: defaultDecodeFlags,
frameRefcon: nil,
infoFlagsOut: nil)
With Address Sanitizer enable I got this error:
Thread 9: Use of deallocated memory
SUMMARY: AddressSanitizer: heap-use-after-free
(.../Frameworks/libclang_rt.asan_ios_dynamic.dylib:arm64+0x1a1f4) in wrap_memmove
...
(if you need more crash info, let me know)
Without: Thread 12: EXC_BAD_ACCESS (code=1, address=0x107dd0020)
I do understand that there is some memory that was freed and it accesses by VTDecompressionSessionDecodeFrame method, but I can't find any address with hex, and I don't understand how this is working perfectly with the DEBUG build.
Before this method, session and sampleBuffer are successfully created(initialized).
Is there are some project settings I can change to DEBUG configuration which can cause the crash? Or somebody can point me out on a code issue?
Thank you!
Changing Optimization Level for Release archive to the same as for Debug - No Optimization[-Onone] hide the problem, but changing build configuration is not the right way to resolve this kinda problem. Also, the problem was not exactly in sampleBuffer. The problem was in blockBufferOut parameter, which goes into sampleBuffer later. I will update the repo source code, so the community can see changes clearly.
So I had before this logic:
// 1. Creating blockBuffer from `bufferPointer`
localFrame.withUnsafeMutableBufferPointer { bufferPointer in
// I should write everything in this body,
// since bufferPointer would be released after the closure
// and so, it will be released from bufferBlock
}
// 2. I called this method, which is creating `sampleBuffer`
CMSampleBufferCreateReady
// 3. I called this method, which is decode frame with session and sampleBuffer
VTDecompressionSessionDecodeFrame
/*
and on this line, it crashes with EXC_BAD_ACCESS,
because the sample wasn't valid anymore, because
on step 1, bufferPointer only valid inside body closure,
so it's release after block when I created sampleBuffer
and later decode it.
This is even pointed by documentation:
Parameters
body
Closure with an UnsafeMutableBufferPointer parameter that points to the
contiguous storage for the array. If no such storage exists, it is created. If
the body has a return value, that value is also used as the return value for the
withUnsafeMutableBufferPointer(_:) method. The pointer argument is valid only for
the duration of the method’s execution.
*/
Summary: if you operate on bufferPointer, do all operations inside a closure.
Added to the answer provided by #vpoltave, I found using a dispatch queue after the samplebuffer creation used to give me an EXC_BAD_ACCESS error or if you turn on address sanitiser, then it would error out in the com.apple.coremedia.videomediaconverter with Use of deallocated memory. Suggestion is to enqueue the raw data instead of the created buffers. For me the source was a frame in elementary format coming in callbacks.
Related
My app uses the following function to serialise a set of custom objects (only relevant code is shown):
class func serializeShoppingLocations(buyLocations: Set<ShoppingLocation>) -> Data {
#if os(iOS)
NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListIOS.ShoppingLocation.self)
#elseif os(watchOS)
NSKeyedArchiver.setClassName("ShoppingLocation", for: ShoppingListWatch.ShoppingLocation.self)
#endif
let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations)
return data
}
The conditional compilation for the iOS and watchOS targets is required in order to allow both targets to dearchive the serialised data later, even if they have been archived by the other target.
ShoppingLocation adopts the NSCoding protocol, and inherits from NSObject.
This code crashes at the let data = … instruction with EXC_BAD_ACCESS (code=1, address=0x0).
I know that the error probably indicates that a non-existent object is referred. However, the variable buyLocations is existent, and I can print the value in the debugger, including all values of the objects in the set.
The stack trace is:
The stack trace indicates that the archiver starts to archive the NSSet, and tries to archive one of the elements of the set, but setObjectForKey in the internal mutable dictionary fails.
What could be the reason?
EDIT:
During further testing I realised that the crash happens always when at least 2 threads of the app are active.
Particularly, I found a situation where one thread crashed (red in Xcode) at an instruction different from the one mentioned above:
let dataBlob = NSKeyedArchiver.archivedData(withRootObject: shoppingItem.buyLocations)
and the other thread stopped at the instruction mentioned above (green in Xcode):
let data = NSKeyedArchiver.archivedData(withRootObject: buyLocations)
Might it be that NSKeyedArchiver is not thread-safe?
My problem is indeed, as suspected, caused by unsynchronised accesses by multiple threads:
An NSArchiver walks through an object graph, starting at the root object, and archives on the way every object it encounters.
In order to create a correct archive, it is therefore required that the object graph is not mutated until the archiver terminates.
In a single-threaded application, this is guaranteed automatically.
In a multi-threaded application where more than 1 thread can mutate the object graph, the programmer is responsible to ensure this, because the archiver has no way to prevent other threads to mutate the root object. (If, e.g., the archiver would first make a deep copy of the object graph, and then archive the copy, the object graph could be mutated during the deep copy).
It is therefore required to serialise all get and set accesses to the object graph, e.g. by execute them in a serial access queue.
I get this error message
The connection to service named com.apple.gamed was interrupted, but
the message was sent over an additional proxy and therefore this proxy
has become invalid.
sometimes when calling
loadMatchesWithCompletionHandler:^(NSArray *matches, NSError *error)
What does it mean?
I'm on iOS 9.3.2
This is the worst possible answer, but it's my own experience with loading matches, I'm sorry to say: sometimes it works, sometimes it doesn't. I've received this error message before, and then had it go away after no code changes at all. Just try again.
Ok now I have more findings. Forget my comment to the other answer.
In my case I got the message when I did not use the #escaping keyword on a closure parameter of a function (using Swift 3 where closures are by default non-escaping). This function was called with a closure that did not refer to self (because it was not needed). However, that function called another function, forwarding the closure.
So in the end my closure ended up without a reference.
I recommend you keep a copy of your block that you use as an argument to loadMatchesWithCompletionHandler. This way the block is not released prematurely.
This also explains why the error occurs just sometimes and not always. It's typical for memory release issues.
I'm doing some work with libevent, version 2.0.22, and I'm struggling with dealing with bufferevent_free and making sure sockets close at the right time. This is within an iOS app built with Xcode 6.4, running on iOS 8.4.
Each socket is managed by a struct bufferevent, and I also have a data structure which keeps track of application state for that socket:
bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_socket_connect_hostname(bev, dns_base, AF_UNSPEC, host, port_number);
struct stream_data *data = malloc(sizeof(struct stream_data));
/* initialize stream data here */
bufferevent_setcb(bev, read_cb, write_cb, event_cb, data);
In a callback from some other buffer socket, I decide I don't need the buffer I just tried to open. This happens before I get the connected callback on the bev in question. Because I created it with BEV_OPT_CLOSE_ON_FREE, I just free it. Then I delete the data structure I'm using. Looks like this:
bufferevent_free(bev);
free(stream_data); // the data corresponding to that bev
In this case, though, the socket actually finished connecting in the meantime. So my event callback fires:
void event_cb(struct bufferevent *bev, short what, void *ctx)
{
struct stream_data *data = ctx;
// data now points to already freed memory
}
And now I've got a pointer to already freed memory. I've confirmed with debugger breakpoints, NSLog, etc that the event callback is firing after the free above.
Is this expected behavior? If so, how can I ever tell that a bufferevent I freed is well and truly gone, making it safe to remove my own data structures?
Yes, this is expected libevent behavior: after bufferevent_free() it still may invoke your callbacks. From libevent book:
Bufferevents are internally reference-counted, so if the bufferevent has pending deferred callbacks when you free it, it won’t be deleted until the callbacks are done.
The easiest solutions is to remove all the callbacks before freeing the bufferevent object:
bufferevent_setcb(bev, NULL, NULL, NULL, NULL);
bufferevent_free(bev);
I'm using PLCrashReporter in my iOS project and I'm curious, is it possible to use Core Foundation code in my custom crash callback. The thing, that handle my needs is CFPreferences.Here is part of code, that I create:
void LMCrashCallback(siginfo_t* info, ucontext_t* uap, void* context) {
CFStringRef networkStatusOnCrash;
networkStatusOnCrash = (CFStringRef)CFPreferencesCopyAppValue(networkStatusKey, kCFPreferencesCurrentApplication);
CFStringRef additionalInfo = CFStringCreateWithFormat(
NULL, NULL, CFSTR( "Additional Crash Properties:[Internet: %#]", networkStatusOnCrash);
CFPreferencesSetAppValue(additionalInfoKey, additionalInfo,
kCFPreferencesCurrentApplication);
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);
}
My target is to collect some system information, just in time when app crashed, e.g Internet connection type.
I know it is not good idea to create own crash callback due to async-safe functions, but this can help.
Also as other option: Is there a way to extend somehow PLCrashReportSystemInfo class?
This is very dangerous. In particular the call to CFStringCreateWithFormat allocates memory. Allocating memory in the middle of a crash handler can lead to battery-draining deadlock (yep; had that bug…) For example, if you were in the middle of free() (which is not an uncommon place to crash), you may already be holding a spinlock on the heap. When you call malloc to get some memory, you may spinlock the heap again and deadlock in a tight-loop. The heap needs to be locked so often and for such short periods of time that it doesn't use a blocking lock. It does the equivalent of while (locked) {}.
You seem to just be reading a preference and copying it to another preference. There's no reason to do that inside a crash handler. Just check hasPendingCrashReport during startup (which I assume you're doing already), and read the key then. It's not clear what networkStatusKey is, but it should still be there when you start up again.
If for any reason it's modified very early (before you call hasPendingCrashReport), you can grab it in main() before launching the app. Or you can grab it in a +load method, which is called even earlier.
NB: The entire code base for this project is so large that posting any meaningful amount wold render this question too localised, I have tried to distil any code down to the bare-essentials. I'm not expecting anyone to solve my problems directly but I will up vote those answers I find helpful or intriguing.
This project uses a modified version of AudioStreamer to playback audio files that are saved to locally to the device (iPhone).
The stream is set up and scheduled on the current loop using this code (unaltered from the standard AudioStreamer project as far as I know):
CFStreamClientContext context = {0, self, NULL, NULL, NULL};
CFReadStreamSetClient(
stream,
kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
ASReadStreamCallBack,
&context);
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);
The ASReadStreamCallBack calls:
- (void)handleReadFromStream:(CFReadStreamRef)aStream
eventType:(CFStreamEventType)eventType
On the AudioStreamer object, this all works fine until the stream is read using this code:
BOOL hasBytes = NO; //Added for debugging
hasBytes = CFReadStreamHasBytesAvailable(stream);
length = CFReadStreamRead(stream, bytes, kAQDefaultBufSize);
hasBytes is YES but when CFReadStreamRead is called execution stops, the App does not crash it just stops exciting, any break points below the CFReadStreamRead call are not hit and ASReadStreamCallBack is not called again.
I am at a loss to what might cause this, my best guess is the thread is being terminated? But the hows and whys is why I'm asking SO.
Has anyone seen this behaviour before? How can I track it down and ideas on how I might solve it will be very much welcome!
Additional Info Requested via Comments
This is 100% repeatable
CFReadStreamHasBytesAvailable was added by me for debugging but removing it has no effect
First, I assume that CFReadStreamScheduleWithRunLoop() is running on the same thread as CFReadStreamRead()?
Is this thread processing its runloop? Failure to do this is my main suspicion. Do you have a call like CFRunLoopRun() or equivalent on this thread?
Typically there is no reason to spawn a separate thread for reading streams asynchronously, so I'm a little confused about your threading design. Is there really a background thread involved here? Also, typically CFReadStreamRead() would be in your client callback (when you receive the kCFStreamEventHasBytesAvailable event (which it appears to be in the linked code), but you're suggesting ASReadStreamCallBack is never called. How have you modified AudioStreamer?
It is possible that the stream pointer is just corrupt in some way. CFReadStreamRead should certainly not block if bytes are available (it certainly would never block for more than a few milliseconds for local files). Can you provide the code you use to create the stream?
Alternatively, CFReadStreams send messages asynchronously but it is possible (but not likely) that it's blocking because the runloop isn't being processed.
If you prefer, I've uploaded my AudioPlayer inspired by Matt's AudioStreamer hosted at https://code.google.com/p/audjustable/. It supports local files (as well as HTTP). I think it does what you wanted (stream files from more than just HTTP).