Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
I modified this down since i don't have nibs/xibs. The while(1) is to just keep the main thread alive while the second one does its thing. This can be saved and compiled as a single source file. You'll need to create a file in your MapPathString path. I called mine S32W4t5.hgt, based on what the code was doing. The OP didn't say anything about the data files. This code does memory management totally wrong, but whatever. That's not the problem, it looks mostly like over-retaining. This does not crash for me.

I certainly don't know why it's crashing for you, but I'd try something similar. Hard-code your paths instead of getting from the GUI and see if you get a crash. If you still do, one less thing to worry about. Trim out the unnecessary parts until you have a very small example that still crashes. If it is getting things from the GUI... well, at least you know that's where things are going awry.

Code:
#import <Foundation/Foundation.h>
#import <dirent.h>
#import <Cocoa/Cocoa.h>

@interface GUI : NSObject {
	NSString        *MapPathString;
	NSString        *OutputPathString;
	float            totalFiles;
	int              currentFile;
	
}

- (void) StartMapGen;

- (void) processThread;                                 
- (void) process3ArcSecondMapFile:(NSString*)inFile lat: (int)lat lon:(int)lon outPath:(NSString*) outPath;                                
@end



@implementation GUI

- (void) StartMapGen 
{
	MapPathString = @"/";
	OutputPathString = @"/Users/";
	currentFile = 0;
	totalFiles = 0;
	
	[MapPathString retain];
	[OutputPathString retain];
	
	DIR *pdir;
	struct dirent *entry;
	NSLog(@"Map path: %@",MapPathString);
	pdir = opendir([MapPathString UTF8String]);
	if (pdir) {
		entry = readdir(pdir);
		NSLog(@"Processing entry %p!",entry);
		while (entry) {
			NSLog(@"The name: %s",entry->d_name);
			if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
				NSLog(@"Incrementing!");
				totalFiles++;
			}
			entry = readdir(pdir);
		}
		
		closedir(pdir);
		
		if (totalFiles > currentFile) {
			NSLog(@"Calling detach!");
			[NSThread detachNewThreadSelector:@selector(processThread) 
									 toTarget:self 
								   withObject:nil];
			while (1) {
				
			}
		}
	}
}

- (void) processThread{
	NSLog(@"In processThread!");
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	DIR *pdir;
	struct dirent *entry;
	NSString *outPath = [[NSString alloc] initWithString:OutputPathString];
	[outPath retain];
	
	pdir = opendir([MapPathString UTF8String]);
	NSLog(@"About to read: %@",MapPathString);
	if (pdir) {
		entry = readdir(pdir);
		while (entry) {
			if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
				if (!strncmp(entry->d_name + (strlen(entry->d_name) - 4), 
							 ".hgt", 4)) {          
					int lat, lon;
					char tmp[4];
					
					tmp[0] = entry->d_name[1]; tmp[1] = entry->d_name[2]; tmp[2] = '\0';
					lat = ((entry->d_name[0] == 'S') ? -1: 1) * atoi(tmp);
					
					tmp[0] = entry->d_name[4]; tmp[1] = entry->d_name[4]; 
					tmp[2] = entry->d_name[6]; tmp[3] = '\0';
					lon = ((entry->d_name[3] == 'W') ? -1: 1) * atoi(tmp);
                    
					lon = (360 + lon) % 360;
					lat = (90 - lat) % 180;
					
					NSString *inFilePath = [[NSString alloc] initWithFormat:@"%@/%s",
											MapPathString, entry->d_name];
					[inFilePath retain];
					NSLog(@"About to call!");
					//At this point all NSString values & ints are what I expect them to be.
					[self process3ArcSecondMapFile: inFilePath lat:lat lon:lon outPath:outPath];
					[inFilePath release];
					NSLog(@"And we're back!");
				}
			}
			currentFile++;
			entry = readdir(pdir);
		}
		closedir(pdir);
	}
	
	[MapPathString release];
	[OutputPathString release];
	[outPath release];
	[pool drain];
}

- (void) process3ArcSecondMapFile:(NSString*)inFile lat: (int)lat lon:(int)lon outPath:(NSString*) outPath
{  // Crashes at this LINE with EXC_BAD_ACCESS, inFile and outPath invalid.
	NSLog(@"The in: %@, the lat: %d, the lon: %d, the out: %@",inFile,lat,lon,outPath);
	int a = 0;
	a++;
	
	
}

@end

int main(int argc, char *argv[])
{
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	GUI *myGUI = [[GUI alloc] init];
	[myGUI StartMapGen];
	[pool drain];
}

-Lee
 

chown33

Moderator
Staff member
Aug 9, 2009
10,750
8,422
A sea of green
Code:
main.m

int main(int argc, char *argv[])
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  return NSApplicationMain(argc,  (const char **) argv);
  [pool drain];
}
That's not the normal idiom for a non-GC Cocoa GUI app.

This is:
Code:
int main(int argc, char *argv[])
{
  return NSApplicationMain(argc,  (const char **) argv);
}


I agree with lee1210: strip it down to an isolated fail case. If that requires xib/nib files, then zip the project and upload it. To solve the problem, someone has to replicate the problem.


EDIT:
You can eliminate the opendir(), readdir() stuff by using NSFileManager. It has a few methods for listing directories. You can get an enumerator or an NSArray of strings.
 
Last edited:

jared_kipe

macrumors 68030
Dec 8, 2003
2,967
1
Seattle
I have modified your two functions. The first one is just to allow the program to actually finish when the thread is done. It took me a little while to figure out why it seemed to stop logging but was still running.

Code:
- (void) StartMapGen 
{
	MapPathString = @"/";
	OutputPathString = @"/Users/";
	currentFile = 0;
	totalFiles = 0;
	
	[MapPathString retain];
	[OutputPathString retain];
	
	DIR *pdir;
	struct dirent *entry;
	NSLog(@"Map path: %@",MapPathString);
	pdir = opendir([MapPathString UTF8String]);
	if (pdir) {
		entry = readdir(pdir);
		NSLog(@"Processing entry %p!",entry);
		while (entry) {
			NSLog(@"The name: %s",entry->d_name);
			if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
				NSLog(@"Incrementing!");
				totalFiles++;
			}
			entry = readdir(pdir);
		}
		
		closedir(pdir);
		
		if (totalFiles > currentFile) {
			NSLog(@"Calling detach!");
			NSThread *t = [[NSThread alloc] initWithTarget:self selector:@selector(processThread) object:nil];
			[t start];
			while ([t isExecuting]) {
				
			}
			[t release];
		}
	}
}

The second was because I realized whatever was going on with that loop was specific to your programs function and didn't seem to be actually doing anything on my computer. So I wrapped a little comment around it and sorta duplicated the supposedly dangerous call. (Since I don't have lon or lat I substituted (int)currentFile and 0...
Code:
- (void) processThread{
	NSLog(@"In processThread!");
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	DIR *pdir;
	struct dirent *entry;
	NSString *outPath = [[NSString alloc] initWithString:OutputPathString];
	[outPath retain];
	
	pdir = opendir([MapPathString UTF8String]);
	NSLog(@"About to read: %@",MapPathString);
	if (pdir) {
		entry = readdir(pdir);
		while (entry) {
			/*
			if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) {
				if (!strncmp(entry->d_name + (strlen(entry->d_name) - 4), 
							 ".hgt", 4)) {          
					int lat, lon;
					char tmp[4];
					
					tmp[0] = entry->d_name[1]; tmp[1] = entry->d_name[2]; tmp[2] = '\0';
					lat = ((entry->d_name[0] == 'S') ? -1: 1) * atoi(tmp);
					
					tmp[0] = entry->d_name[4]; tmp[1] = entry->d_name[4]; 
					tmp[2] = entry->d_name[6]; tmp[3] = '\0';
					lon = ((entry->d_name[3] == 'W') ? -1: 1) * atoi(tmp);
                    
					lon = (360 + lon) % 360;
					lat = (90 - lat) % 180;
					
					NSString *inFilePath = [[NSString alloc] initWithFormat:@"%@/%s",
											MapPathString, entry->d_name];
					[inFilePath retain];
					NSLog(@"About to call!");
					//At this point all NSString values & ints are what I expect them to be.
					[self process3ArcSecondMapFile: inFilePath lat:lat lon:lon outPath:outPath];
					[inFilePath release];
					NSLog(@"And we're back!");
				}
			}*/
			NSString *inFilePath = [[NSString alloc] initWithFormat:@"%@/%s",
									MapPathString, entry->d_name];
			NSLog(@"About to call!");
			[self process3ArcSecondMapFile: inFilePath lat:currentFile lon: 0 outPath:outPath];
			[inFilePath release];
			NSLog(@"And we're back!");
			currentFile++;
			entry = readdir(pdir);
		}
		closedir(pdir);
	}
	
	[MapPathString release];
	[OutputPathString release];
	[outPath release];
	[pool drain];
}

It runs and concludes just fine for me. Leading me to believe that the commented logic is faulty. Which wouldn't surprise me, all those ->'s and [#] with no checks to see if they aren't NULL

Anyway, here is a little output section of my run log.

Code:
2010-12-10 09:16:29.776 ThreadCrash[15597:1503] About to call!
2010-12-10 09:16:29.776 ThreadCrash[15597:1503] The in: //Users, the lat: 30, the lon: 0, the out: /Users/
2010-12-10 09:16:29.776 ThreadCrash[15597:1503] And we're back!
2010-12-10 09:16:29.777 ThreadCrash[15597:1503] About to call!
2010-12-10 09:16:29.777 ThreadCrash[15597:1503] The in: //usr, the lat: 31, the lon: 0, the out: /Users/
2010-12-10 09:16:29.777 ThreadCrash[15597:1503] And we're back!
2010-12-10 09:16:29.777 ThreadCrash[15597:1503] About to call!
2010-12-10 09:16:29.778 ThreadCrash[15597:1503] The in: //var, the lat: 32, the lon: 0, the out: /Users/
2010-12-10 09:16:29.778 ThreadCrash[15597:1503] And we're back!
2010-12-10 09:16:29.778 ThreadCrash[15597:1503] About to call!
2010-12-10 09:16:29.779 ThreadCrash[15597:1503] The in: //Volumes, the lat: 33, the lon: 0, the out: /Users/
2010-12-10 09:16:29.779 ThreadCrash[15597:1503] And we're back!

EDIT: Looks like I was mostly beaten to the punch. Thats what I get for making coffee and breakfast while replying/fixing some code.
 

Aumnayan

macrumors newbie
Original poster
Dec 4, 2010
9
0
Okay, I've found what was causing the problem, but I don't know WHY it should be causing this problem.

Within the function fun1, or process3ArcSecondMapFile, whichever snippet you look at, I was declaring 3 variables:
Code:
short rawArray[1201][1201];
short procArray[1200][1200];
unsigned char gradOff[1200][1200];
I didn't catch these definitions when I #ifdef'ed out the code of the function, but did get deleted when I posted the last snippet.

Simply having this ~7MB declared was causing the problem. Putting this chunk of memory on the heap via standard C memory allocation routines fixed the problem.

So I guess the question I have now is: Why would allocating this memory on the stack cause such a problem? It wasn't caused by accessing the memory incorrectly, if it was I would expect the error to exist at the location I messed up the dereferencing or immediately thereafter, not on entering the function.

Thanks to everyone who helped.
 

Sydde

macrumors 68030
Aug 17, 2009
2,552
7,050
IOKWARDI
Simply having this ~7MB declared was causing the problem. Putting this chunk of memory on the heap via standard C memory allocation routines fixed the problem.

So I guess the question I have now is: Why would allocating this memory on the stack cause such a problem?
A look at the docs on threading would explain it. The default stack size for a secondary thread using the +detach… method is 512Kb.

You could configure a larger stack by creating the thread before starting it (if you are writing for 10.4, you would have to use pthreads). Alternately, you could create a different object specifically for performing the operation on the secondary thread, with the huge arrays as ivars (thus making deallocation concise).

But mostly, you could post your code verbatim, so that it can be debugged by the people you ask for help.
 
Last edited:

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Okay, I've found what was causing the problem, but I don't know WHY it should be causing this problem.

Within the function fun1, or process3ArcSecondMapFile, whichever snippet you look at, I was declaring 3 variables:
Code:
short rawArray[1201][1201];
short procArray[1200][1200];
unsigned char gradOff[1200][1200];
I didn't catch these definitions when I #ifdef'ed out the code of the function, but did get deleted when I posted the last snippet.

Simply having this ~7MB declared was causing the problem. Putting this chunk of memory on the heap via standard C memory allocation routines fixed the problem.

So I guess the question I have now is: Why would allocating this memory on the stack cause such a problem? It wasn't caused by accessing the memory incorrectly, if it was I would expect the error to exist at the location I messed up the dereferencing or immediately thereafter, not on entering the function.

Thanks to everyone who helped.

The stack and heap grow in opposite directions. If you smash through the boundary on the stack (just "pushing" the 7-8MB stack frame will do it) you're now in the heap in an area that wasn't allocated to you.

Obviously you omitted the most important part of the code. In the future it would be ideal to post, verbatim, all of your files. Zipping your project including nibs/xibs would be best. So often we get the "relevant" part of the code, and with memory issues often you don't know what the relevant part is. If you did, you could probably fix it.

I'm guessing if we'd seen 7MB of automatic storage it would have been an instant red flag. Instead 6 days transpired before you ultimately straightened it out yourself.

-Lee
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.