From: <cod...@go...> - 2009-08-20 23:09:53
|
Revision: 408 Author: wol...@gm... Date: Thu Aug 20 16:09:05 2009 Log: On GNUstep, clean up the stack frame chain in Invocation.m:callWithExceptions When the FFI call from Haskell to callWithExceptions() is made, %ebp contains not a stack frame link but rather some other value. When GNUstep's NSException tries to walk the stack to generate a stack trace, it segfaults. Therefore, we use GCC's __builtin_frame_address to retrieve the saved frame pointer value, save it elsewhere and reset the stack frame link to 0 so that GNUstep's stack trace just stops there. It is reset to the stored value upon exit. Fixes issue #19. http://code.google.com/p/hoc/source/detail?r=408 Modified: /trunk/hoc/HOC_cbits/Invocation.m ======================================= --- /trunk/hoc/HOC_cbits/Invocation.m Sat Jan 5 08:46:39 2008 +++ /trunk/hoc/HOC_cbits/Invocation.m Thu Aug 20 16:09:05 2009 @@ -8,10 +8,37 @@ NSException *callWithExceptions(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { +#ifdef GNUSTEP + // GHC messes up the stack frame chain. + // GNUstep generates exception stack traces on the assumption + // that the stack frame chain makes sense. + // Therefore, we move the frame pointer value left behind by + // GHC from its regular stack slot into a local variable and + // set the stack-frame link to 0 (temporarily). + + void **frame = __builtin_frame_address(0); + void *save = *frame; + + // We assume that + // *(void**)__builtin_frame_address(0) == __builtin_frame_address(1) + // which is true at least for i386, x86_64 and powerpc[64]. + assert(save == __builtin_frame_address(1)); + + *frame = 0; +#endif + + NSException *exception = nil; NS_DURING ffi_call(cif, fn, rvalue, avalue); NS_HANDLER - return localException; + exception = localException; NS_ENDHANDLER - return nil; -} + +#ifdef GNUSTEP + // restore old stack frame link + *frame = save; +#endif + + return exception; +} + |