hould be fix for bug #22514

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@26315 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
rfm 2008-03-16 18:17:49 +00:00
parent 68e50feb65
commit 22436d0c17
2 changed files with 65 additions and 79 deletions

View file

@ -1,3 +1,8 @@
2008-03-16 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSDebug.m: Trap sigbus if gcc functions to get stack frame
info run off the end of the stack.
2008-03-16 Richard Frith-Macdonald <rfm@gnu.org> 2008-03-16 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSArray.m: * Source/NSArray.m:

View file

@ -856,8 +856,10 @@ GSDebugMethodMsg(id obj, SEL sel, const char *file, int line, NSString *fmt)
return message; return message;
} }
#define _NS_FRAME_HACK(a) case a: val = __builtin_frame_address(a + 1); break; #define _NS_FRAME_HACK(a) \
#define _NS_RETURN_HACK(a) case a: val = __builtin_return_address(a + 1); break; case a: env->addr = __builtin_frame_address(a + 1); break;
#define _NS_RETURN_HACK(a) \
case a: env->addr = __builtin_return_address(a + 1); break;
/* /*
* The following horrible signal handling code is a workaround for the fact * The following horrible signal handling code is a workaround for the fact
@ -877,7 +879,14 @@ GSDebugMethodMsg(id obj, SEL sel, const char *file, int line, NSString *fmt)
#include <setjmp.h> #include <setjmp.h>
#endif #endif
static jmp_buf * typedef struct {
jmp_buf buf;
void *addr;
void (*bus)(int);
void (*segv)(int);
} jbuf_type;
static jbuf_type *
jbuf() jbuf()
{ {
NSMutableData *d; NSMutableData *d;
@ -885,37 +894,30 @@ jbuf()
d = [[[NSThread currentThread] threadDictionary] objectForKey: @"GSjbuf"]; d = [[[NSThread currentThread] threadDictionary] objectForKey: @"GSjbuf"];
if (d == nil) if (d == nil)
{ {
d = [[NSMutableData alloc] initWithLength: d = [[NSMutableData alloc] initWithLength: sizeof(jbuf_type)];
sizeof(jmp_buf) + sizeof(void(*)(int)) + sizeof(void*)];
[[[NSThread currentThread] threadDictionary] setObject: d [[[NSThread currentThread] threadDictionary] setObject: d
forKey: @"GSjbuf"]; forKey: @"GSjbuf"];
RELEASE(d); RELEASE(d);
} }
return (jmp_buf*)[d mutableBytes]; return (jbuf_type*)[d mutableBytes];
} }
static void static void
recover(int sig) recover(int sig)
{ {
jmp_buf *env = jbuf(); longjmp(jbuf()->buf, 1);
longjmp(*env, 1);
} }
void * void *
NSFrameAddress(int offset) NSFrameAddress(int offset)
{ {
jmp_buf *env; jbuf_type *env;
void (*old)(int);
void *val;
env = jbuf(); env = jbuf();
if (setjmp(*env) == 0) if (setjmp(env->buf) == 0)
{ {
old = signal(SIGSEGV, recover); env->segv = signal(SIGSEGV, recover);
val = (void*)env; env->bus = signal(SIGBUS, recover);
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
switch (offset) switch (offset)
{ {
_NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2); _NS_FRAME_HACK(0); _NS_FRAME_HACK(1); _NS_FRAME_HACK(2);
@ -952,42 +954,33 @@ NSFrameAddress(int offset)
_NS_FRAME_HACK(93); _NS_FRAME_HACK(94); _NS_FRAME_HACK(95); _NS_FRAME_HACK(93); _NS_FRAME_HACK(94); _NS_FRAME_HACK(95);
_NS_FRAME_HACK(96); _NS_FRAME_HACK(97); _NS_FRAME_HACK(98); _NS_FRAME_HACK(96); _NS_FRAME_HACK(97); _NS_FRAME_HACK(98);
_NS_FRAME_HACK(99); _NS_FRAME_HACK(99);
default: val = NULL; break; default: env->addr = NULL; break;
} }
signal(SIGSEGV, old); signal(SIGSEGV, env->segv);
signal(SIGBUS, env->bus);
} }
else else
{ {
val = jbuf(); signal(SIGSEGV, env->segv);
val += sizeof(jmp_buf); signal(SIGBUS, env->bus);
memcpy(&old, val, sizeof(old)); env->addr = NULL;
signal(SIGSEGV, old);
val = NULL;
} }
return val; return env->addr;
} }
unsigned NSCountFrames(void) unsigned NSCountFrames(void)
{ {
jmp_buf *env; jbuf_type *env;
void (*old)(int);
void *val;
env = jbuf(); env = jbuf();
if (setjmp(*env) == 0) if (setjmp(env->buf) == 0)
{ {
unsigned *loc; env->segv = signal(SIGSEGV, recover);
env->bus = signal(SIGBUS, recover);
old = signal(SIGSEGV, recover); env->addr = 0;
val = (void*)env;
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
val += sizeof(old);
loc = (unsigned*)val;
*loc = 0;
#define _NS_COUNT_HACK(X) if (__builtin_frame_address(X + 1) == 0) \ #define _NS_COUNT_HACK(X) if (__builtin_frame_address(X + 1) == 0) \
goto done; else *loc = X + 1; goto done; else env->addr = (void*)(X + 1);
_NS_COUNT_HACK(0); _NS_COUNT_HACK(1); _NS_COUNT_HACK(2); _NS_COUNT_HACK(0); _NS_COUNT_HACK(1); _NS_COUNT_HACK(2);
_NS_COUNT_HACK(3); _NS_COUNT_HACK(4); _NS_COUNT_HACK(5); _NS_COUNT_HACK(3); _NS_COUNT_HACK(4); _NS_COUNT_HACK(5);
@ -1025,35 +1018,29 @@ unsigned NSCountFrames(void)
_NS_COUNT_HACK(99); _NS_COUNT_HACK(99);
done: done:
signal(SIGSEGV, old); signal(SIGSEGV, env->segv);
signal(SIGBUS, env->bus);
} }
else else
{ {
env = jbuf(); env = jbuf();
val = (void*)env; signal(SIGSEGV, env->segv);
val += sizeof(jmp_buf); signal(SIGBUS, env->bus);
memcpy(&old, val, sizeof(old));
signal(SIGSEGV, old);
} }
val = (void*)env + sizeof(jmp_buf) + sizeof(old); return (unsigned)(uintptr_t)env->addr;
return *(unsigned*)val;
} }
void * void *
NSReturnAddress(int offset) NSReturnAddress(int offset)
{ {
jmp_buf *env; jbuf_type *env;
void (*old)(int);
void *val;
env = jbuf(); env = jbuf();
if (setjmp(*env) == 0) if (setjmp(env->buf) == 0)
{ {
old = signal(SIGSEGV, recover); env->segv = signal(SIGSEGV, recover);
val = (void*)env; env->bus = signal(SIGBUS, recover);
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
switch (offset) switch (offset)
{ {
_NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2); _NS_RETURN_HACK(0); _NS_RETURN_HACK(1); _NS_RETURN_HACK(2);
@ -1090,20 +1077,20 @@ NSReturnAddress(int offset)
_NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95); _NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95);
_NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98); _NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98);
_NS_RETURN_HACK(99); _NS_RETURN_HACK(99);
default: val = NULL; break; default: env->addr = NULL; break;
} }
signal(SIGSEGV, old); signal(SIGSEGV, env->segv);
signal(SIGBUS, env->bus);
} }
else else
{ {
val = jbuf(); env = jbuf();
val += sizeof(jmp_buf); signal(SIGSEGV, env->segv);
memcpy(&old, val, sizeof(old)); signal(SIGBUS, env->bus);
signal(SIGSEGV, old); env->addr = NULL;
val = NULL;
} }
return val; return env->addr;
} }
NSMutableArray * NSMutableArray *
@ -1113,9 +1100,7 @@ GSPrivateStackAddresses(void)
NSMutableArray *stack = [NSMutableArray arrayWithCapacity: n]; NSMutableArray *stack = [NSMutableArray arrayWithCapacity: n];
CREATE_AUTORELEASE_POOL(pool); CREATE_AUTORELEASE_POOL(pool);
unsigned i; unsigned i;
jmp_buf *env; jbuf_type *env;
void (*old)(int);
void *val;
/* There should be more frame addresses than return addresses. /* There should be more frame addresses than return addresses.
*/ */
@ -1129,12 +1114,10 @@ GSPrivateStackAddresses(void)
} }
env = jbuf(); env = jbuf();
if (setjmp(*env) == 0) if (setjmp(env->buf) == 0)
{ {
old = signal(SIGSEGV, recover); env->segv = signal(SIGSEGV, recover);
val = (void*)env; env->bus = signal(SIGBUS, recover);
val += sizeof(jmp_buf);
memcpy(val, &old, sizeof(old));
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
{ {
@ -1174,23 +1157,21 @@ GSPrivateStackAddresses(void)
_NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95); _NS_RETURN_HACK(93); _NS_RETURN_HACK(94); _NS_RETURN_HACK(95);
_NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98); _NS_RETURN_HACK(96); _NS_RETURN_HACK(97); _NS_RETURN_HACK(98);
_NS_RETURN_HACK(99); _NS_RETURN_HACK(99);
default: val = 0; break; default: env->addr = 0; break;
} }
if (val == 0) if (env->addr == 0)
{ {
break; break;
} }
[stack addObject: [NSValue valueWithPointer: val]]; [stack addObject: [NSValue valueWithPointer: env->addr]];
} }
signal(SIGSEGV, old); signal(SIGSEGV, env->segv);
signal(SIGBUS, env->bus);
} }
else else
{ {
env = jbuf(); signal(SIGSEGV, env->segv);
val = (void*)env; signal(SIGBUS, env->bus);
val += sizeof(jmp_buf);
memcpy(&old, val, sizeof(old));
signal(SIGSEGV, old);
} }
RELEASE(pool); RELEASE(pool);
return stack; return stack;