NSCF String Leak without use of a string - objective-c

I am working on mounting some network shares in a program. The URL and username are saved in a dictionary with the password coming in from the keychain which is changed to a NSString, used and released. I have traced the only memory leak to the actual mounting of the server:
error = FSMountServerVolumeSync((CFURLRef) [objects objectForKey:#"url"], NULL, (CFStringRef) [objects objectForKey:#"username"],(CFStringRef) password, NULL, 0);
The object for "url" is a NSURL and the username is a NSString.
In the leak performance tool it says:
Leaked Object: NSCFString responsable library: smb, responsable frame: smb_url_to_dictionary
If I look at the history it is a CFString malloc for 32 bytes and then goes through 8 iterations of CFRetain-CFRelease from smb and NetFS libraries which results in a +1 retain count.
Being new to Objective-C and memory management I thought I was doing everything correct I have released everything alloc'd and really not sure how this leak is occurring.
Is there something with the FSMountServerVolumeSync that is tricky thats causing this leak?
Is there any way to look during runtime at the memory location to determine what is there to see what the leak is from?
Also what does the NSCF stand for?
Thanks for the help

Related

Releasing an autoreleased string object doesnt crash

I have this basic question where when we try to allocate memory to a string by using alloc init and add it to autorelease pool, and then try to release it, it doesn't crash.
NSString *value = [[[NSString alloc] initWithString:#"Hello"] autorelease];
[value release];
If I do the same thing for a array, it crashes.
I just want to know how string is different from array since both inherit from NSObject.
Do you mean it doesn't crash right away?
I.e. in the debugger after stepping over the release line?
The Autorelease-Pool will not have triggered at that point so the auto-release operation is still outstanding.
Either way - As always with memory errors they might not crash
instantly,
on your machine/operating system,
with this specific built,
with your current build settings,
...
or even at all.
It's a programming error nevertheless.
It is not guaranteed that the program crashes. Unfortunally there are several errors that does not cause a crash (immediately).
However there is an optimization for string literals. They live eternally regardless of the way they are created, retained or released. -initWithString: can be smart enough not to return a new instance of NSString.
First, undefined behavior is undefined -- it is not guaranteed to crash or do any other specific thing. Over-release is undefined behavior.
Second, what is happening here is that string literals evaluate to a pointer to a statically-allocated string object which lives for the lifetime of the program. It is not dynamically-allocated, and thus is not subject to memory management. retain, release, etc. have no effect on it. [[NSString alloc] initWithString:...] (as well as [... copy]) on an immutable string object simply retains and returns its argument directly, since there is no need to create a new object. So [[NSString alloc] initWithString:#"Hello"] is the same as #"Hello".

CGPDFDocumentCreateWithURL ARC Memory Leak

I want to render PDFs on iOS and I'm getting a memory leak when I call CGPDFDocumentCreateWithURL(). I know this issue has been discussed before, but I don't know whether my conditions are different because I'm using ARC.
I've extracted and simplified the problem by running the following code on my viewDidLoad:
// Bridge resourceRef to ARC with no ownership change (still owned by ARC)
CFURLRef resourceRef = (__bridge CFURLRef) [NSURL fileURLWithPath:htmlPath];
CGPDFDocumentRef pdf;
pdf = CGPDFDocumentCreateWithURL(resourceRef);
CGPDFDocumentRelease(pdf);
// Do not need to release resourceRef because ARC will release it
Instruments tells me that the Leaked Object is a Malloc 48 Bytes, responsible by CoreGraphics. And the stacktrace has CGPDFDocumentCreateWithURL in it. Leaking means that there is object out there without an owner.
I've create a git repo with a replication of the problem:
https://github.com/indika/PDFLeaks
Any ideas. Would appreciate any help or 'pointers'.
resourceRef is going to be overreleased. Take a look at what you are doing.
1) Bridge resourceRef to ARC with no ownership change (still owned by ARC)
2) CFRelease on resourceRef
3) ARC also releases resourceRef
You don't need step 2
This is not a memory leak though, but an overrelease.
I made many mistakes, especially with double releasing the document reference. However, that wasn't the real critter in my situation.
I was loading a broken PDF! I was using pdftk to slice and merge pdf documents, and I was breaking the indexes. So remember, after merging a PDF with pdftk, repair the file with:
pdftk original output destination

Understanding Instruments and Memory Management

I'm in need of understanding how memory is managed in objective C.
I know the basics, if you create it and own it, you must release it yourself.
However, when it gets to code such as:
self.storeDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
Do I own this? Must I release this memory?
self.storeDict = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath2];
//73.3% leak
totalCharacters = [storeDict count];
tagCounter = 1;
dictKeyArray = [[storeDict allKeys] mutableCopy];
//13.3% leak
When Instruments puts a bunch of percentages next to the highlighted leaks, what does that tell me? Does it tell me the size of the leak relative to the total amount of memory leaked?
And one last thing.. Is it normal for the amount of allocated memory to continuously rise? Or should it stabilize somewhere?
Thanks for all the help! Everything is greatly appreciated!
In most cases, you only own objects returned by methods whose names begin with "alloc", "new", "copy", or "mutableCopy". Of course, you also own anything to which you send -retain. Exceptions to these rules should be called out in the documentation for the non-conforming methods.
See https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmRules.html#//apple_ref/doc/uid/20000994-SW1
Instruments attributes a leak to the line where the object was created. However, that's not necessarily the code which leaked the object. If the pointer to the object was passed to some other code and that code did not balance its retains and releases, then that code is responsible for the leak. Instruments can show you the history of retains and releases for a specific object, and you'll have to review those to see which code is not discharging its ownership responsibilities properly.
Also, if an object is owned by another object and it's really that second object that was leaked, then everything it owned will have leaked "transitively" as it were. So, look for higher-level objects which have leaked before trying to track down low-level objects which have leaked. Often, it is the objects which have leaked fewer instances which are the root of a graph of leaked objects.
Whether it is normal for memory to keep rising or to stabilize, that depends a little. Usually, memory usage should stabilize. However, if your app really is doing more and more, then it may be normal for its memory usage to keep increasing. For example, if an app is receiving data over the network and accumulating results as it does so, then its memory usage would likely rise as more data arrives. But if it doesn't stop at some reasonable point, that's a problem. On an iOS device, the system will eventually kill it.

XCode/Instruments not showing memory leaks

I'm following the Stanford iOS development lectures and I have a Calculator brain class which has been alloc init in a controller but I haven't released it in the dealloc.
- (CalculatorBrain *)brain
{
if (!brain)
brain = [[CalculatorBrain alloc] init];
return brain;
}
I ran from XCode -> Run with Performance Tool and the app started and no leaks appeared, I then clicked the home button in the iOS Simulator and nothing, I then double clicked the home button and closed the app and still nothing.
I also did Build & Analyse and it didnt spot anything
Could you let me know why its not picking it up?
It appears as if there is no detectable leak. Look at this line:
brain = [[CalculatorBrain alloc] init];
As long as brain points to an object, that object won't be considered a "memory leak". If at some point you do this,
brain = nil;
Then the leak will register. Deallocating the container object will also achieve this, but are you sure it's being deallocated? (It won't be deallocated when your program exits, for example.)
The problem: Leak detectors cannot detect all memory leaks -- this is a mathematically proven fact. Most detectors only detect unreachable objects, and many leak detectors are especially susceptible to false negatives -- in C it is hard to tell the difference at runtime between a pointer and an integer.
Edit: It sounds like your application only ever creates one instance of the controller, which only creates one instance of CalculatorBrain. If you think about what a memory leak really is, you can define it as unused memory that your program does not release back to the operating system.
While the program is running, CalculatorBrain is always in use and therefore it is not a leak.
When the program exits, the operating system automatically reclaims all memory used by your process, therefore there cannot be any memory leaks after a program exits.
If you want to create a leak to see what it looks like, you could create a new CalculatorBrain multiple times while your program is running, but forget to release the unused versions. In this scenario, as your program runs, more and more instances of CalculatorBrain would accumulate. On iOS and other embedded systems, this will generally crash your program. On a modern 64 bit computer it will gradually fill up the available swap space until you run out of swap, address space, or some other resource -- causing the program to crash or making the system very unresponsive.
Standard practice is to not care about deallocating objects which are supposed to exist for the entire program's run.
The analyzer cannot find all memory leaks. As far as it is concerned, storing the instance into the ivar doesn't leak it from that method, and then in dealloc it doesn't realize that the ivar should be released. XCode 4 may have improved in this respect, I don't recall (I still use XCode 3 myself).
As for the performance tool, remember that an object won't be considered leaked until nothing holds a reference to it anymore. So even though your controller doesn't deallocate the brain, the brain won't be considered leaked until the controller is deallocated (or receives a brain transplant). Also, note that on *nix-like systems, memory allocations are automatically cleaned up on process exit. So it isn't really a leak if you allocate memory for objects that should exist for the lifetime of your process (e.g. the app delegate and anything it permanently holds on to) and rely on this behavior to free it on process exit.
Well... it's true that leaks can't detect all memory leaks, but let's say that you are doing this:
myIvarBrain=[self brain];
If you are giving it to an iVar (released in the dealloc of your class, and without accessors), actually there is no leak at all. The returned RC is one and it will be one since the deallocation of your class. If you don't release it in the dealloc, you should wait a dealloc of your class to see a memory leak.
Does make sense?

Objective-C: Is there any way to find out what kind of object resides at a particular memory address?

Coming from Java and Python, I am not so well versed in memory management, but is there any way to find out what kind of object resides at a particular memory address?
I am asking because my application terminated with a cryptic message that reads:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSDecimalNumber encodedURLParameterString]: unrecognized selector sent to instance 0x164840'
and would like to get some clues as to what is going wrong.
And if that is not possible, some debugging techniques for such error messages would be greatly appreciated.
Thanks in advance!!
EDIT: Follow Up Concern (MOVED HERE)
After some investigation of the framework that I have been using, I came across something that I don't really understand.
If I have a method
- (void) myMethod:(NSString *)string {
[Object anothermethodWithString:string];
}
and I call
[Object myMethod:#"this is a string"];
Do I need to do something like
NSString *string2 = [[NSString alloc] initWithFormat:#"%#", string];
[Object anothermethodWithString:string2];
[string2 release];
instead of the way I had myMethod before? It seems like the string I passed through the parameter of my method got released somewhere, and doing that solves my problem. I guess I don't really understand what exactly #"string" does in terms of memory. Is it like an auto-released NSString?
well, from the error, the object type at that memory address is NSDecimalNumber. You got an error because you called encodedURLParameterString on a NSDecimalNumber which does not have a method with that name.
In gdb you could type
po <address>
to find out the object's description if it's really an Objective-C object.
But in your case it sounds more like you're sending message to an already deallocated object, which will give wrong result on the object's type. Try to enable NSZombie to show what kind of object it actually is.
This type of error is often caused by a "dangling pointer", the result of keeping a pointer reference to an object after it has been deallocated. If an other object is instantiated in the (now empty) memory space and you subsequently send a message through the dangling pointer, you get an error like that you've observed. This particular error is caused by sending a message encodedURLParameterString to an NSDecimalNumber.
The fact that the beginning of the struct objc_object of an NSDecimalNumber instance is in the memory location previously occupied by the object you think you're referencing isn't of much consequence. You really care about where the dangling reference is held, and why the object was deallocated before you expected. You can enable NSZombie tracking, which keeps deallocated objects alive and stops in the debugger when you try to send them a message. You can also investigate the stack trace from the site of the crash. The previous stack frame will likely point you to where the offending message was sent from, and thence to the reference that was used.
Once you've identified where the dangling reference is being kept, you should check whether that reference is correctly retained (to keep the object alive).