Corefoundation CFArray ownership - objective-c

I found a strange problem while using Core Foundation Array! Here is the code snippet
fname = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%s%s"), path, ep->d_name);
CFArrayAppendValue(fileNames, fname);
CFRelease(fname); <---- problem here
cnt = CFArrayGetCount(fileNames);
for (i = 0; i < cnt; i++) {
fname = CFArrayGetValueAtIndex(fileNames, i);
if (fname) {
ptr = (char *)CFStringGetCStringPtr(fname, CFStringGetFastestEncoding(fname));
The code crashes at the last line. Please correct me if I got this wrong. After I created the CFStringRef, I add it to CFArray. As per my understanding the object is now owned by CFArray. Hence I can safely remove the CFStringRef I originally allocated. But when I do CFRelease(fname); the code crashes when I access the array elements in the second part of the code. Can someone explain what is correct way of doing it? If I remove the CFRelease() then everything works fine.

As CFMutableArray Reference says:
The value parameter is retained by theArray using the retain callback
provided when theArray was created. If value is not of the type
expected by the retain callback, the behavior is undefined.
So looks like this is the issue of the fileNames array creation. Probably the third parameter of the CFArrayCreateMutable function. Since CFString is a CFType try to pass kCFTypeArrayCallBacks there.

Related

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.

Modifying self in `iter_mut().map(..)`, aka mutable functional collection operations

How do I convert something like this:
let mut a = vec![1, 2, 3, 4i32];
for i in a.iter_mut() {
*i += 1;
}
to a one line operation using map and a closure?
I tried:
a.iter_mut().map(|i| *i + 1).collect::<Vec<i32>>();
The above only works if I reassign it to a. Why is this? Is map getting a copy of a instead of a mutable reference? If so, how can I get a mutable reference?
Your code dereferences the variable (*i) then adds one to it. Nowhere in there does the original value get changed.
The best way to do what you asked is to use Iterator::for_each:
a.iter_mut().for_each(|i| *i += 1);
This gets an iterator of mutable references to the numbers in your vector. For each item, it dereferences the reference and then increments it.
You could use map and collect, but doing so is non-idiomatic and potentially wasteful. This uses map for the side-effect of mutating the original value. The "return value" of assignment is the unit type () - an empty tuple. We use collect::<Vec<()>> to force the Iterator adapter to iterate. This last bit ::<...> is called the turbofish and allows us to provide a type parameter to the collect call, informing it what type to use, as nothing else would constrain the return type.:
let _ = a.iter_mut().map(|i| *i += 1).collect::<Vec<()>>();
You could also use something like Iterator::count, which is lighter than creating a Vec, but still ultimately unneeded:
a.iter_mut().map(|i| *i += 1).count();
As Ry- says, using a for loop is more idiomatic:
for i in &mut a {
*i += 1;
}

How can I do C pointer arithmetic in a C file which is part of an Xcode 4.3.3 Objective-C project for iPad?

I have what looks to me an innocent cycle which iterates on elements of an array whose type is unknown at compile time; my array is named mesh->vertices and is a pointer to void. Depending on the truth value of mesh->textured I need to consider the array differently. Incidentally, the code in the if and the else in the code segment below is similar, but I do need to distinguish two cases.
void TransformMesh(struct Mesh *mesh, struct Matrix4 *t)
{
for (int i = 0; i < mesh->nVertices; ++i)
{
if (mesh->textured)
{
struct TexturedVertex *ptr = ((struct TexturedVertex *)mesh->vertices) + i;
ptr[i].position = MatrixPointMultiply3(t, &ptr->position);
ptr[i].normal = MatrixPointMultiply3(t, &ptr->normal);
}
else
{
struct Vertex *ptr = ((struct Vertex *)mesh->vertices) + i;
ptr[i].position = MatrixPointMultiply3(t, &ptr->position);
ptr[i].normal = MatrixPointMultiply3(t, &ptr->normal);
}
}
}
I guess I created the project with the Automatic Reference Counting option, thinking that it would not have affected C code, but now I feel like I'm wrong (by the way, how can I check which option I chose?).
Well, it looks like this function is doing something wrong with another array, called mesh->triangles, probably freeing it. When I try to use the vector I get an EXC_BAD_ACCESS error:
glDrawElements(GL_TRIANGLES, mesh->nTriangles * 3, GL_UNSIGNED_INT, mesh->triangles);
It looks like iterating on the mesh->vertices elements, casting them and doing the pointer arithmetic, is corrupting the memory. I think my problem is ARC, so I tried to do what described here but with no luck.
EDIT:
The code above was wrong, as pointed out by Conrad Shultz; the following is correct:
ptr->position = MatrixPointMultiply3(t, &ptr->position);
ptr->normal = MatrixPointMultiply3(t, &ptr->normal);
I seriously doubt ARC has anything to do with this - ARC only manages Objective-C objects. (It doesn't even know how to handle Core Foundation types, which leads to the requirement for using the __bridge... keywords.)
I'm struggling to understand your code. Admittedly, I don't do a great deal of straight C programming, but I don't get what you're trying to do by adding i to ptr, which is presumably the pointer arithmetic of which you speak.
Are you trying to just access the ith struct TexturedVertex in mesh->vertices? If so, just use your ptr[i] construct as written.
It looks to me like you are doing arithmetic such that ptr ends up pointing to the ith struct TexturedVertex, then by accessing ptr[i] you are reading i elements past the ith struct TexturedVertex. If nVertices refers to the count of vertices (as would seem logical, given the name and C array conventions), you are then reading past the end of vertices, a classic buffer overflow error, which would unsurprisingly lead to EXC_BAD_ACCESS and all sorts of other fun errors.

Find out how many arguments a block needs

Let's say I have an array containing Blocks, and I need to assert that all of them expect a given number of arguments.
Is there a way to find this out programmatically?
This is indeed possible, for any recent version of Clang.
The Apple ABI for Blocks is private but also published. Since that document tells us the layout the compiler will use for a Block object, we can duplicate that information in a header file and use it to access the components of a Block.
Mike Ash's MABlockForwarding project does just that (see also the article) -- much of the stuff at the top of this file is a copy-paste from the ABI doc. The thing that he created which we are interested in is the BlockSig() function:
static const char *BlockSig(id blockObj)
{
struct Block *block = (__bridge void *)blockObj;
struct BlockDescriptor *descriptor = block->descriptor;
assert(block->flags & BLOCK_HAS_SIGNATURE);
int index = 0;
if(block->flags & BLOCK_HAS_COPY_DISPOSE)
index += 2;
return descriptor->rest[index];
}
which will return (for Blocks that have it (which they all do with recent Clang)), a type encoding string describing the Block's return and argument types. From there, you can create an NSMethodSignature object, and ask it for its numberOfArguments:
NSString * (^block)(int, NSArray *) = ^NSString * (int i, NSArray * a){
return #"Oh, yeah!";
};
const char * types = BlockSig(block);
NSMethodSignature * sig = [NSMethodSignature signatureWithObjCTypes:types];
[sig numberOfArguments];
The result there is 3, because it includes a hidden argument for the Block itself (and Blocks don't use the hidden _cmd argument or it would be 4).
The answer is you cannot. See the comment on Mike Ash's page regarding this:
Search for Intropection which sends you here
So, what is your real problem? If you structure the arguments properly, you can insure that your system functions properly. For instance, you can do what C++ does with default values for arguments, and cast each block to a type that takes the max number of args, and always push that many items on the stack. Or you could always have the first argument be the number of arguments you are pushing on the stack. If you push objects and not numbers/pointers, then you r blocks can look at the class of each argument and dynamically adapt.

Can't get where is the memory leak in the function

I am having a problem in identifying a memory leak. I tried Instruments and it says that there is memory leak every time I call the function described below.
CFStringRef getStringFromLocalizedNIB(int cmdId)
{
IBNibRef nibRef;
WindowRef wind=NULL;
CFStringRef alertString;
CreateNibReference(CFSTR("main"), &nibRef);
CreateWindowFromNib(nibRef, CFSTR("Localized Strings"), &wind);
DisposeNibReference(nibRef);
ControlID alertID = {'strn',cmdId};
ControlRef alertRef;
GetControlByID(wind, &alertID,&alertRef);
GetControlData(alertRef, kControlNoPart, kControlStaticTextCFStringTag, sizeof(CFStringRef), &alertString, NULL);
return alertString;
}
Every time I call the function, I release the returned object.
CFStringRef lstr;
lstr = getStringFromLocalizedNIB(20);
//Use lstr;
CFRelease(lstr);
So can anybody please explain where the leak is?
If I understand correctly, you aren't showing the window created using CreateWindowFromNib(). I would expect the window to have the Carbon equivalent of release-on-close, and the CreateWindowFromNib() to be balanced by a ShowWindow(). I haven't done Carbon in 9 years though, so I'm not sure.
Try calling DisposeWindow() on wind to balance the create:
...
DisposeWindow(wind);
return alertString;
}