Using new[] where size is result of a message call causes crash - objective-c++

I have some Objective-C++ code which dynamically allocates space for an array of Objective-C object pointers. The size is computed by an Objective-C message call:
ItemCell **rawCells = new ItemCell*[[self cellCount]];
This code eventually causes a segfault. The similar code
ItemCell **rawCells = (ItemCell**)std::malloc([self cellCount] * (sizeof *rawCells));
works just fine. What's going on here?

Copied from poster's answer (he lacks the karma to answer himself, so he put it in the question), and marked as community wiki (because copy/paste shouldn't earn me karma):
The problem is that [[self cellCount]] is treated as a C++11 attribute and ignored, since the compiler doesn't recognize it. The result is that the line effectively becomes
ItemCell **rawCells = new ItemCell*;
which doesn't allocate enough storage. I confirmed this in gdb - the argument to new is 8, the size of a single pointer.
The most compact way to solve this is to insert an extra pair of parentheses to prevent the compiler from recognizing [[ and ]] as attribute syntax:
ItemCell **rawCells = new ItemCell*[([self cellCount])];
You can also store the result of [self cellCount] in a local variable and refer to that in the new[] call.

Related

using boost::python::list as return value need increase ob_refcnt?

I am trying my best to find memory leaks in a very important module in our project and got a code snippet like this:
PyObject* python_func( const char* str )
{
..........................
boost::python::list obj;
obj.append(str);
obj.ptr()->ob_refcnt++; //this is necessary??
return obj.ptr();
}
I am confused about this line: obj.ptr()->ob_refcnt++;
I think ob_refcnt is maintained by python internally for gc, we can't operate it so obviously cause this will lead to memory leaks, on the other hand, obj is going to leave its scope, I am not sure if boost::python::list deconstructor will decrease ob_refcnt, if that's true, remove that line, the resource obj hold would be released, that will lead to a crash.
So my question is whether obj.ptr()->ob_refcnt++; is necessary, and why?
The reason the code increases the reference count is that python_func is intended to return a new reference to the object. (A new reference is one that has the reference count already increased -- returning a new reference allows the function to create new objects, such as a new list in this case.) On the other hand, the ptr() member function returns a borrowed reference to the object.
As you correctly surmised, if the code failed to increase the reference count of the borrowed reference, the destructor of boost::python::list would decrease the reference count and the returned object would be invalid.
Note that you should never directly access the ob_refcnt member of PyObject. The proper way to increase the reference count is through the use of the Py_INCREF macro or its boost::python equivalent boost::python::incref:
return boost::python::incref(obj.ptr());

attempt to mutate immutable object randomly thrown

One part of the program takes text from a uitextfield, copies it to a mutable string and then performs
sharedManager.ce_name=name.text
[sharedManager.ce_name replaceOccurrencesOfString:#" " withString:#"%20"
options:NSLiteralSearch range:NSMakeRange(0, [sharedManager.ce_name length])];
At this point it always gave me "attempt to mutate immutable object" - it was not random
The first time I got this error I changed it to
sharedManager.ce_name=(NSMutableString *)name.text
This STILL gave me the attempt to mutate immutable object error, but it would occur randomly - weird right?
I then changed it to
NSMutableString *mutable_name = [NSMutableString stringWithString:name.text];
sharedManager.ce_name=mutable_name;
It has yet to fail on me doing it this way but I am convinced that I have not found the solution.
my questions:
1) Could that fact that it was doing it randomly after the first fix indicate I have some deep seated memory management problem?
2) Why didn't the C-style cast fix it?
3) Will my current fix work?
Thanks for your time :)
The problem here is the way in which you're using casting. When you cast a pointer, it just starts treating the memory at that location as though it were a block of data representing that type.
So if I've got a pointer to a Car class: Car* mycar;, and I cast it to a Person object: (Person*)mycar;, the program will try to access the memory there as though it was pointing at a Person object. However, a car is not a person, except in an old TV sitcom, so when it tries to access members on this or call functions, it's going to try to go to a memory location that contains something other than what it's expecting, and undefined things happen (generally, crashing).
NSMutableString and NSString are incompatible in this regard, and so casting from one to the other will result in terrible times. Your fix ([NSMutableString stringWithString:]) is the correct solution.
If it was doing it randomly, it means that name.text was sometimes a mutable string and some times an immutable string.
Casting between objects like that doesn't change the class of the object. It won't make your immutable object mutable.
That "fix" is probably the best way to do it (at least from what I can see in the code you are showing)
Without seeing at least the declarations of the variables involved, it's difficult to say for certain, but your final solution, creating a new mutable string is likely the correct fix. As for your questions,
Not memory management per se, but it was probably overwriting something it shouldn't have somewhere.
Casts cannot change the fundamental type of an object. You had (presumably) an NSString and all the casting in the world cannot make it into an NSMutableString.
Like I said, probably, but we'd need to see more code to make sure. It's certainly a much better fix.

Malloc() creates space for single struct, not array of structs

I've been banging my head against this problem all day, I would be very grateful to anyone who could help out.
Here's the deal - I'm trying to create a dynamic C array using malloc(). This array will hold CGPoint structs, which I start building and assigning right after the array is built. Here's the code:
CGPoint* tempVertices = malloc(sizeof(CGPoint) * 4); //defining a collision frame
tempVertices[0] = CGPointMake(37, 46);
tempVertices[1] = CGPointMake(69, 40);
tempVertices[2] = CGPointMake(48, 6);
tempVertices[3] = CGPointMake(17, 10);
//Then I pass the pointer to my array off to a setter...
[self setVertices: tempVertices];
However, when tempVertices gets created, it seems that I'm only getting space for one CGPoint:
int test1 = sizeof(CGPoint); // 8
int test2 = sizeof(tempVertices); // 4
int test3 = sizeof(*tempVertices); // 8
When stepping through with the XCode debugger, it shows that tempVertices is a pointer to a CGPoint. When I set tempVertices[0], the CGPoint that tempVertices points to recieves that value, which is reflected in the debugger. Where did my other 3 slots go? tempVertices seems to be pointing to a singe CGPoint instead of an array. I want the array.
Any ideas on what I'm doing wrong? I know that there are other ways to fix this using C++ or other objects, but I want to stick to C if possible.
Thanks in advance!
Update :
To answer zpasternack, setVertices: is a custom written setter. And I don't know how / if it knows how big the incoming array is. I'm trying to understand straight C stuff better, so insights/explanations regarding the proper way of passing a dynamic C-array as an argument are highly appreciated. Here's what the setter looks like :
- (void) setVertices:(CGPoint*) val {
_vertices = val; //_vertices is a member variable of the type CGPoint*
//...calculate a centroid, other stuff...
}
If needed, I could wrap my CGPoints in NSValue objects and use an NSArray instead, but I sure would like to know the right way of doing it in plain ol' C.
Thanks to everyone who has commented - you guys are great :)
On your 32 bit machine, you're getting exactly what you expect. sizeof(tempVertices) is the size of the pointer, while sizeof(*tempVerices) gives you the size of a CGPint (probably two ints). You can't get the size of an allocated array with sizeof(). The value is only known at run-rime, and sizeof() is a compile time operator.
OK, after your edit I think I see what's going on. That code, exactly as you've written, should work OK. Xcode won't show you the values of any of those CGPoints, because it doesn't know it's an array, just a pointer to a single CGPoint. But it's there. Set a breakpoint right after you call setVertices:. At the gdb prompt, print some of those values.
(gdb) print _vertices[1]
$2 = {
x = 69,
y = 40
}
(gdb) print _vertices[3]
$3 = {
x = 17,
y = 10
}
Correct, see?
That's not to say there aren't issues here. For one thing, setVertices: is leaking that memory. You're allocating memory for tempVertices, holding onto that pointer, but not freeing it anywhere. The next time you call setVertices:, you'll have a leak.
A bigger issue is that nobody knows how many CGPoints are in that array, except the code that allocated the memory for it. Will it always be 4 CGPoints? What happens if somebody accesses _vertices[5] or _vertices[27]? Bad things, if you didn't allocate that much space for them.
Is there a requirement that this be a plain C array? Like, these points are going to get passed to OpenGL or cocos2d or something? If not, you might consider using some kind of array class for it. Because these aren't NSObject-derived objects you're storing, you can't use an NSArray. You could use a std::vector, if you don't mind dragging in a buncha C++. I probably would not do that.
If you're set on sticking with a C array, you should probably do some work to try to make the interface less error prone. Like I mentioned before, you'll need to track the size of the array. Perhaps you could add a parameter to setVertices: representing the number of CGPoints that the array holds. Then other parts of the code that access _vertices could check that to make sure they're not walking off the end of the array. And, like I mentioned before, make sure you free that memory before you reassign the pointer.
Messing about with pointers is fraught with danger. Tread carefully, there be dragons there.
The malloc is allocating enough space for 4 GCPoint structs and returning a pointer to the allocated space.
The first is at tempVertices + 0. It's tempVertices[0].
The second is at tempVertices + 1. It's tempVertices[1].
The third is at tempVertices + 2. It's tempVertices[2].
The fourth is at tempVertices + 3. It's tempVertices[3].
I would not use sizeof() to determine the size of an array allocated at runtime.
Have you actually had trouble assigning new CGPoint objects into your array? Does CGPointMake() perform any allocation of its own?

Why do people always use reassignment for instance variables in Objective-C (namely iPhone)?

I always see example code where in the viewDidLoad method, instead of saying, for example
someInstanceVar = [[Classname alloc] init];
they always go
Classname *tempVar = [[Classname alloc] init];
someInstanceVar = tempVar;
[tempVar release];
Why is this? Isn't it the exact same thing, just longer?
The short answer: This pattern shows up all the time in iPhone code because it is considered the best way to create a new object and assign it to a member variable while still respecting all of the memory management rules and invoking the appropriate side effects (if any) while also avoiding the use of autorelease.
Details:
Your second example would create a zombie, since var is left holding a pointer to memory that has been released. A more likely usage case looks like this:
tempVar = [[Classname alloc] init];
self.propertyVar = tempVar;
[tempVar release];
Assuming that propertyVar is a declared as copy or retain property, this code hands off ownership of the new object to the class.
Update 1: The following code is equivalent, but not recommended* on iOS, which is probably why most iPhone programs use the first pattern instead.
self.propertyVar = [[[Classname alloc] init] autorelease];
* autorelease is discouraged on iOS because it can cause problems when overused. The easiest way to be sure you never overuse it is to never use it all, so you will quite often see iOS code that uses alloc/init and release, even when autorelease would be acceptable. This is a matter of coder preference.
Update 2: This pattern looks confusing at first because of the memory management that Cocoa performs automagically behind the scenes. The key to it all is the dot notation used to set the member variable. To help illustrate, consider that the following two lines of code are identical:
self.propertyVar = value;
[self setPropertyVar:value];
When you use the dot notation, Cocoa will invoke the property accessor for the indicated member variable. If that property has been defined as a copy or retain property (and that is the only way for this pattern to work without creating a zombie), then several very important things happen:
Whatever value was previously stored in propertyVar is released
The new value is retained or copied
Any side effects (KVC/KVO notifications, for example) are automatically handled

NSString to C-style char array crashes on second invoke to drawRect

I am trying to write text using a Core Graphics context. I can do it the first time, no problem, but the second time crashes my iPhone app. Here is a code snippet:
NSString *name = [MyClass getName];
const char *cname = [name UTF8String];
[self drawText:context text:cname];
MyClass and drawText are custom classes/methods but you get the idea. These three lines live in drawRect:
The first time drawRect: is executed, I see the text as expected. However, on any refresh of drawRect:, the line:
const char *cname = [name UTF8String];
causes my app to crash with the cryptic, "GDB: Program loaded." status message.
I get a similar response even when I use the getCString: method. I think I might be missing a fundamental understanding of NSString to char array conversion.
It sounds like you're trying to call methods on an object which has been deallocated already. The UTF8String message has the problem that you can't hold onto the returned pointer, since it may become invalidated when the string is released -- you have to copy the string if you need to hold onto it. However, getCString:maxLength:encoding: does not have that problem.
Make sure you're following properly memory management protocol. See the Memory Management Programming Guide for Cocoa, and double-check that you're sending retain, release, and autorelease messages to the proper objects at the proper times. Chances are you're sending an extra release or autorelease when you shouldn't be, or you're forgetting to retain your string somewhere.
The most likely cause is that you're keeping a reference to the previously returned char* and you are dereferencing it on the second call. According to spec, the pointer is not valid to store: The returned C string is automatically freed just as a returned object would be released; you should copy the C string if it needs to store it outside of the autorelease context in which the C string is created.