Objective C Seg Fault that only occurs when compiler optimizations are enabled - iphone

I'm stumped trying to debug an issue on iOS that seems to only occur with Release builds which seems to implicate that the optimizer is doing something that isn't playing nicely with my code. The code that crashes is some code that is serializing some binary data into a NSMutableData instance as follows.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
_data is a NSMutableData instance. pointerAtOffset and the init method for this class is defined as follows.
- (unsigned char *)pointerAtOffset {
return ((unsigned char *)_data.mutableBytes) + _offset;
}
- (id)init {
if( self = [super init] ) {
_data = [[NSMutableData alloc] initWithCapacity:1028];
_offset = 0;
}
return self;
}
Now the strange thing is that if I add a NSLog print statement, it fixes the bug.
[_data increaseLengthBy:sizeof(CFSwappedFloat64)];
NSLog(#"%d - %d", (int)_data.mutableBytes, _offset);
*((CFSwappedFloat64 *)[self pointerAtOffset]) = CFConvertFloat64HostToSwapped(value);
_offset += sizeof(CFSwappedFloat64);
Any ideas what might be causing this? It's kind of unnerving to deploy code that works because of a NSLog statement.

This reminds me of the armv6 Thumb instruction problems. If you change your debug build settings to optimize to Fastest,Smallest and it crashes, then that is your problem.

Related

FPS Lag scheduler?

I've been getting FPS lag. I've looked around and people say to use
[self schedule:#selector(gameLoop:) interval: 1/60.0f];
When I use this I get choppy lag. but when I use
[self schedule:#selector(gameLoop:)];
It's a lot smoother. Here is a snippet of my movement code.
- (void)gameLoop :(ccTime)dt
{
[self manageCannon:dt];
[self manageBullets:dt];
[self manageEnemies:dt];
[self manageAllies:dt];
}
- (void) manageEnemies :(ccTime)dt
{
enemyClass *tempEnemy;
for(int i = 0; i < [enemies count]; i++)
{
tempEnemy = [enemyClass new];
tempEnemy = [enemies objectAtIndex:i];
tempEnemy.position = ccp(tempEnemy.position.x-tempEnemy.speed*dt,tempEnemy.position.y);
if((tempEnemy.position.x - tempEnemy.range) < [wall getwally])
{
tempEnemy.speed = 0;
}
if(tempEnemy.health < 1)
{
tempEnemy.alive = false;
}
if(tempEnemy.alive == false)
{
[enemies removeObjectAtIndex:i];
[tempEnemy removeFromParentAndCleanup:true];
}
}
}
I always try to write my own code from scratch, so if you can help me out with other things that i'm doing that is incorrect that would be very helpful towards me.
It's hard to say what is slowing down your app from the information given. As LearnCocos2D suggested, you can use Instruments to figure out where the slow stuff is. Or if you want to get very granular analysis, you can always use the following macros in your code:
#define TIC start = [NSDate date]
#define TOC -[start timeIntervalSinceNow]
#define TOCP NSLog(#"TIME: %f", TOC)
Before using, be sure to declare NSDate *start in scope of use. Then just put a series of TIC/TOC or TIC/TOCP pairs in your code to print out times your code is taking in different places. You can very quickly find the bottlenecks this way.

Why am I getting exc_bad_access errors for objectAtIndex in my floodfill algorithm

I have a flood fill function:
-(void) fillArea :(int) fillNum x:(int) xSpot y:(int) ySpot
{
int gridValue = 1;
int gridCount = [theGrid count];
[[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue];
if (gridValue != 0) {
return;
}
[theGrid replaceObjectAtIndex:(xSpot + ySpot*120) withObject:[NSNumber numberWithInt:fillNum]];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot)];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot-1)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot)];
[self fillArea:fillNum x:(xSpot-1) y:(ySpot+1)];
[self fillArea:fillNum x:(xSpot) y:(ySpot+1)];
[self fillArea:fillNum x:(xSpot+1) y:(ySpot+1)];
return;
}
theGrid is an NSMutableArray of ints (either a 0 or a 1). It is just a 1D array that simulates a 2D array by multiplying the ySpot by 120 (the width of my grid). I checked the gridCount and it is equal to 9600.
However, I get an exc_bad_access at [[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue]. I check my xSpot and ySpot when this happens and I know that (xSpot+ySpot*120) < 9600 every time. So I know it's not that I'm trying to access an object who's index is outside my array.
Futhermore, in my tick function I ran the code:
int gVal = 1;
int gIndex = 0;
while (gIndex < [theGrid count]) {
[[theGrid objectAtIndex:gIndex] getValue:&gVal];
gIndex += 1;
}
I did not get an exc_bad_access error. Please help me figure out why I'm getting an exc_bad_access error.
EDIT:
I split [[theGrid objectAtIndex:(xSpot+ySpot*120)] getValue:&gridValue]; into:
id object = [theGrid objectAtIndex:(xSpot+ySpot*widthInGridSize)];
gridValue = [object intValue];
I still get exc_bad_access and it says it is on the line:
gridValue = [object intValue];
So I assume this means object has already been released? I don't understand how that's possible. I thought ints didn't need to be retained in any way since they're just ints. Also I thought adding an object to an array automatically retained it so why would my int get released.
In the debug section the value of object is said equal: (_NSCFNumber *) 0x005aec80 (int) 0
As per comments - this isn't actually an out of bounds issue, but rather the object you're pulling out of 'theGrid' is bogus (already released). Break that into multiple lines to confirm; and turn on "zombies" in your debug settings. Cheers!

accessing instance variable in cocos2d scheduled method crashes

fresh to objC and cocos2d :)
i'm following "learn cocos2d game development with iOS5", in chapter4, there is a "DoodleDrop" game.
define some variable in GameScene.h like this
#interface GameScene : CCLayer
{
CCSprite *player;
CGPoint playerVelocity;
CCArray *spiders;
CGSize screenSize;
int dropedSpidersCount;
float duration;
}
+ (CCScene *)scene;
#end
in GameScene.m the init method looks like this
- (id)init
{
if (self = [super init]) {
duration = 4.0;
[self createPlayer];
[self createSpiders]; // spiders were inited here.
[self resetSpiders];
[self schedule:#selector(chooseSpider:) interval:0.7];
}
return self;
}
while in chooseSpider, i cannot access spiders, xcode broke
in other methods, spiders or duration just behave normally, why does this happens?
gist code added
https://gist.github.com/2940466
After inspecting your code, I suggest you to try this fix:
- (void)createSpiders
{
CCSprite *tempSpider = [CCSprite spriteWithFile:#"spider.png"];
CGSize spiderSize = [tempSpider texture].contentSize;
int spiderCount = screenSize.width / spiderSize.width;
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
for (int i = 0; i < spiderCount; i++) {
CCSprite *spider = [CCSprite spriteWithFile:#"spider.png"];
[self addChild:spider];
[spiders addObject:spider];
}
}
where the only difference is in the line:
spiders = [[CCArray arrayWithCapacity:spiderCount] retain];
Indeed, if you do not retain you spiders object, it will be autoreleased at the next run loop iteration.
OLD ANSWER:
Without seeing more code it is not possible to say exactly what is happening, but it seems that in the interval between creating the spiders and the actual execution of chooseSpiders, your spiders array gets deallocated.
As a quick try, I would suggest adding:
[spiders retain];
before calling
[self schedule:#selector(chooseSpider:) interval:0.7];
and see wether the crash keeps happening.
if you provide more code, it could be possible to help you further.

App Crashing When Calling Release on Autorelease Pool - Timing Issue ? iPhone

I have the following method in my app :
- (void) loadModel {
// Runs in a seperate thread so we need to create an additional NSAutoreleasePool
pool = [[NSAutoreleasePool alloc] init];
NSData *getData = [activeModelInfo getFileData];
if (getData) {
if ([activeModel loadFromFileData:daeData]) {
[activeModel reset];
[mainViewController performSelectorOnMainThread:#selector(showModelView) withObject:nil waitUntilDone:NO];
}
else {
}
}
else {
}
[pool release];
}
The loadFromFileData method calls the following code which loads data. :
- (void) loadVerticesFromSource:(NSString*)verticesSourceId meshNode:(TBXMLElement*)meshNode intoMesh: (Mesh3D*) mesh {
NSLog(#"Getting Vertices for Source %#",verticesSourceId);
FloatArray *floatArray = [self getFloatArrayFromSource: verticesSourceId meshNode: meshNode];
if (floatArray) {
[daeFloatArray addObject:floatArray];
}
if (floatArray) {
if ([floatArray.array count] % 3 != 0) {
NSLog(#"Float array length not divisible by 3!");
}
else {
mesh->verticesCount = [floatArray.array count] / 3;
mesh->vertices = malloc(sizeof(Vector3D) * mesh->verticesCount);
for (int i=0; i<mesh->verticesCount; i++) {
mesh->vertices[i].x = [[floatArray.array objectAtIndex:(i*3)] floatValue];
mesh->vertices[i].y = [[floatArray.array objectAtIndex:(i*3)+1] floatValue];
mesh->vertices[i].z = [[floatArray.array objectAtIndex:(i*3)+2] floatValue];
// update extents information
if (!extents.pointDefined || mesh->vertices[i].x < extents.minX) extents.minX = mesh->vertices[i].x;
else if (!extents.pointDefined || mesh->vertices[i].x > extents.maxX) extents.maxX = mesh->vertices[i].x;
if (!extents.pointDefined || mesh->vertices[i].y < extents.minY) extents.minY = mesh->vertices[i].y;
else if (!extents.pointDefined || mesh->vertices[i].y > extents.maxY) extents.maxY = mesh->vertices[i].y;
if (!extents.pointDefined || mesh->vertices[i].z < extents.minZ) extents.minZ = mesh->vertices[i].z;
else if (!extents.pointDefined || mesh->vertices[i].z > extents.maxZ) extents.maxZ = mesh->vertices[i].z;
if (!extents.pointDefined) extents.pointDefined = YES;
[pointerStorageArray addObject:[NSValue valueWithPointer:mesh->vertices]];
}
}
}
}
Since this method is called several times while the data loads, each time mallocing memory for the mesh->vertices struct, I have created a pointerStorage array where I store the pointer to the malloced memory.
The app then displays a 3D object using OpenGL ES. When the user presses a Main Menu button, I then free up the pointerStorageArray as follows :
- (void) freeUpMallocedMemory
for (NSValue * value in pointerStorageArray) {
free(value);
}
The problem is that the app then crashes during this process. All I get is the EXC_BAD_ACCESSS error message and a pointer to the following line of code in the loadModel method above :
[pool release];
Nothing in the stack trace. I have also tried turning on NSZombie, NSAutoreleaseTrackFreedObjectCheck and NSDebugEnabled, but I still don't get any additional information.
The odd thing is that if I put a delay on the button of 2 seconds (i.e only trigger the freeUpMallocedMemory method after 2 seconds), the app no longer crashes and works fine.
Can anyone suggest what might be causing this - really confused and have already spent a few days troubleshooting.
Thank you !
You are over-releasing... the values in pointerStorageArray are created via a convenience method and as such don't need releasing, simply removing them from the array will dispose of them.

Memory Leak question

I am having a memory leak issue with the following code. As much as I can tell I don't see why the problem persists but it still does not release when called. I am detecting the problem in instruments and the following code is keeping its "cards" classes alive even when it should had released them.
Any help welcome.
...
...
-(id)initDeckWithCardsPicked: (NSMutableArray*)cardsPicked andColors:(NSMutableArray*)cardColors
{
self = [self init];
if (self != nil) {
int count = [cardsPicked count];
for (int i=0; i<count; i++) {
int cardNum = [[cardsPicked objectAtIndex:i] integerValue];
Card * card = [[MemoryCard alloc] initWithSerialNumber:cardNum position: CGPointZero color:[cardColors objectAtIndex:i]];
[_cards addObject: card];
[card release];
}
}
return self;
}
- (id) init
{
self = [super init];
if (self != nil) {
self.bounds = (CGRect){{0,0},[Card cardSize]};
self.cornerRadius = 8;
self.backgroundColor = kAlmostInvisibleWhiteColor;
self.borderColor = kHighlightColor;
self.cards = [NSMutableArray array];
}
return self;
}
...
...
Without looking at the rest of your code, its hard to know where the problem is, but have you tried using the static analyzer in xcode? Its can be invaluable for finding memory leaks.
To use it, select 'Build and Analyze' from the Build menu. Further details are on Apple's dev website.
When you add a Card to the _cards NSMutableArray using addObject, it is sent a retain message. Thus, as long as you keep _cards in memory, a pointer will also be kept for each of it's constituents. As long as your dealloc releases the array, or you do so elsewhere, you shoul dbe fine with what you have posted here (assuming your initWithSerialNumber method returns a retained object).