I check for the variable's existence, but still get the exc_bad_access! How is this possible? I have tried Zombies, Instruments, and the console, to no avail, and about all else my limited knowledge can muster. Any other suggestions??
if (intDealerCard) {
NSLog(#"%i", intDealerCard); // EXC_BAD_ACCESS - code 2 occurs here
}
Perhaps some things of note...
The code is being executed over 1000 times, as it is a simulation, and it will execute just fine numerous times. I'd like to think there is a problem with my code, but the verified check throws me off. Also, there are two different spots where this may happen, mostly in one of the spots, but occasionally in the other, but still, I'm not sure that is relevant seeing how the check is verified?!
EXC_BAD_ACCESS occurs when memory hasn't been managed properly. Many times an app will crash with this error message in one place, however the memory management error has occurred elsewhere in the logic -- perhaps an unexpected dealloc is occurring on the instance of the class contains the member that is crashing, or if the app is running simulations concurrently, a race condition between a shared resource, etc. In short, the few lines of code in your question are likely not the culprit, just a symptom of a more systemic error with how that variable's memory is being managed.
As you've run Zombies and nothing has shaken loose, consider running the static analyzer (Product > Analyze) -- this class of error can sometimes be detected via static analysis and present one or more code flows that could resulting early release, unexpected deallocation, etc. These analysis errors and compiler warnings should be repaired and then you can retest using NSZombies if the error persists.
Related
I'm using Firebase Crashlytics to get crash reports from my iOS app and I get some crashes that I don't understand with a <compiler-generated> error message. I don't understand what causes this kind of crash.
When I look at the stack trace I get one or several lines with the compiler-generated error message too.
I've been searching but can't find the reason or reasons why this kind of crash happens. In this particular example here is the function where the crash happens (it doesn't say which line). From what I see I can only guess that it has to do with the fact that I'm using an index from an array on another array so it might be out of range... but I don't really know.
It makes it really hard to fix crashes cause I just can assume what might be wrong in my code. Plus if the problem is actually the range out of index thing, shouldn't it report the line where the crashes occurs ? I'm really trying to understand the compiler-generated thing more than solving this actual crash :)
Compiler-generated means code injected into final binary by swift compiler. This might be unrolled inline-type library function, optimisation things, etc. The crash-log on your screenshot just shows the top call of the failed execution stack, and in majority of cases it is not your code line (while there is the reason) but some standard function call (from library or autogenerated). So you have to investigate not just one first line, but complete back trace of crashed stack.
I am trying to reproduce such crash(es):
There's Manual Reference Counting in my project. Also, there's a lot of multi-threading.
Some of the properties are not thread-safe. :(
I have just one assumption about the cause of this crash: some object is overreleased (?).
I've added automated UI tests (Appium), but they haven't helped yet.
Also, I've profiled for Zombies - everything seems ok.
Also, I've tried Xcode's Static Analyzer ( Product -> Analyze ), there're a lot of warnings, but none of them seems to be a cause of such crash (I've looked at the warning Incorrect decrement of reference count not owned at this point).
I created a test project with MRC, and added such code:
- (void)testAssumptions {
//#autoreleasepool
{
[self overReleaseNilValue];
[self overReleaseNotNilValue];
}
}
- (void)overReleaseNilValue {
NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:42];
[path release];
[path release];
}
- (void)overReleaseNotNilValue {
NSIndexPath* path = nil;
[path release];
[path release];
}
Releasing an object twice doesn't crash neither with autorelease pool enabled nor without a pool.
So my questions are:
1. What can be another reason of such crash except of releasing already released object?
2. Are there ways to increase a probability of reproducing such crash? E.g. some env. variable which reduces some autorelease pool tolerance to unsafe code? Or some additional autorelease pool?
3. Why doesn't my test project code crash?
Any comments are highly appreciated.
Incorrect decrement of reference count not owned at this point
This would definitely the be warning to explore. It's almost certainly pointing you to at least one error.
Your test project is not actually testing anything (they're also named backwards I believe). There is no promise that over-releasing a value will cause a crash. overReleaseNotNilValue is well-defined behavior, and is absolutely will not crash (sending a message to nil does nothing). overReleaseNilValue is undefined behavior. I haven't dug into it, but I would expect NSIndexPath to be implemented with tagged pointers, which will not crash if you over-release them.
Undefined is undefined. It doesn't mean crash. Over-releasing a value can do anything. If you're lucky, it'll crash....
Also, there's a lot of multi-threading. Some of the properties are not thread-safe.
I would expect this to be at the heart of your problem if it's intermittent. I've worked on such projects. The solution is to fix the problems. You will not know which specific problem is the cause of your crashes. You may never know. You still must fix them all. It will take some time, but you have to make the code thread-safe, or its behavior is undefined.
As to debugging, you will want to do the following, in order:
Turn on the Runtime Sanitization options (under the Scheme editor, Run, Diagnostics). You especially will want the Thread Sanitizer for this.
Clear all Static Analyzer warnings. If any of them say your memory management is wrong, you have to clear those. The system is literally telling you where the problems are. Don't ignore it.
Clear all warnings. There should be zero warnings in your project. If there are lots of "false" warnings then you will never see the real warnings telling you exactly where your problems are. Eliminate all warnings.
I spent 8 months eliminating rare over-release crashes in one a well-written project written by expert developers and almost no threading. It can take a lot of time. You have to clear every problem. Just one incorrect release is enough to crash the program randomly.
I'm trying to debug an EXC_BAD_ACCESS crash using NSZombie. My app creates lots of large objects though and with NSZombie enabled they aren't getting released causing the app to crash in seconds. This means I can't even cause the EXC_BAD_ACCESS crash before the app crashes due to low memory.
Is there an alternative? Can I enable NSZombie on specific file instead of the entire project? How else could I debug this crash (I know it's caused by UIGestureRecognizer but I use them a lot so it doesn't narrow down the issue significantly).
Thanks.
Edit:
Thanks for the advice. I think I may have solved the issue and will report back after more testing.
Edit 2: Sovled the issue myself but selected the answer which seems like it would be a good solution to any similar issues in the future.
All I can think of is implementing it manually; create a proxy container that holds an object of type id and nominates that as -forwardingTargetForSelector: as well as getting it to respond to -isKindOfClass:, etc.
Disable ARC for the proxy and have it retain itself during init and check its own retainCount when nominating a forwarding target.
If the count is 1 then raise an exception or log a warning or whatever.
Have suspect classes wrap themselves in and return a proxy as the last line of their unit.
For possible bonus points, store [NSThread callStackSymbols] somewhere (probably on disk) during the proxy's unit so you can at least find out where the incorrectly managed object was created.
NSZombies was/is for apps that use their own memory management. If your app uses ARC then this won't help.
Create a new Breakpoint: All Exceptions
That should usually show you where you trigger the bad access.
Am new to the iOS development. While looking into one of the App I work on, with exception breakpoint enabled in xcode. I see so many repetitive exceptions been raised.
But till now, we never realised this, as iOS was excusing those exceptions. The main exception was happening in our service layer, where, in an XML parsing, one of the element mentioned as key was missing. since so many back end requests are fired, for every XML response, and for multiple items inside it, this exception is thrown.
Now that our app is published, will this impact the device's stability? We are planning to fix thee kind of issues. But now, Will these be logged into Apple's diagnostic information. Just curious to know these. Can someone shed some light over it?
In Objective-C, Exceptions are used to signal fatal errors, that is programmer errors and "unexpected" and unrecoverable runtime errors. In Objective-C, Exceptions are a debugging and testing aid, not a construct to control program flow or to regain control after an error.
Usually, an application in a release state shouldn't throw exceptions. If it happens anyway, the only correct course of action is to terminate the program as soon as possible. In general, the Objective-C system frameworks are not exception safe. This means, after an exception has been thrown the application's state will be corrupt. If your program continues, even worse things may happen.
There are only a few, always undocumented harmless cases where exceptions will be thrown and caught by system libraries without leaving the program in an unstable condition.
See also https://developer.apple.com/library/ios/documentation/cocoa/conceptual/Exceptions/Exceptions.html
I had a rather interesting exc_bad_access crash today. After a lot of digging, I came up with the following information (running in simulator):
If I just ran the code, the app would randomly crash at a random point while loading data into my managed object. From what I could tell, it was always crashing when I loaded data into the managed object -- not on the sections that converted from my JSON dict to data to the object actually used (from strings and NSNulls to ints/floats and nils)
Random crashes are, of course, evil, so I tried to step through the process in the debugger, but that didn't prove practical -- I was processing a LOT of objects, so stepping through them one-by-one just didn't work. So I decided to add some NSLogs to track the process and try to spot a pattern that way.
Instantly solved the crash.
Just one NSLog, anywhere in the process, prevented the crash.
I eventually tracked my way up the stack trace and found the actual issue: I was accessing the managed object in a threaded environment, but NOT from within the associated MOC's performBlockAndWait: method. At that point, the crash was incredibly obvious to me -- I'm shocked I didn't have more issues earlier. I'm willing to bet that between having a 'small' test data set of 2-3 objects and having debug code in there with NSLogs, the error was pretty effectively masked earlier... but the question remains:
Why does an NSLog prevent the app from crashing? How on earth could a piece of code without side effects change the execution of the rest of the app? This makes no sense!
Amazingly enough, this is a fairly common situation: I have seen it more than once when enabling logging in a seemingly unrelated place would instantly solve a timing issue somewhere else.
The reason for this is that NSLog, just like many other output functions, has internal synchronization. There is a mutex somewhere that protects access to the internal buffers of NSLog, either in the NSLog itself or in one of the I/O libraries that it uses. This synchronization enables callers to use NSLog from multiple threads. It is this synchronization that changes the timing of your program, affecting a race condition and ultimately solving a crash.
Why does an NSLog prevent the app from crashing? How on earth could a
piece of code without side effects change the execution of the rest of
the app? This makes no sense!
Indeed this makes a sense. Really.
A single NSLog forces to print something to your console, it takes some fraction of seconds and in between your processing on somethread gets finished and the crash (might be due to un-availability of input is) no-more.
Your error may be due to async call. Your next process starts before finishing previous one. And your next process need data from previos process. NSLog consumes some time.