Clang static analyzer warning "Null pointer argument in call to CFRelease" - objective-c

In Xcode 4.6, the clang static analyzer warns me about a "Null pointer argument in call to CFRelease".
Here's a screenshot of the analyzer warning:
And here's the code in case you want to copy & paste it:
- (void)test
{
CFUUIDRef aUUID = CFUUIDCreate(kCFAllocatorDefault);
[self setUUID:aUUID];
CFRelease(aUUID);
}
- (void)setUUID:(CFUUIDRef)uuid
{
_uuid = uuid ? CFRetain(uuid) : CFUUIDCreate(kCFAllocatorDefault);
}
I don't understand why it is warning me. aUUID can never be a null pointer, can it? I've learnt to rather mistrust myself than the tools I'm using, so I'm asking here. I would be very glad if someone explained to me what I'm missing.

Anything returning an allocated value could, in theory, return NULL.
The analyzer follows multiple possible paths of execution. While following the "aUUID is NULL" scenario, it eventually ends up at the CFRelease of the NULL object.
It's not that setUUID is the cause, that's just the path along which the issue was spotted, so that's the path that's illustrated.

Related

Invalid pointer operation when freeing TStreamAdapter

Can anyone clarify why do I get "Invalid pointer operation" when I attempt to delete TStreamAdapter? Or... how to properly free the memory from TStreamAdapter? It works, if I remove the delete but that causes a memory leak. Even if I use boost::scoped_ptr it also fails with the same error.
Note: I also tried initializing TStreamAdapter with soOwned value, same error.
The code:
HRESULT LoadFromStr(TWebBrowser* WB, const UnicodeString& HTML)
{
if (!WB->Document)
{
WB->Navigate("about:blank");
while (!WB->Document) { Application->ProcessMessages(); }
}
DelphiInterface<IHTMLDocument2> diDoc = WB->Document;
if (diDoc)
{
boost::scoped_ptr<TMemoryStream> ms(new TMemoryStream);
{
boost::scoped_ptr<TStringList> sl(new TStringList);
sl->Text = HTML;
sl->SaveToStream(ms.get(), TEncoding::Unicode);
ms->Position = 0;
}
DelphiInterface<IPersistStreamInit> diPSI;
if (SUCCEEDED(diDoc->QueryInterface(IID_IPersistStreamInit, (void**)&diPSI)) && diPSI)
{
TStreamAdapter* sa = new TStreamAdapter(ms.get(), soReference);
diPSI->Load(*sa);
delete sa; // <-- invalid pointer operation here???
// UPDATED (solution) - instead of the above!!!
// DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
// diPSI->Load(sa);
// DelphiInterface is automatically freed on function end
return S_OK;
}
}
return E_FAIL;
}
Update: I found the solution here - http://www.cyberforum.ru/cpp-builder/thread743255.html
The solution is to use
_di_IStream sa(*(new TStreamAdapter(ms.get(), soReference)));
or...
DelphiInterface<IStream> sa(*(new TStreamAdapter(ms.get(), soReference)));
As it will automatically free the IStream once it is out of scope. At least it should - is there a possible memory leak here? (CodeGuard did not detect any memory leaks).
TStreamAdapter is a TInterfacedObject descendant, which implements reference counting semantics. You are not supposed to delete it at all, you need to let reference counting free the object when it is no longer being referenced by anyone.
Using _di_IStream (which is just an alias for DelphiInterface<IStream>) is the correct way to automate that with a smart pointer. TComInterface<IStream> and CComPtr<IStream> would also work, too.

Core Foundation: why LLVM analyzer report that caller doesn't own object created with *Create* function?

According to The Create Rule I have created my own "constructor" - CFStringCreateFromGoString. It contains "Create" in its name. I expect that if I call CFStringCreateFromGoString then I own returned object.
But according to LLVM static analyzer this is not entirely true and in some cases I receive warning Incorrect decrement of the reference count of an object that is not owned at this point by the caller - see 1.h. And in other cases where is no warning - see 2.h.
From common.h:
CFStringRef CFStringCreateFromGoString(_GoString_ str) {
return CFStringCreateWithBytes(NULL, (UInt8*)_GoStringPtr(str), (CFIndex)_GoStringLen(str), kCFStringEncodingUTF8, false);
}
From 1.h:
CGRect _GetTextLineGeometry(CGContextRef context, _GoString_ str, CTFontRef font) {
CFStringRef _str = CFStringCreateFromGoString(str);
CGRect r = GetTextLineGeometry(context, _str, font); // no warning if I remove this line
CFRelease(_str); // warning here
return r;
}
From 2.h:
CTFontRef _CreateFontFromFile(_GoString_ path, struct FontSpec spec) {
CFStringRef _path = CFStringCreateFromGoString(path);
CTFontRef r = CreateFontFromFile(_path, spec);
CFRelease(_path); // no warning
return r;
}
Can somebody explain the difference between 1.h and 2.h?
Update 0
Thx matt for comment.
The problem was at GetTextLineGeometry - this function by mistake performed CFRelease(_str). Now I have no warnings.
But I don't understand why warning was in _GetTextLineGeometry instead of GetTextLineGeometry?
The name component "Create" does not perform any magic; it is just a matter of convention. So, for that matter, is the concept of "ownership".
So forget about all that and just think about the retain count.
The static analyzer, unlike mere human beings like you and me, can see all your code, and can count. It is counting the retains and releases on this object. When we get to CFRelease(_str) in your first example, you have previously released this same object, causing its retain count to drop to zero; so at this point you are performing an overrelease. Thus the static analyzer flags you at this point.
Now let's go back and think about it again from the point of view of "ownership". Only the "owner" of something can release it; that is what "ownership" means. But the static analyzer is perfectly willing to let you transfer ownership, if you know what you're doing. So if you want to "take ownership" by releasing in GetTextLineGeometry, that's fine with the static analyzer. But when when we get to CFRelease(_str), that is a second "owner" — and that isn't cricket. Thus, again, the static analyzer flags you here.

Assert with string argument not working as expected

EDIT: The issue was with the assert as people pointed out below. Thanks for the help!
I have a enum set that i'm trying equate, but for some reason its not working.
Its declared like so:
typedef NS_ENUM(NSUInteger, ExUnitTypes) {
kuNilWorkUnit,
kuDistanceInMeters,
//end
kuUndefined
};
And i'm using it here:
+(NSString*) ExUnitDescription: (ExUnitTypes) exUnit
{
if (exUnit == kuNilWorkUnit)
{
assert("error with units");
}
///.... more stuff
}
Xcode isnt triggering my assert. EDIT: the assert is just for testing. i've used NSLog as well. The conditional isn't evaluating to true even though the value is clearly kuNilWorkUnit.
Does anyone have any suggestions or ideas of what i'm doing wrong?
You want to do this:
+(NSString*) ExUnitDescription: (ExUnitTypes) exUnit
{
assert(exUnit != kuNilWorkUnit);
///.... more stuff
}
This is because, assert only stops execution if the expression you pass to it is false. Since a string literal is always non-zero, it will never stop execution.
Now, since you are using Objective C and it also looks like you want to have a message associated with your assert, NSAssert would be preferable.
+(NSString*) ExUnitDescription: (ExUnitTypes) exUnit
{
NSAssert(exUnit != kuNilWorkUnit, #"error with units");
///.... more stuff
}

CFStringGetCStringPtr returns NULL on iOS7

I have the following code in my Application:
static void foo(CFStringRef str)
{
CFStringEncoding encoding = CFStringGetSystemEncoding();
const char * cString = CFStringGetCStringPtr(str, encoding);
//.....
}
It's been around since iOS 5, and always worked.
Since iOS 7 release, CFStringGetCStringPtr returns NULL.
Adding the following code, have solved it:
if (cString==NULL)
{
cString = [
((NSString *)str) cStringUsingEncoding:[NSString defaultCStringEncoding]
];
}
Still, I would like to know if anyone knows what causes the problem?
CFStringGetCStringPtr() isn't guaranteed to return non-NULL. From the docs (emphasis added):
Whether or not this function returns a valid pointer or NULL depends on many factors, all of which depend on how the string was created and its properties. In addition, the function result might change between different releases and on different platforms. So do not count on receiving a non-NULL result from this function under any circumstances.
Always have a fallback to CFStringGetCString(), but even better, use Objective-C and NSString's helper methods (e.g. UTF8String).

Symbian: kern-exec 3 panic on RLibrary::Load

I have troubles with dynamic loading of libraries - my code panics with Kern-Exec 3. The code is as follows:
TFileName dllName = _L("mydll.dll");
TFileName dllPath = _L("c:\\sys\\bin\\");
RLibrary dll;
TInt res = dll.Load(dllName, dllPath); // Kern-Exec 3!
TLibraryFunction f = dll.Lookup(1);
if (f)
f();
I receive panic on TInt res = dll.Load(dllName, dllPath); What can I do to get rid of this panic? mydll.dll is really my dll, which has only 1 exported function (for test purposes). Maybe something wrong with the DLL? Here's what it is:
def file:
EXPORTS
_ZN4Init4InitEv # 1 NONAME
pkg file:
#{"mydll DLL"},(0xED3F400D),1,0,0
;Localised Vendor name
%{"Vendor-EN"}
;Unique Vendor name
:"Vendor"
"$(EPOCROOT)Epoc32\release\$(PLATFORM)\$(TARGET)\mydll.dll"-"!:\sys\bin\mydll.dll"
mmp file:
TARGET mydll.dll
TARGETTYPE dll
UID 0x1000008d 0xED3F400D
USERINCLUDE ..\inc
SYSTEMINCLUDE \epoc32\include
SOURCEPATH ..\src
SOURCE mydllDllMain.cpp
LIBRARY euser.lib
#ifdef ENABLE_ABIV2_MODE
DEBUGGABLE_UDEBONLY
#endif
EPOCALLOWDLLDATA
CAPABILITY CommDD LocalServices Location MultimediaDD NetworkControl NetworkServices PowerMgmt ProtServ ReadDeviceData ReadUserData SurroundingsDD SwEvent TrustedUI UserEnvironment WriteDeviceData WriteUserData
source code:
// Exported Functions
namespace Init
{
EXPORT_C TInt Init()
{
// no implementation required
return 0;
}
}
header file:
#ifndef __MYDLL_H__
#define __MYDLL_H__
// Include Files
namespace Init
{
IMPORT_C TInt Init();
}
#endif // __MYDLL_H__
I have no ideas about this... Any help is greatly appreciated.
P.S. I'm trying to do RLibrary::Load because I have troubles with static linkage. When I do static linkage, my main program doesn't start at all. I decided to check what happens and discovered this issue with RLibrary::Load.
A KERN-EXEC 3 panic is caused by an unhandled exception (CPU fault) generated by trying to invalidly access a region of memory. This invalid memory access can be for both code (for example, bad PC by stack corruption) or data (for example, accessing freed memory). As such these are typically observed when dereferencing a NULL pointer (it is equivalent to a segfault).
Certainly the call to RLibrary::Load should never raise a KERN-EXEC 3 due to programmatic error, it is likely to be an environmental issue. As such I have to speculate on what is happening.
I believe the issue that is observed is due to stack overflow. Your MMP file does not specify the stack or heap size the initial thread should use. As such the default of 4Kb (if I remember correctly) will be used. Equally you are using TFileName - use of these on the stack is generally not recommended to avoid... stack overflow.
You would be better off using the _LIT() macro instead - this will allow you to provide the RLibrary::Load function with a descriptor directly referencing the constant strings as located in the constant data section of the binary.
As a side note, you should check the error value to determine the success of the function call.
_LIT(KMyDllName, "mydll.dll");
_LIT(KMyDllPath, "c:\\sys\\bin\\");
RLibrary dll;
TInt res = dll.Load(KMyDllName, MyDllPath); // Hopefully no Kern-Exec 3!
if(err == KErrNone)
{
TLibraryFunction f = dll.Lookup(1);
if (f)
f();
}
// else handle error
The case that you can't use static linkage should be a strong warning to you. It shows that there is something wrong with your DLL and using dynamic linking won't change anything.
Usually in these cases the problem is in mismatched capabilities. DLL must have at least the same set of capabilities that your main program has. And all those capabilities should be covered by your developer cert.