 |
 |
Odd autorelease crashes
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
Hey everyone. I'm having rather odd issues with the NSAutoRelease pool. My program is crashing when the NSAutoRelease pool releases an NSString that I have neither retained nor released. This string was created using the -substringWithRange: method. I have used Apple's ObjectAlloc tool to figure out what object is actually bringing the program down, and I have also used that tool to verify that this object was neither retained nor released.
The part that I find extremely odd is that this string is created in a factory method for my laExpression class. If I autorelease the object returned from this function, the program crashes at the the NSString object. If I do not autorelease the laExpression object, the program does not crash.
Forgive me for not posting code, but this factory method is 1000 lines long. I'm just curious if anyone has run into similar issues.
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Senior User
Join Date: Apr 2001
Location: Bolingbrook, IL, USA
Status:
Offline
|
|
My guess is that NSString's -substringWithRange: returns an autoreleased NSString, so if you autorelease that, it's on the autorelease pool twice, and thus gets sent -release twice from the autorelease pool, causing a crash.
That was a run-on sentence, if there ever was one. 
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
Originally posted by oVeRmInD911:
My guess is that NSString's -substringWithRange: returns an autoreleased NSString, so if you autorelease that, it's on the autorelease pool twice, and thus gets sent -release twice from the autorelease pool, causing a crash.
That was a run-on sentence, if there ever was one.
That's what the documentation says. Therefore, I am not autoreleasing the object.
Is it possible that I am releasing an object elsewhere that is already on the autorelease pool, and then this object just inadvertently gets allocated in the same location as the other object? If this is the case, that would mean the crash has nothing to do with the NSString (which is what it appears) and more to do with a memory management error elsewhere that just appears to be due to this NSString. I feel like I have been chasing my tail for the past two weeks on this one.
Thanks for any input.
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Dedicated MacNNer
Join Date: Dec 2000
Location: sj ca
Status:
Offline
|
|
Originally posted by Detrius:
Is it possible that I am releasing an object elsewhere that is already on the autorelease pool, and then this object just inadvertently gets allocated in the same location as the other object?
I would say that's highly improbable.
My bet is that you released this string somewhere earlier, so when auotrelease does its magic, the object is already gone.
A technique that I have found useful in the past is to create and use a subclass that does an NSLog in the dealloc method, so you can do your own pseudo reference counting (for debugging). To make this work for your situation, you'll need to either use the poseAsClass: class method, or do a "swizzle" (search on cocoadevcentral for details). Make sure your new dealloc calls [super dealloc]!
That's a pretty hardcore technique for your problem, but if you've already spent two weeks...
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
Don't autorelease the object. Whenever you get an object without using an alloc] init... statmeent, it's assuemd the the object has already been autoreleased.
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
The thing that is absolutely bizarre is that according to Apple's ObjectAlloc utility, the NSString object has been neither retained nor released, yet it is crashing in the autorelease pool.
The thing that is incredibly bizarre is that I can fix this crash by changing a line of code to *not* autorelease a totally different object that I alloced/inited. However, when I do that, I'm getting a crash in a completely unrelated retain/release on an NSView (the crash is on a release called by Apple, shortly after Apple calls retain).
By brain is getting tired of trying to figure this out... I'm about willing to let someone else look at my codebase--that is if anyone is willing, capable, and has the time to look at a project this large.
I know this is a stretch, but under the assumption that my code is not the problem, what else could possibly cause I problem like this? If my code is the problem, how is the autorelease crash possible if the object has not been retained/released?
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
Originally posted by Detrius:
If I autorelease the object returned from this function, the program crashes at the the NSString object. If I do not autorelease the laExpression object, the program does not crash.
That's what the documentation says. Therefore, I am not autoreleasing the object.
this thread has gotten kind of muddled. Are you saying that unlike your original post, now when you decline to autorelease this object (which is already autoreleased by NSString and therefore you shouldn't be autoreleasing again), it now crashes in this case as well?
whenever I've had memory problems it's always turned out that I've overrun a buffer or something in an unrelated part of my app. I found the culprit once using MallocDebug, maybe you can as well. Also try writing a test app that only uses this one factory method, but which uses it as much as possible, constantly, ad infinitum. It might be that your app's stack is being molested before you even get to this method.
|
|
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
wait, now that I actually read the part I quoted I'm less sure I ever knew what you were talking about. Did you mean you were autoreleasing the NSString you were talking about, or autoreleasing some other object you created? And if the latter, how exactly did you create it?
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
Originally posted by Uncle Skeleton:
wait, now that I actually read the part I quoted I'm less sure I ever knew what you were talking about. Did you mean you were autoreleasing the NSString you were talking about, or autoreleasing some other object you created? And if the latter, how exactly did you create it?
+ (laExpression *)expressionWithString: (NSString *)theString
andListOfVariables: (laVariableList *)theList
{
...
laExpression *output = [[[laExpression alloc] int] autorelease];
...
NSString *spareString = [theString substringWithRange: anNSRange];
laExpression *left = [laExpression withString: spareString];
...
}
*spareString is the variable that is crashing in the autorelease pool. It is not stored, retained, or released. It is merely used in that function, and the relevant information is extracted and stored in a different form. Oddly, if *output is not autoreleased, the crash does not occur. I have verified the fact that *spareString is not retain/released/stored both by searching through my code and by observing the information obtained by ObjectAlloc. In addition, this crash does not occur on every pass through this code. Just to see what would happen, I inserted a line to pass a retain message to spareString to see if that would prevent the crash, which it does not.
My sense of logic virtually never fails me. However, in this case, the vastness of the code is overwhelming my mental capacity to retain all of the information. Due to the details mentioned in the previous paragraph, my logic tells me that if the external code all follows the convention that all functions return an autoreleased object (except for alloc) then the above crash is impossible.
If the crash were due to a fault in my code elsewhere, then memory calls of some kind should show up in ObjectAlloc when searching for the address of the object that causes the crash.
This leads me to believe that the crash is not my fault, but if that were the case, someone else should have come across the problem. I have no evidence that says the crash is due to bad programming on my part. I also have no evidence to say that it's not.
For anyone that's interested, this is the project I'm working on (and it's the definition of the e constant that is bringing it down):
http://homepage.mac.com/whschultz/vectorcalc/index.html
I'm working on 1.0b5, which adds the ability to edit the expression directly in the tree. Unfortunately, this was nearing completion and I ran across a different autorelease crash. So, I did some more research on memory management, and I checked my code. I realized that I hadn't been following proper procedure, so I went back through all of my code and changed it as seemed appropriate. After doing so, my program would no longer launch. After systematically removing autorelease commands, I narrowed the crash down to the specific function. So, I started hunting through Apple's tools to see if any of them would help me find a specific object or line of code that was causing the crash. Then, I found the NSString, but oddly, could not find a reason for the crash. After several days of searching, I came to the conclusion that the NSString crash is a side effect, rather than a cause, which really threw a wrench in it... and now here I am.

(Last edited by Detrius; Apr 7, 2004 at 09:40 PM.
)
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Dec 2000
Location: Chicago, Illinois
Status:
Offline
|
|
First thing, you shouldn't start your classes with lower case letters - it's bad style
laExpression => LAExpression
Second, I'm betting then something really weird is happening in the init method for your LAExpression class. That's just a hunch, but it's hard to debug without some code... could you make a sample stub code project that causes this error?
Matt Fahrenbacher
|
|
|
| |
|
|
|
 |
|
 |
|
Addicted to MacNN
Join Date: Nov 2002
Location: Seattle, WA
Status:
Offline
|
|
Originally posted by Detrius:
I realized that I hadn't been following proper procedure, so I went back through all of my code and changed it as seemed appropriate.
my first instinct is to say you probably had a release on one of those once and now it's being auto-released and the stray release is now causing problems. To find such a case I would subclass -retain, -release and -dealloc and just NSLog some relevant info and call super. You might also want to give each instance of your object a unique number and put that number there too. Something might jump out at you by reading those print outs. Also if you really think the problem is isolated to this object, you will be very well served by building a much simpler app that only uses this object and see if you can still reproduce the problem (then it will be much easier to track down)
|
|
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
Originally posted by Uncle Skeleton:
my first instinct is to say you probably had a release on one of those once and now it's being auto-released and the stray release is now causing problems. To find such a case I would subclass -retain, -release and -dealloc and just NSLog some relevant info and call super. You might also want to give each instance of your object a unique number and put that number there too. Something might jump out at you by reading those print outs. Also if you really think the problem is isolated to this object, you will be very well served by building a much simpler app that only uses this object and see if you can still reproduce the problem (then it will be much easier to track down)
I did actually do this on the laExpression class. I even implemented my own retain count in such a way that took autorelease into account, and it would drop a note to the log or stop the program in debug mode when I released/autoreleased beyond what the retain count would allow. Still no problems found. It can be difficult to observe every single object created when there may be hundreds of them.
As far as building a smaller project to test a smaller portion of the code, I think that's the best idea yet. I'll have to try that in the next few days.
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
New information:
Elsewhere in this laExpression class, I have been using the NSNotification center to pass messages to whomever needs to know when the object has changed. On a whim, I took this out (thus breaking functionality, but it is just a whim).
As a result, the program is no longer crashing at the NSString. However, now it is crashing at an NSNumber that is used in the laExpression super class, laValue. Again, the same situation applies: According to the ObjectAlloc tool, this NSNumber is autoreleased and then retained, but it is still crashing in the NSAutoReleasePool. I have managed to find this object using the debugger at the moment before it brings the program down, and indeed, it is no longer there.
This leads me to believe that somehow, I have seriously messed up somewhere and I am clobbering my own memory space. Unfortunately, it appears that this NSNumber crash, like the NSString crash, is just a side effect.
Any ideas on how something like this could happen?
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
|
 |
|
Mac Elite
Join Date: Sep 2000
Location: Tempe, AZ
Status:
Offline
|
|
Maybe you should take a look at the stuff in NSDebug.h and search Apple's developer site for MallocDebug. These are both helpful in tracking down these types of issues.
|
Geekspiff - generating spiffdiddlee software since before you began paying attention.
|
| |
|
|
|
 |
|
 |
|
Professional Poster
Join Date: Apr 2001
Location: Long Beach, CA
Status:
Offline
|
|
Some closure here... apparently, ObjectAlloc isn't a program you can rely on to give you details about why your program crashed. The thing that I finally had to do is print out all of the suspicious files and go through them line by line with a highlighter. I finally found this:
+ (laValue *)withString:(NSString *)theString
{
laExpression *theValue = [[super withString:theString] retain];
laExpression *output = [[[laExpression alloc] init] autorelease];
output->theType = theValue->theType;
output->value = theValue->value;
[theValue release];
return output;
}
and changed it to this:
+ (laValue *)withString:(NSString *)theString
{
laExpression *theValue = [[super withString:theString] retain];
laExpression *output = [[[laExpression alloc] init] autorelease];
output->theType = theValue->theType;
output->value = [theValue->value retain];
[theValue release];
return output;
}
I'm still working on finding other similar issues in other files. There was, by the way, another similar transfer of data that did not have a transfer of ownership in this specific file that was bringing the program down, but the NSString had nothing to do with it.
|

ACSA 10.4/10.3, ACTC 10.3, ACHDS 10.3
|
| |
|
|
|
 |
 |
|
 |
|
|
|
|
|

|
|
 |
Forum Rules
|
 |
 |
|
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
|
HTML code is Off
|
|
|
|
|
|
 |
 |
 |
 |
|
 |
|