Understated Ur-Drakon Celtic Minstrel Posted April 10, 2009 Posted April 10, 2009 I'm trying to work on the Mac Blades a little, but I've run into a few problems. First, it can't seem to find the scenarios, and I can't understand why since there seems to be nothing wrong with my code. Second, after informing me that there are no scenarios installed, it crashes. I can't locate where exactly the crash is occurring, but it's SIGSEGV, which I think means access violation. And last but certainly not least, I can't debug it. The debugger gives me a "Bad CPU type in executable" error. I suspect that this is because it's compiled as a PPC application, which is odd, because the Architecture setting clearly says "i386". I can't seem to get either an Intel or a Universal application for some reason. If I can resolve the third problem, I may be able to figure out the first two. Does anyone have any ideas? Quote
Well-Actually War Trall Ishad Nha Posted April 11, 2009 Posted April 11, 2009 If it can't find custom scenarios, that was a problem on the Windows version. If it can't find any scenarios at all, where is it looking? Quote
Rotghroth Rhapsody Chokboyz Posted April 11, 2009 Posted April 11, 2009 That looks like a uninitialized or bad initialized pointer (doesn't find anything than access violation crash) ... Unfortunately, i have no way to compile the mac code to test that Chokboyz Quote
Well-Actually War Trall Niemand Posted April 11, 2009 Posted April 11, 2009 It cannot be compiled as Intel, I think, because of the many old libraries, such as Quickdraw, on which it depends. This means that generally you get to fall back on debug-by-printf. With regard to the crash: Yep, if you get a SIGSEGV or SIGTERM you almost certainly dereferenced a bad pointer. I fear I can't reproduce your crash, as the (likely different) version of the code I have lying around finds the scenarios and does okay until it claims it has an 'error 9880'. Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 I was actually trying to locate where the problem was by inserting SysBeep(1) in various locations (one at a time though). Maybe it'll help if I post the code? Code: FSRef ref;FSIterator iter;err = FSPathMakeRef((UInt8*)"Blades of Exile Scenarios/",&ref,NULL);err = FSOpenIterator(&ref, kFSIterateFlat, &iter);if (err != noErr)SysBeep(2);ItemCount numScens = 0;FSRef fileRefs[50];FSSpec files[50];//myCPB.dirInfo.ioCompletion = NULL;//myCPB.dirInfo.ioNamePtr = scen_name;//myCPB.dirInfo.ioVRefNum = start_volume;do { //myCPB.hFileInfo.ioFDirIndex = index; //myCPB.hFileInfo.ioDirID = scen_dir; //err = PBGetCatalogInfoSync(&myCPB); if(cur_entry == numScens){ err = FSGetCatalogInfoBulk(iter, 50, &numScens, NULL, kFSCatInfoNone, NULL, fileRefs, files, NULL); cur_entry = 0; } As you can see, I tried to rewrite it to use non-deprecated functions. I can't see anything wrong with the code itself: the FSRef call completes successfully, as does the following call, but the GetCatalog call returns a "no more items" error. This isn't what's causing the crash, though. I'm not sure whether the crash is related to this, but it occurs after the code runs through to the end of this function and even right back out into the switch statement in handle_startup_press(). I haven't tested further than that, so it could be almost anywhere beyond there or even in the next iteration of the event loop. The odd thing about the crash is that sometimes, instead of SIGSEGV, it simply stops responding... Quote
Well-Actually War Trall Niemand Posted April 11, 2009 Posted April 11, 2009 I would recommend printf instead of SysBeep. That way you can get out the same information that you would have gotten if you had been able to use the debugger, if with the annoyance that you have to recompile when you think of another bit of information that you want to check. One point that occurs to me: It looks like you're using a relative path as the argument to FSPathMakeRef. Are you sure that the current directory, to which your path is relative, is what you think it is? You might try using CFBundleCopyBundleURL to get a URL to the location of the application, and from there constructing an absolute path. Quote
Rotghroth Rhapsody Chokboyz Posted April 11, 2009 Posted April 11, 2009 I may be wrong, but i though FSPathMakeRef used POSIX paths : Blades of Exile Scenarios/ vs Blades of Exile Scenarios: Also, in the windows code, the custom scenario problem was caused by the program looking in the wrong directory (because an OpenFileName function changed the working directory. Hope it helps, Chokboyz Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 Originally Posted By: Niemand I would recommend printf instead of SysBeep. That way you can get out the same information that you would have gotten if you had been able to use the debugger, if with the annoyance that you have to recompile when you think of another bit of information that you want to check. But how do I see the output? Originally Posted By: Niemand One point that occurs to me: It looks like you're using a relative path as the argument to FSPathMakeRef. Are you sure that the current directory, to which your path is relative, is what you think it is? You might try using CFBundleCopyBundleURL to get a URL to the location of the application, and from there constructing an absolute path. In the project window, under Executables, I right-clicked on the app, chose Get Info, and set the working directory to "Project directory". Before doing that, it failed to find the resource files (for which I also used relative paths); now it finds them perfectly well. So unless the working directory has somehow changed since opening the resource files, that can't be the problem. Originally Posted By: Chokboyz I may be wrong, but i though FSPathMakeRef used POSIX paths :Blades of Exile Scenarios/ vs Blades of Exile Scenarios: The former is a POSIX path; the latter is the Mac Classic path format. Originally Posted By: Chokboyz Also, in the windows code, the custom scenario problem was caused by the program looking in the wrong directory (because an OpenFileName function changed the working directory. Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory? Quote
Well-Actually War Trall Niemand Posted April 11, 2009 Posted April 11, 2009 Printf prints to the console, while is the system log, viewable in Cosole.app if you're running the program stand-alone, or in XCode's console when run from within Xcode. Xcode should open the console automatically when you run the program, but if it doesn't, use Command+Shift+R. The issue with setting the working directory in the IDE is that this will make it work within the IDE, but not necessarily when it's launched by itself, such as from the Finder. You might want to test and see whether your version works this was as well or not. EDIT: I thought it might help to provide some somewhat similar and working code. Below is a chunk I added to the character editor to make it able to load the item definitions from the scenario the party is in. I wouldn't call it great code (particularly as it only reports error messages to the console where the user won't see them), but it does at least run, so maybe there's something useful in it. Click to reveal.. Code: bool load_scen_item_defs(char scen_name[256]){ OSErr err; char cPath[768]; CFBundleRef mainBundle=CFBundleGetMainBundle(); CFURLRef progURL = CFBundleCopyBundleURL(mainBundle); CFStringRef progPath = CFURLCopyFileSystemPath( progURL, kCFURLPOSIXPathStyle); CFRange findRes; if(!CFStringFindWithOptions(progPath, CFSTR("/"), CFRangeMake(0, CFStringGetLength(progPath)), kCFCompareBackwards, &findRes)){ printf( "Error: Unable to find scenario directory\n"); return(false); } CFStringRef scenPath = CFStringCreateWithFormat( NULL,NULL,CFSTR("%@/Blades of Exile Scenarios/%s"), CFStringCreateWithSubstring(NULL, progPath, CFRangeMake(0,findRes.location)),scen_name); CFStringGetCString(scenPath, cPath, 768, kCFStringEncodingUTF8); FSRef scenRef; FSPathMakeRef((UInt8*)cPath, &scenRef, false); FSIORefNum forkRef; HFSUniStr255 forkName; FSGetDataForkName(&forkName); err=FSOpenFork(&scenRef, forkName.length, forkName.unicode, fsRdPerm, &forkRef); if(err!=noErr){ printf("Unable to open scenario data\n"); return(false); } err=FSReadFork(forkRef, fsFromStart, 41942, 26400, &(item_list[0]), NULL); if(err!=noErr){ printf("Unable to read scenario data\n"); return(false); } err=FSCloseFork(forkRef); if(err!=noErr){ printf("Unable to close scenario data\n"); } return(true);} Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 Originally Posted By: Niemand The issue with setting the working directory in the IDE is that this will make it work within the IDE, but not necessarily when it's launched by itself, such as from the Finder. You might want to test and see whether your version works this was as well or not. Hmm... if launched from the Finder, would the working directory be set to the folder containing the package? That could explain why it doesn't work when I double-click it... ...but moving it into the project directory doesn't change that, so maybe not. Quote
Rotghroth Rhapsody Chokboyz Posted April 11, 2009 Posted April 11, 2009 Quote: Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory? Yup, but aren't you squishing the err value resulting from FSPathMakeRef when assigning it to the output of FSOpenIterator ? Let's imagine that FSPathMakeRef fails and ref is empty. Then FSOpenIterator has nothing to do thus doesn't return an error.Then FSGetCatalogInfoBulk is called with iter which can be absolutely everything since it hasn't been initialized ... FSOpenIterator should report an error if iter was not properly open ... Is the function working when using fullpath ? Besides, we're assuming that cur_entry is valid since we don't know where it is declared An hypothesis though, Chokboyz Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 Originally Posted By: Chokboyz Quote: Theoretically possible, but in that case wouldn't I get a "file folder not found" error when making the FSRef for the directory? Yup, but aren't you squishing the err value resulting from FSPathMakeRef when assigning it to the output of FSOpenIterator ? In that version of the code, yes, but a slightly different version revealed that FSPathMakeRef returned noErr (ie 0). Originally Posted By: Chokboyz Besides, we're assuming that cur_entry is valid since we don't know where it is declared It's declared as a short a few lines up, and initialized to 0. Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 Whoa, I imagine this is probably the cause of the crash: Quote: Blades of Exile(43576,0xa08f6830) malloc: *** error for object 0x2000: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug I just need to determine where that happens. Tomorrow, maybe. Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 I just thought – could an error like the above be caused by trying to allocate with new but deallocate with free() ? Quote
Well-Actually War Trall Niemand Posted April 11, 2009 Posted April 11, 2009 In theory yes, but likely not in practice for two reasons: Jeff almost never used C++ techniques, so I would be surprised if the program explicitly used new anywhere at all, and by default with g++ (as far as I can tell) operator new is implemented using malloc, so you might actually get away with mixing the mechanisms. My guess would be that your pointer isn't being allocated at all, it's just holding a junk value which causes trouble when you try to work with it. The fact that the pointer apparently has the rather improbable value of 0x2000 seems to me to support this idea. Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 Well, I changed one or two mallocs to new, but I never changed any frees to delete, so that's why I thought it might be that. I'll go look up all instances of malloc, new, and free, though. It's obviously one of them that caused that. (I only got that message once, though...) EDIT: It's not the source of the crash – there was only a single occurence, in a function which I suspect was not part of the original source. (a function for loading a bmp from a file) Quote
Magnificent Ornk Drakefyre Posted April 11, 2009 Posted April 11, 2009 I agree with Niemand - 0x2000 indicates that the pointer was never actually allocated, so you're trying to free something that wasn't allocated. Can't you find the crash with gdb? Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 GDB doesn't work – it gives me a "Bad CPU type in executable" error. I haven't determined what caused that message to appear, but it hasn't appeared since, so maybe it solved itself somehow. I finally figured out the cause of the SIGSEGV, though. Since I changed the type of scen_headers from scen_header_type[25] to vector<scen_header_type>, the version check immediately after calling pick_a_scen() was no longer safe because the vector may have 0 elements (if no scenarios are found). I simply shifted the code to check for scen < 0 before that instead of after. The game still fails to find the scenarios, though. I'm no closer to a solution than before, really. I took Niemand's advice and altered it to use an absolute path, but that didn't change anything. There are clearly 3 scenarios in the folder it is checking in, but they aren't being found. Quote
Rotghroth Rhapsody Chokboyz Posted April 11, 2009 Posted April 11, 2009 Print out the current directory location (i don't know what function is used on Mac, but it must have an equivalent to pwd or GetCurrentDirectory). If it's okay, it's one less possible problem. Chokboyz Quote
Understated Ur-Drakon Celtic Minstrel Posted April 11, 2009 Author Posted April 11, 2009 I'm not sure how to do that from C. It shouldn't help here, since I'm using an absolute path. The path of the scenario folder is being printed, though, and it's correct, so that does not appear to be the problem. FSOpenIterator also completes without error. It's just the catalog info call that fails, and I can't figure out why. ...Maybe I'll try putting the absolute path in as a single string literal, just to see if it'll work. Obviously that's an incredibly bad strategy, but I don't have any other ideas... EDIT: Unsurprisingly, that didn't help. Quote
Magnificent Ornk Drakefyre Posted April 11, 2009 Posted April 11, 2009 Try outputting a simple file to the scenario directory (or what the program thinks is the scenario directory), then checking the Scenario Folder for the file. Or searching for it on your HD if it's not in the scenario folder. That way you can tell whether it's a directory problem or a scenario reading problem. Quote
Rotghroth Rhapsody Chokboyz Posted April 11, 2009 Posted April 11, 2009 Quote: just the catalog info call that fails, and I can't figure out why. The function seems correct to me ... (from what i can tell from only looking at the prototype ) Is there a way to look inside iter to see if it's empty ? Apart from that, have you tested if your check if(cur_entry == numScens) was succeding ? Good luck, Chokboyz Quote
Understated Ur-Drakon Celtic Minstrel Posted April 12, 2009 Author Posted April 12, 2009 Originally Posted By: Drakefyre Try outputting a simple file to the scenario directory (or what the program thinks is the scenario directory), then checking the Scenario Folder for the file. Or searching for it on your HD if it's not in the scenario folder. That way you can tell whether it's a directory problem or a scenario reading problem. Hmm... I could probably try that... EDIT: Tried it, and the file was exactly where I would expect it to be. I called FSCreateFileUnicode(&ref, 15, name, NULL, NULL, NULL, NULL), where ref is the FSRef that I just created from FSPathMakeRef to point to the scenario directory. No error was returned, and when I checked the scenario directory, the file was there. Originally Posted By: Chokboyz Quote: just the catalog info call that fails, and I can't figure out why. The function seems correct to me ... (from what i can tell from only looking at the prototype ) Is there a way to look inside iter to see if it's empty ? Apart from that, have you tested if your check if(cur_entry == numScens) was succeding ? Good luck, Chokboyz The format of the FSIterator type is hidden, so I have no way to tell if it's valid apart from the fact that FSOpenIterator did not return an error. There are two ways I can be sure that the if(cur_entry == numScens) check is succeeding. The first is that they are both initialized to zero; the second is that the diagnostic message I placed in that if statement is being displayed. Quote
Understated Ur-Drakon Celtic Minstrel Posted April 13, 2009 Author Posted April 13, 2009 (Just so people know, this problem is still not resolved. I can enter the prefab scenarios, but it can't find them to display the custom scenario picker.) Quote
Understated Ur-Drakon Celtic Minstrel Posted April 17, 2009 Author Posted April 17, 2009 Posting here partly because it's somewhat related, partly because this problem is still not resolved (unless it resolved itself silently), and partly because if I put it in the Compiled Suggestion List it's liable to get lost quickly. I have successfully compiled the scenario editor as a Universal binary which runs successfully. (The two things preventing this from working were accessing picFrame rather than using QDGetPictureBounds or whatever it's called, and possibly also constructing the GWorlds in big-endian rather than native-endian.) It still works in ppc mode too. The only problem is that loading a scenario fails in Intel mode – it tries to locate the first town beyond the end of the file. I'm guessing this is also an endian issue; I'll look into it at some point. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.