Open Quuxplusone opened 11 years ago
Attached InterproceduralBug.zip
(4806 bytes, application/zip): Xcode project
Attached report.html
(9594 bytes, text/html): Static analyzer report
The analyzer is pedantically correct; adoptedString could equal kEmptyCFString. Your Adopt() method should release its argument if it's the same as the current string.
To be clear, we could do special modeling of CFSTR and CFStringCreateCopy, but in general this is a real issue with this class, even though this particular case is safe.
Thanks a lot for the comment. You are indeed correct. I though the Static
Analyzer would be able to detect that both CFStringRef are different but that's
not the case.
I really don't think that you should do something special for CFSTR and
CFStringCreateCopy. I could reproduce the same issue with any CoreFoundation
objects (CFURLRef, ...).
Your suggestion of releasing the argument of the Adopt() method is not
something I completely like. I agree that this is theoretically what should be
done but I think that passing the same string should be considered as a
programming error. I am working on a project with a huge codebase. Changing the
Adopt() method to always release the parameter could led to crashes if some
code incorrectly uses the Adopt() method.
I ended up with the following solution. I only release the parameter in the
DEBUG build and also force a crash. This way the Static Analyzer doesn't report
a memory leak and I would catch the possible programming errors. The release
build would not be affected and I prefer to leak a string rather than crashing.
void Adopt(CFStringRef s)
{
if (s != mRef)
{
if(mRef != NULL)
CFRelease(mRef);
mRef = s;
}
#if DEBUG
else
{
// Prevent the Clang Static Analyzer to report a memory leak.
CFRelease(s);
// Force a crash to detect programming errors.
int *a = (int*)1;
*a = 2;
}
#endif
}
I think you can close the bug. There are only one improvement in the Static
Analyzer I could see to help with such cases. You could improve the workflow
displayed. Right now the Static Analyzer gives me the workflow:
- Call to function 'CFStringCreateCopy' returns a Core Foundation object with a
+1 retain count
- Object leaked: object allocated and stored into 'adoptedString' is not
referenced later in this execution path and has a retain count of +1
It doesn't tell me that it don't take the if branch in the Adopt() method.
I wouldn't have reported this issue if the workflow was:
- Call to function 'CFStringCreateCopy' returns a Core Foundation object with a
+1 retain count
- Taking false branch (in the Adopt() method)
- Object leaked: object allocated and stored into 'adoptedString' is not
referenced later in this execution path and has a retain count of +1
Thanks again,
Alexandre
Let's keep this bug open for the poor path, then. This is one in a common family of problems.
By the way, the analyzer understands assert() (and abort() or exit()), so you can use either of those to silence the issue, even without the extra CFRelease().
I decided to use the CFRelease call even in the release build. I discovered 2 cases in our source code where the Adopt() function was incorrectly called with a not CFRetained parameter. I believe that the Clang Static Analyzer might find these issues.
I also noticed that there were some real memory leak in the case of constant CFString: CFStringCreateCopy and similar functions have optimizations for constant strings. Instead of returning a new string, the string is simply retained. This caused the Adopt function to leak the constant string because the 'else' case was taken.
InterproceduralBug.zip
(4806 bytes, application/zip)report.html
(9594 bytes, text/html)