UB external runs fine ppc and PC crashes Intel Mac
Greetings to all... I am new to developing Max externals, and a relatively inexperienced C programmer. That said, I'm trying to develop a set of simple objects for use with Just Intonation, and have been cheerfully coding away over the past weeks until I hit a strange snag. My latest object compiles successfully in Xcode 2.5 (this works on both PPC G4 and on Mac Intel platforms), producing a universal binary object which loads on both platforms. (It also works on PC and on a G5). On the PPC it does exactly what it should, and on an Intel Mac it crashes as soon as it receives a number in inlet 1.
I've isolated what causes the crash, and it is a very simple subroutine that performs a search, given a starting input value (t) and a test value (l). The bit of code looks like this:
int ftti_searchdown(int t, int l)
/* brute-force search downwards matches within prime limit (l) or returns -1 */
{
int check, t_in;
t_in=t;
if (t > 0) {
t--;
check = ftti_TIpl(t);
/* ftti_TIpl returns values from a lookup table of prime limit values which range between 1 and 23 */
while ((check > l)&&(t > 0)) {
t--;
check = ftti_TIpl(t);
}
}
if (t == t_in) {
t = -1;
}
return t;
/* search returns -1 if it failed */
}
If there is anyone willing to check this out, I would appreciate any suggestions. I've attached a zip archives, containing my Xcode project folder, the compiled external, a test patch and a crash report.
best regards and many thanks in advance
Marc
PS subfolders:
ftti-sabat has the external, a test patch, and the crash report
ffti-xcode is my source code file ftti.c and related files: Info.plist, ftti.xcodeproj, ftti.def
Hi Marc,
I'm not sure how you've narrowed this down, as I can't get any useful info from a crash log...
Anyway if you compile it under the development configuration (optimisation off) it runs fine under intel. If you set any other optimisation mode then it crashes - so it seems like the problem is something that gcc is doing to your code when it optimises it....
I suppose it's possible that this is a bug in gcc, I'm not really sure. Probably to track this further you need to read the assembly code or whatever that gcc is spitting out, and debug it there. I can't help there unfortunately.
Possibly someone who knows more can say something more helpful, but at least you have the option of just turning optimisation off for now and working round it that way..
Regards,
Alex
Thank you for the optimization tip, I've recompiled and will wait to hear from my beta testing Intel users. Strange bug, good to know there is a way out...
many thanks
Marc
Hi,
Could you post the resolution for this? Marc's responses weren't included. Posting the resolution details would help to make sure that someone doesn't have to hunt for the answer in the future.
thanks
_Mark
Quote: Mark Pauley wrote on Mon, 04 February 2008 16:27
----------------------------------------------------
> Hi,
> Could you post the resolution for this? Marc's responses weren't included....
There's nothing missing here. The thread in the forum shows all the correspondence. To clarify - the (possible) workaround for now is:
Turn optimisations OFF in XCode in the deployment configuration.
Recompile.
It works on my machine at least. But this is not a resolution really, just a workaround. It seems that gcc compiles duff code when optimisation is on for this particular source file. This may be a bug in gcc. There is perhaps a way to alter the source code to avoid this, or if someone locates a bug in gcc due to this then maybe it'll get fixed for the next version, but at the moment this is simply a way to try to get the external to work on the intel platform...
Alex
In ftti_TIpl() you declare a 121-element int array and fill it with 122 values.
int TIpl[121];
.
.
TIpl[121]=7;
The declaration means you can use the indices 0 to 120. Writing to the array element TIpl[121] is an error. The element doesn't exist. You need to declare your array as having 122 elements if you want to do that. In the optimized build that write is probably screwing up a return address or something.
Over and above, your implementation is rather inefficient. You should have the implementation of isalpha() & Co somewhere in the XCode libraries. It is worth studying for a more efficient and idiomatic approach.
Basically you want to define the array globally, outside your function, something like
enum { kArraySize = 121 };
// A lot of people do this as a #define, but
// I prefer using compiler constants.
int TIpl[kArraySize] = {1, 3, 5, 7, //etc.etc.
};
.
.
.
int ftti_TIpl(int n) /* lookup prime limit values */
{
int res=1;
if (n >= kArraySize) {
res = 7;
}
else if (n > 0) {
res = TIpl[n];
}
return res;
}
Hardcore C programmers will do it even more compactly, for instance
{
return (n >= kArraySize) ? 7 : (n >= 0) ? TIpl[n] : 1;
}
Thanks for these -- found the 121 bug late yesterday night and am currently thinking over about how to structure the array globally as you suggest. I would very much appreciate any shortcuts for the snaky "find" subroutine I wrote which seems very "case-by-case" with far too many logical "if" clauses.
My basic problem : given a rising lookup-table, I want to locate the index of the nearest and next-nearest fit to a target value. Then use the index to lookup other data. There must be a library of efficient algorithms for such a standard type of search? Any further thoughts would be kindly appreciated!
Thanks
Marc
Long term, I'd suggest "Algorithms + Data Structures" by Nick Wirth and Jon Benley's "Programming Pearls". Lots of ideas in both on writing efficient code. Both are old, Wirth's book is very Pascal oriented, neither of which is not necessarily a bad thing in my book. Both Wirth & Bentley talk about binary search.
Off hand, by convention chained else-if statements do not indicated additional indentation (your ifs aren't nested, they're chained). That would already make your code look less complex. Not having analyzed your code in detail, but you may find that breaking the input value into integer and fractional parts could streamline your code. You can then switch() on the integer part and inside each case block do an if(fractPart > 0.0) {} else {}.
You can test at the beginning of your search function for out-of-range input, set flags & do a quick return. Then focus on the core of your search in the main body of your routine. That can also streamline your code.
Hope this helps,
Peter