My code is crashing with an EXC_BAD_ACCESS error that I don't know how to debug.
This is the code:
NSUInteger lineCount = self.lineBeginnings.count;
NSUInteger lineBeginnings[lineCount];
[self.lineBeginnings getIndexes:lineBeginnings maxCount:lineCount inIndexRange:nil];
It crashes on the last line, with EXC_BAD_ACCESS (code=2, address=0x...).
Notice two lines above, it's able to read self.lineBeginnings perfectly, but in the debugger I get:
(lldb) p [self lineBeginnings]
error: Trying to put the stack in unreadable memory at: 0x7fff5d15e310.
(lldb) p _lineBeginnings
(NSMutableIndexSet *) $1 = 0x0000610000059b90
(lldb) po _lineBeginnings
[no Objective-C description available]
Also lineBeginnings doesn't show up properly in the GUI scope browser (all other variables do) and trying to "View Memory of lineBeginnings" gives a completely empty memory view.
The lineBeginnings variable is stored as a strong #property, it's a mutable index set created in the app delegate's init method and never removed while the app is running. There is a background operation queue that writes to it, but it switches to the main thread for all modifications using dispatch_sync(dispatch_get_main_queue()).
I'm not sure how to debug this further? It's hard to reproduce, I have to resize the window for up to a minute (which causes the lineBeginnings variable to be re-created on a background queue, a process that takes ~5 minutes when given 180MB of data), in order to make this crash occur.
It looks like a buffer overrun or something to me? How do I track it down?
The source code for the file is here: https://gist.github.com/abhibeckert/7128740 (the crash is on line 254).
In 180 MB there are probably millions of line beginnings? So you are allocating an array of millions of eight byte words on the stack. A thread's stack usually is not that large.
You should allocate the array on the heap, using malloc.
Your problem is called a stack overflow. Sounds familiar?
I had the same problem, after spending 2 days i found that my getter is calling several time because i was using self in getter.
if(! _openSectionIndexes) _openSectionIndexes = [NSMutableArray new];
if( _openSectionIndexes.count != _requests.count)
{
for (int i =0; i < _requests.count; i++)
{
[self.openSectionIndexes addObject: #(NO)];// here was the problem, replaced it with _openSectionIndexes
}
}
return _openSectionIndexes;
Related
I am having problem with NSOperationQueue, if I am adding the same operation for 200 times method is behaving as expected.
But if I increase the for loop to 500 times, parameter are becoming empty when queue will start executing the task. Below is the code snippet.
- (void)someMethod:(char *)param1 {
NSBlockOperation *theOp = [NSBlockOperation blockOperationWithBlock: ^{
// use this paramter and do something
}];
[[MyQueueService sharedMyQueueService] operationQueue] addOperation:theOp];
}
This is how I am invoking the above method
for (int index = 1; index < 500; index++) {
MyClass *classInstance = [[MyClass alloc] init];
NSString *parm1 = [NSString stringWithFormat:#"%d", index];
[classInstance someMethod:(char *)[string cStringUsingEncoding:NSUTF8StringEncoding]];
}
Here is becoming empty i.e "", if i run the same method for 500 time, due to this I am unable to perform other operation. Please help me regarding this.
The problem is not with NSOperationQueue. The issue is the use of char *. As the documentation for cStringUsingEncoding says:
The returned C string is guaranteed to be valid only until either the receiver is freed, or until the current memory is emptied, whichever occurs first. You should copy the C string or use getCString:maxLength:encoding: if it needs to store the C string beyond this time.
Bottom line, simple C pointers like char * do not participate in (automatic) reference counting. Your code is using dangling pointers to unmanaged buffer pointers. This is exceedingly dangerous and when not done properly (as in this case), will lead to undefined behavior. The resulting behavior is dictated whether the memory in question happened to be reused for other purposes in the intervening time, which can lead to unpredictable behavior that changes based upon completely unrelated factors (e.g. the loop count or whatever).
You should try running your app with the "address sanitizer" turned on (found in the scheme settings under the "run" settings, on the diagnostics tab) and it will likely report some of these issues. E.g. when I ran your code with address sanitizer, it reported:
==15249==ERROR: AddressSanitizer: heap-use-after-free on address 0x60300003a458 at pc 0x00010ba3bde6 bp 0x70000e837880 sp 0x70000e837028
For more information, see Address Sanitizer documentation or its introductory video.
The easiest solution is going to be to eliminate the char * and instead use the int index value or use an object, such as NSString *.
I have a function that constructs an NSMutableDictionary using bk_apply, a method provided by the third-party block utility library BlocksKit. The function's test suite usually passes just fine, but once every couple runs it crashes.
NSMutableDictionary *result = [[NSMutableDictionary alloc] init];
[inputSet bk_apply:^(NSString *property) {
NSString *localValueName = propertyToLocalName[property];
NSObject *localValue = [self valueForKey:localValueName];
result[property] = localValue ?: defaults[property]; // Crash
// Convert all dates in result to ISO 8601 strings
if ([result[property] isKindOfClass:[NSDate class]]) { // Crash
result[property] = ((NSDate *)result[property]).ISODateString; // Crash
}
}];
The crash always happens on a line where result is referenced, but it's not the same line every time.
Examining the contents of result in the debugger, I've seen very strange values like
po result
{
val1 = "Some reasonable value";
val2 = "Also reasonable value";
(null) = (null);
}
It's impossible for an NSDictionary to have null keys or values, so clearly some invariant is being violated.
What is causing this crash and how do I fix it?
From the BlocksKit documentation for bk_apply:
Enumeration will occur on appropriate background queues. This will
have a noticeable speed increase, especially on dual-core devices, but
you must be aware of the thread safety of the objects you message
from within the block.
The code above is highly unsafe with respect to threading, because it reads from and writes to a mutable variable on multiple threads.
The intermittent nature of the crash comes from the fact that the thread scheduler is non-deterministic. The crash won't happen when several threads accessing shared memory happen to have their execution scheduled in sequence rather than in parallel. It is therefore possible to "get lucky" some or even most of the time, but the code is still wrong.
The debugger printout is a good example of the danger. The thread that's paused is most likely reading from result while another thread performs an insertion.
NSMutableDictionary insertions are likely not atomic; example steps might be,
allocate memory for the new entry
copy the entry's key into the memory
copy the entry's value into the memory
If you read the dictionary from another thread between steps 1 and 2, you will see an entry for which memory has been allocated, but the memory contains no values.
The simplest fix is to switch to bk_each. bk_each does the same thing as bk_apply but it's implemented in a way that guarantees sequential execution.
The following line causes memory growth (no releases, only one malloc line in instruments) when testing with mark generation feature of allocations instrument
- (instancetype)initWithTitle:(NSString *)title andImageNamed:(NSString *)imageName andButtonProperties:(NOZSKButtonNodeProperties *)buttonProperties
{
...
textNode.text = buttonProperties.buttonTitleIsUppercase ?
[title uppercaseStringWithLocale:[NSLocale currentLocale] ] : title;
...
}
Here is the code that calls it
NOZSKButtonNodeProperties *props = [self getThreeButtonProps];
...
props.buttonTitleIsUppercase = YES;
...
// this initializer is calling the above initializer by passing nil for imageName arg
NOZSKButtonNode *btn = [[NOZSKButtonNode alloc] initWithTitle:#"Play Again" andButtonProperties:props];
-uppercaseStringWithLocale: makes an upper-case copy of the title string. This requires allocation. And although you didn't show this, I assume textNode both retains its text property and has a wider scope than the -initWithTitle:andImageNamed:andButtonProperties: method and therefore continues to live afterwards.
Without more complete code it is not possible to be sure, but here is a guess in case it helps.
It sounds like you might be chasing a ghost. Are you seeing increasing memory due to this code across different iterations of your run loop?
Explanation: Even with ARC some memory is placed in the "autorelease pool" rather than being immediately deallocated when no longer required. This is an unfortunate legacy of MRC. ARC is able to avoid some uses of the autorelease pool and deallocate memory quicker, but not all uses.
The autorelease pool is typically emptied once per iteration of your main run loop. If you allocate and release a lot of memory in response to a single event, say in a long loop, it can be worth while wrapping the offending code in an #autorelease { ... } block which creates, and empties on exit, a local autorelease pool. This helps keep the peak memory usage down - it doesn't deallocate any more memory overall, it just does it cleanup sooner.
When you altered your code and saw an apparent improvement you may just have reorganised your code in a way more amenable to ARC's optimisations which reduce use of the autorelease pool, and so memory is deallocated sooner.
You only need to be concerned if (a) memory is increasing across multiple events or (b) you are hitting a too high peak memory use. Under ARC (a) should be rare, while (b) requires locating the source and wrapping it in an #autorelease { ... } block.
HTH
textNode.text = buttonProperties.buttonTitleIsUppercase ?
[title uppercaseStringWithLocale:[NSLocale currentLocale] ] : title;
When you write [title uppercaseStringWithLocale:], this method has to create a new instance in order to change the given string to upper case. This is going to increase the memory usage of your program because this new string has to be allocated.
Also, it would have helped to know whether or not you are using ARC, because I don't think this should be an issue with ARC.
I have the following method:
+ (NSString*) getMD5HashFromFile:(NSString*)filePath {
CFStringRef md5hash = FileMD5HashCreateWithPath((CFStringRef)filePath, FileHashDefaultChunkSizeForReadingData);
NSString *hashStr = (NSString*)md5hash;
CFRelease(md5hash);
return hashStr;
}
I was getting random crashes on the Simulator, about 1 in 20-30 executions. The fact that this wasn't consistent didn't help me dig deeper before.
Now that I see the code again, it seems obvious that md5hash gets released before being returned, which means the returned object is invalidated. The returned value is used in another method in a consistent way that crashes sometimes, but not always. My question is why this only happens rarely and not always.
Does it have something to do with the mix of Obj-C and C code and the way autorelease pools work?
Note: The bug seems to be fixed by using NSString *hashStr = [NSString stringWithString:(NSString*)md5hash], which makes total sense to me.
Just because a piece of memory is released and deallocated doesn't mean that it's immediately returned to the OS. Your application can hold onto it for an arbitrary period of time based on numerous factors and at several layers. The OS has more important things to do sometimes than reclaim every piece of memory you let go of and might ask for again in half a second. Accessing memory that you've called free() on, but technically own, does not generate a signal. This is why MallocScribble exists. It overwrites memory that you free with trash (0x55) so that it's more obvious when you use freed memory.
Try the following:
char *foo = malloc(100);
strcpy(foo, "stuff");
free(foo);
printf("%s", foo);
Most of the time that'll work fine, despite being completely wrong. Now, edit your Scheme>Diagnostics and Enable Scribble. Re-run and you'll see a bunch of "U" (0x55) indicating that you're reading nonsense. But it still won't crash.
You may be interested in Matt Gallagher's A look at how malloc works on the Mac for a bit more on the topic.
CFRelease argument must not be NULL.
If CFRelease argument is NULL, this will cause a runtime error and
your application will crash
if(md5hash)
CFRelease(md5hash);
+(NSString*) getMD5HashFromFile:(NSString*)filePath {
CFStringRef md5hash = FileMD5HashCreateWithPath((CFStringRef)filePath, FileHashDefaultChunkSizeForReadingData);
NSString *hashStr = [(NSString*)md5hash copy];
CFRelease(md5hash);
return [hashStr autorelease];
}
make sure to retain the returned value in the caller if you need to hang on to it for any length of time.
I am having a weird problem. I am using a method from Apple's private frameworks in my application. When I call it for the first time, it works. When I call it for the second time immediately without anything in between, it crashes. However, if I put NSLog between the two calls, it works wonderfully. So I try removing NSLog and puting for-loops, sleep(), printf("..."), and fprintf(stderr, "...") between them to emulate NSLog, but it doesn't help. I am wondering how the method knows that I use NSLog? In other words, what does NSLog actually do to affect the behaviors of the method?
Thank you very much!
EDIT:
I seem to solve this problem. I will share my solution here and hope it may be useful to some people.
I am creating a multitouch-related application using MultitouchSupport.framework. I copied code from http://aladino.dmi.unict.it/?a=multitouch and added a CFRelease at the end of the loop. So, basically, my main method looks like this :
int main(void) {
int i;
NSMutableArray* deviceList = (NSMutableArray*)MTDeviceCreateList(); //grab our device list
for(i = 0; i<[deviceList count]; i++) { //iterate available devices
MTRegisterContactFrameCallback([deviceList objectAtIndex:i], touchCallback); //assign callback for device
MTDeviceStart([deviceList objectAtIndex:i], 0); //start sending events
}
CFRelease((CFMutableArrayRef)deviceList);
printf("Ctrl-C to abort\n");
sleep(-1);
return 0;
}
After running for a while, it will show "Program received signal: “EXC_BAD_ACCESS”."
And here is the stack trace:
#0 0x7fff8795496e in ParsedMultitouchFrameRepInitialize
#1 0x7fff879565b1 in mt_HandleMultitouchFrame
#2 0x7fff87955a03 in mt_DequeueDataFromDriver
#3 0x7fff87955b29 in mt_DequeueMultitouchDataFromDriverThreadEntry
#4 0x7fff831b3456 in _pthread_start
#5 0x7fff831b3309 in thread_start
However, if I put NSLog below MTDeviceStart, it will not crash.
The reason I added CFRelease((CFMutableArrayRef)deviceList) to the original code is that I think objects that are created from functions named *Create* or *Copy* should be released by ourselves. But it turns out that if I remove it like the original code does, it will not crash, even without using NSLog.
So, maybe it's because I release deviceList too early? But if that's so, why does NSLog seem to be able to prevent the crash?
Something similar to this:
static inline void NSLogMessageString(NSString *string){
NSString *date=[[NSDate date]
descriptionWithCalendarFormat:#"%Y-%m-%d %H:%M:%S.%F"
timeZone:nil locale:nil];
NSString *process=[[NSProcessInfo processInfo] processName];
NSLogFormat(#"%# %#[%d:%lx] %#",date,process,NSPlatformProcessID(),NSPlatformThreadID(),string);
}
void NSLogv(NSString *format,va_list arguments) {
NSString *string=NSStringNewWithFormat(format,nil,arguments,NULL);
NSLogMessageString(string);
[string release];
}
void NSLog(NSString *format,...) {
va_list arguments;
va_start(arguments,format);
NSLogv(format,arguments);
}
Thanks for asking this question lol, I wanted to rewrite it so I could add debugging variables, meaning I could turn all NSLogging calls off when needed..
It takes a long time. I'm not sure why. It prints the date/time, process name, process ID, thread ID, and (finally) the string you asked for. I think it also sends the log message to syslogd (either Xcode or iPCU's console shows multiline NSLogs as a single entry; I forget which); the IPC there might be significant.
Try using syslog() (#import <syslog.h> and then syslog(LOG_INFO, "Hello there!");, if it works but you get no output, try changing the priority (see man 3 syslog).
NSLog can affect issues like the one you are running into because it affects the order that threads execute because when you call NSLog in a background thread, it has to gain exclusive access to stdout. printf debugging tricky problems with threads often leads to "heisenbugs" for this reason (i.e. they change behavior when you try to examine them).
It could be a problem with memory management: an extraneous release perhaps. If you post the traceback, it might be some help in tracking down the issue. (As it turns out, someone on Twitter I follow mentioned something like this last night).