PDA

View Full Version : This should not work...but it does?




mdeh
Feb 21, 2009, 10:34 AM
Hi all,
I am up to memory management in Kochan. In playing around with strings and retain counts, I tried to invoke a seg fault.
The example from Wikipedia does it in c, thus:

int main (int argc, const char * argv[]) {
char *s = "Sigsegv error constant string";
*s = 'H';

But then I tried this in Obj-C, which I **think** is close to the C example, but obviously not?? , because it works, which is not what I had expected.

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *myStr = @"Constant String";

myStr = [myStr stringByReplacingCharactersInRange: NSMakeRange(1, 11) withString: @"this a test"];
/*[myStr release]; */
NSLog(@"This should not work...but it does!!! %@", myStr);
[pool drain];
return 0;
}


Any insight?
Uncommenting the expression "[myStr release];" does, I **think** do so, however.
Thanks.



newb16
Feb 21, 2009, 12:06 PM
Hi all,
int main (int argc, const char * argv[]) {
char *s = "Sigsegv error constant string";
*s = 'H';

But then I tried this in Obj-C, which I **think** is close to the C example, but obviously not?? , because it works, which is not what I had expected.

They're not equivalent. In C code you assign ( *s = 'H' ) some value to a byte int program (executable) memory, that is forbidden.

NSString *myStr = @"Constant String";
myStr = [myStr stringByReplacingCharactersInRange: NSMakeRange(1, 11) withString: @"this a test"];


Here you create new (autoreleased ) object using stringByReplacingCharactersInRange and assign its address to pointer located in stack, and you are don't modify actual data belonging to @"constant string". Autoreleased object then is deleted when autorelease pool is deleted.

If you release it manually using [myStr release] it probably is released and when autorelease pool tries to delete ( and deallocate ) it by the address it knows ( it knows nothing about you released it), it may crash.

lee1210
Feb 21, 2009, 12:15 PM
In your C example, you dereference your pointer, then do an assignment of a single character. If you instead assigned a new string literal to the pointer (not dereferencing it), it would work just like the objective-C example. "" string literals in C are just char * (maybe const char *, i can't say for sure... i haven't spent a lot of time reading the standards). So you can assign as many as you want to a char * you declare in your code. These string literals just live in the data section of your binary, and obviously modifying anything in that area would be very dangerous, as you may reuse the string literal and if it were modified that would certainly cause some unexpected behavior.

This is more similar to the Objective-C example:

#include <stdio.h>
int main(int argc, char *argv[]) {
char *myString = "This is the first string!";
printf("%s\n",myString);
myString = "This is the second string!";
printf("%s\n",myString;
return 0;
}


It doesn't do any substring stuff, but it's basically the same idea. You have two char * literals and you assign their pointers to the same char * variable, myString.

In Objective-C, any Object is on the heap, and you have a pointer to it. You cannot dereference an Object pointer and have a "concrete" object in Objective-C like you can in C++. So whenever you have an object like an NSString, all you are storing in your function's local variables (or wherever) is a pointer to the object.

In your example you assign an @"" constant (which is just going to be an NSString *) you then use stringByReplacingCharactersInRange:withString: to get a new NSString. That might be where you have gotten caught up. It is brand new. "ByReplacingCharacters" doesn't actually mean in the memory location of the receiver. It means "I have this NSString, i'd like a new one that looks like this one, except...". NSString is immutable. This means that an NSString can't change. You can always assign a new pointer to an NSString *, but that's not changing the original object. There is an NSMutableString that is intended to be changed "in place". This can save memory, because each change you make doesn't have to instantiate a brand new object like you would working with NSStrings. So basically, you get a brand new NSString's pointer from stringByReplacingCharactersInRange:withString:, and you assign it to myStr.

Java uses a method like this, which can lead to some slow code when it is not understood. The java.lang.String type in Java is immutable, but also has a lot of methods that "change" the String. What's really going on is the creation of a new String whenever you use one of these. Since Java has always been GC'd, programmers didn't have to worry about cleaning up the memory, but instantiating a few thousand java.lang.Strings in a tight loop could still be very costly.

Information on @"" literals, mentioning memory management related to these, from apple:
http://developer.apple.com/documentation/Cocoa/Conceptual/Strings/Articles/CreatingStrings.html#//apple_ref/doc/uid/20000148-SW1
That seemed a little related, and I thought I should point to some sort of document instead of just asserting things.

-Lee

mdeh
Feb 21, 2009, 12:21 PM
Here you create new (autoreleased ) object using stringByReplacingCharactersInRange and assign its address to pointer located in stack, and you are don't modify actual data belonging to @"constant string". Autoreleased object then is deleted when autorelease pool is deleted.


So, if I am understanding you correctly, I am simply "redirecting" if that is the correct term, myStr from what it originally points to ( ie "Constant String" ) to a **new** string object , which happens to use myStr in the creation of this new object.

OK...if that is correct? What happens to the original "Constant String". Is this memory leak?

lee1210
Feb 21, 2009, 12:27 PM
So, if I am understanding you correctly, I am simply "redirecting" if that is the correct term, myStr from what it originally points to ( ie "Constant String" ) to a **new** string object , which happens to use myStr in the creation of this new object.

OK...if that is correct? What happens to the original "Constant String". Is this memory leak?

Check out the link in my post above (guessing you didn't see it before posting this) there is a link that describes @"" and memory management. The short and long is that these are never deallocated.

-Lee

mdeh
Feb 21, 2009, 12:42 PM
You were writing as I was answering!
Thank you as always.

In your C example, you dereference your pointer, then do an assignment of a single character. If you instead assigned a new string literal to the pointer (not dereferencing it), it would work just like the objective-C example.

That's what I missed it completely.


"" string literals in C are just char *

Yes...I believe this is correct, and depending upon how they are assigned, ( I stand corrected though) they are either "Constant" and not to be messed with or under the programmer's control ( malloc/strcpy).


These string literals just live in the data section of your binary, and obviously modifying anything in that area would be very dangerous,

Lee...is that significant ie the fact that it is in that ie "binary" area , or is that what I ( unintentionally) alluded to above?


.......whenever you have an object like an NSString, all you are storing in your function's local variables (or wherever) is a pointer to the object.

Which is a nice conceptual way of visualizing it...thanks.


In your example you assign .........That might be where you have gotten caught up. It is brand new. "ByReplacingCharacters" doesn't actually mean in the memory location of the receiver. It means "I have this NSString, i'd like a new one that looks like this one, except..."

Yes..exactly...you narrowed in, as did "newb16" on the key issue I was missing.
One last thing;
I thought I should point to some sort of document instead of just asserting things

assert( Lee advice correct) == Constant TRUE :)

Thanks newb16 (where new comes from I am not sure!!) and Lee for that great insight.

Check out the link in my post above (guessing you didn't see it before posting this)
-Lee

Looking at it now...thank you.

Check out the link in my post above (guessing you didn't see it before posting this) there is a link that describes @"" and memory management. The short and long is that these are never deallocated.

-Lee

Reading is *never* a good thing! :) From the documentation you postedThe compiler makes such object constants unique on a per-module basis, and they’re never deallocated, though you can retain and release them as you do any other object. You can also send messages directly to a string constant as you do any other string:

Kochan mentions this.
Constant strings have no reference-counting mechanism because they can never be released And in fact , in the little program that we use to demonstrate this , when the retain count of @"constant string" is queried, it returns, 0x7fffffff;
The code is this.
NSString *myStr1 = @"Constant string";
.....snip....

NSLog(@"Retain count: myStr1; %lx", (unsigned long) [myStr1 retainCount] );


Obviously both statements are true, but they seem at odds to me.

lee1210
Feb 21, 2009, 04:49 PM
Lee...is that significant ie the fact that it is in that ie "binary" area , or is that what I ( unintentionally) alluded to above?


Any constant you use in your code must be stored in a section of your executable file so they can be "called up" and used when necessary. If you use the string "cow" 50 times in your program, it will (generally) always be using the same section in memory, where the literal "cow\0" is stored. If you were able to change it to "cat\0" instead, it would lead to some strange behavior later. This may be what you meant in terms of these being "constant".


Obviously both statements are true, but they seem at odds to me.


I am guessing you mean that it seems strange that they will both never be released, but you can send retain and release to them. I think the guide is saying "have fun, send them whatever retain/release messages you'd like, but it won't make a difference". Basically the retain count in your program was the maximum value for some integer size. It looks like 36 bits worth, which seems strange, but one way or the other it's "all bits but the sign bit" set. I am guessing that if you send a release, it will still be that number. That is going to be implementation specific, but something will keep it from ever being deallocated. It may be that if you ran release in a loop, when it got to 1 it would never go down, or it may just stay the maximum value, etc.

-Lee

mdeh
Feb 21, 2009, 07:54 PM
Any constant you use in your code must be stored in a section of your executable file so they can be "called up" and used when necessary. If you use the string "cow" 50 times in your program, it will (generally) always be using the same section in memory, where the literal "cow\0" is stored. If you were able to change it to "cat\0" instead, it would lead to some strange behavior later. This may be what you meant in terms of these being "constant".



I am guessing you mean that it seems strange that they will both never be released, but you can send retain and release to them............

-Lee

Thank you again Lee.
My bet is that is exactly what it means.
ps...tried to see what happens when one sends retain and release to the "constant" object. Nothing. No crashes ie the documentation is correct in that one **can** send a message, but Kochan is also correct in that it has no effect , as you surmised, on the retain count!

Catfish_Man
Feb 22, 2009, 04:38 AM
You can check out the source for CFRetain/CFRelease (different from objc retain/release, but closely related) and see how it handles this stuff. It's actually rather interesting, although somewhat arcane.

mdeh
Feb 22, 2009, 05:41 AM
You can check out the source for CFRetain/CFRelease (different from objc retain/release, but closely related) and see how it handles this stuff. It's actually rather interesting, although somewhat arcane.


Thanks Catfish_Man. As you can see from an adjoining thread, I looked at it and it does summarize the rules really well..still leaving some question..
Thanks again.