Message ID | 4E9C3703.3040109@mc.net |
---|---|
State | New |
Headers | show |
On 10/17/2011 07:09 AM, Bob Breuer wrote: > I don't think this is a free/g_free issue. If I use the following > patch, then I at least get the openbios messages: > > diff --git a/cpu-exec.c b/cpu-exec.c > index a9fa608..dfbd6ea 100644 > --- a/cpu-exec.c > +++ b/cpu-exec.c > @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState > /* main execution loop */ > > volatile sig_atomic_t exit_request; > +register void *ebp asm("ebp"); > > int cpu_exec(CPUState *env) > { > @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) > > /* prepare setjmp context for exception handling */ > for(;;) { > + int dummy = 0; > + ebp = &dummy; See if asm("" : : : "ebp"); also solves the problem. > Google finds a mention of longjmp failing with -fomit-frame-pointer: > http://lua-users.org/lists/lua-l/2005-02/msg00158.html > > Looks like gcc 4.6 turns on -fomit-frame-pointer by default. Hmm. This is the first I've heard of a longjmp implementation failing without a frame pointer. Presumably this is with the mingw i.e. msvc libc? This is something that could be worked around in gcc, I suppose. We recognize longjmp for some things, we could force the use of a frame pointer for msvc targets too. For now it might be best to simply force -fno-omit-frame-pointer for mingw host in the configure script. r~
On Mon, Oct 17, 2011 at 5:22 PM, Richard Henderson <rth@twiddle.net> wrote: > On 10/17/2011 07:09 AM, Bob Breuer wrote: >> I don't think this is a free/g_free issue. If I use the following >> patch, then I at least get the openbios messages: >> >> diff --git a/cpu-exec.c b/cpu-exec.c >> index a9fa608..dfbd6ea 100644 >> --- a/cpu-exec.c >> +++ b/cpu-exec.c >> @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState >> /* main execution loop */ >> >> volatile sig_atomic_t exit_request; >> +register void *ebp asm("ebp"); >> >> int cpu_exec(CPUState *env) >> { >> @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) >> >> /* prepare setjmp context for exception handling */ >> for(;;) { >> + int dummy = 0; >> + ebp = &dummy; > > See if > > asm("" : : : "ebp"); > > also solves the problem. > >> Google finds a mention of longjmp failing with -fomit-frame-pointer: >> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >> >> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. > > Hmm. This is the first I've heard of a longjmp implementation > failing without a frame pointer. Presumably this is with the > mingw i.e. msvc libc? > > This is something that could be worked around in gcc, I suppose. > We recognize longjmp for some things, we could force the use of > a frame pointer for msvc targets too. > > For now it might be best to simply force -fno-omit-frame-pointer > for mingw host in the configure script. IIRC buggy versions of alloca() could also fail without a frame pointer.
On 10/17/2011 12:14 PM, Blue Swirl wrote:
> IIRC buggy versions of alloca() could also fail without a frame pointer.
(1) GCC always uses a frame pointer for alloca,
(2) Unless you do -fno-builtin-alloca, we always implement it inline.
r~
Richard Henderson wrote: > On 10/17/2011 07:09 AM, Bob Breuer wrote: >> I don't think this is a free/g_free issue. If I use the following >> patch, then I at least get the openbios messages: >> >> diff --git a/cpu-exec.c b/cpu-exec.c >> index a9fa608..dfbd6ea 100644 >> --- a/cpu-exec.c >> +++ b/cpu-exec.c >> @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState >> /* main execution loop */ >> >> volatile sig_atomic_t exit_request; >> +register void *ebp asm("ebp"); >> >> int cpu_exec(CPUState *env) >> { >> @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) >> >> /* prepare setjmp context for exception handling */ >> for(;;) { >> + int dummy = 0; >> + ebp = &dummy; > > See if > > asm("" : : : "ebp"); > > also solves the problem. No, that doesn't fix it. > >> Google finds a mention of longjmp failing with -fomit-frame-pointer: >> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >> >> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. > > Hmm. This is the first I've heard of a longjmp implementation > failing without a frame pointer. Presumably this is with the > mingw i.e. msvc libc? Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package gcc-core-4.6.1-2-mingw32-bin. > This is something that could be worked around in gcc, I suppose. > We recognize longjmp for some things, we could force the use of > a frame pointer for msvc targets too. > > For now it might be best to simply force -fno-omit-frame-pointer > for mingw host in the configure script. Here's a testcase that crashes on the longjmp: #include <stdio.h> #include <setjmp.h> jmp_buf env; int test(void) { int i; asm("xor %%ebp,%%ebp" ::: "ebp"); i = setjmp(env); printf("i = %d\n", i); if (i == 0) longjmp(env, 2); return i; } int main(void) { return test(); } Remove the asm statement to make it not crash. Obviously with omit-frame-pointer, gcc can shove anything into ebp. Bob
2011/10/17 Bob Breuer <breuerr@mc.net>: > Richard Henderson wrote: >> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>> I don't think this is a free/g_free issue. If I use the following >>> patch, then I at least get the openbios messages: >>> >>> diff --git a/cpu-exec.c b/cpu-exec.c >>> index a9fa608..dfbd6ea 100644 >>> --- a/cpu-exec.c >>> +++ b/cpu-exec.c >>> @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState >>> /* main execution loop */ >>> >>> volatile sig_atomic_t exit_request; >>> +register void *ebp asm("ebp"); >>> >>> int cpu_exec(CPUState *env) >>> { >>> @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) >>> >>> /* prepare setjmp context for exception handling */ >>> for(;;) { >>> + int dummy = 0; >>> + ebp = &dummy; >> >> See if >> >> asm("" : : : "ebp"); >> >> also solves the problem. > > No, that doesn't fix it. > >> >>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>> >>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >> >> Hmm. This is the first I've heard of a longjmp implementation >> failing without a frame pointer. Presumably this is with the >> mingw i.e. msvc libc? > > Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package > gcc-core-4.6.1-2-mingw32-bin. > >> This is something that could be worked around in gcc, I suppose. >> We recognize longjmp for some things, we could force the use of >> a frame pointer for msvc targets too. >> >> For now it might be best to simply force -fno-omit-frame-pointer >> for mingw host in the configure script. > > Here's a testcase that crashes on the longjmp: > > #include <stdio.h> > #include <setjmp.h> > > jmp_buf env; > > int test(void) > { > int i; > > asm("xor %%ebp,%%ebp" ::: "ebp"); > > i = setjmp(env); > printf("i = %d\n", i); > > if (i == 0) > longjmp(env, 2); > > return i; > } > > int main(void) > { > return test(); > } > > Remove the asm statement to make it not crash. Obviously with > omit-frame-pointer, gcc can shove anything into ebp. > > Bob This crash isn'r related to ebp existing, or not. The issue is the hidden argument of setjmp, which is missing. If you can try the following at top of file after include section. #define setjmp(BUF) _setjmpex((BUF), NULL) int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) _setjmp3(jmp_buf _Buf, void *_Ctx); ... This will work as expected with or without omit-frame-pointer. The issue is that setjmp has a second (undocumented as usual) argument, which has a meaning. Regards, Kai PS: _setjmp3 is an export from msvcrt.dll. So if symbol is missing on link, simply specify msvcrt.dll as argument to link-line.
Kai Tietz wrote: > 2011/10/17 Bob Breuer <breuerr@mc.net>: >> Richard Henderson wrote: >>> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>>> I don't think this is a free/g_free issue. If I use the following >>>> patch, then I at least get the openbios messages: >>>> >>>> diff --git a/cpu-exec.c b/cpu-exec.c >>>> index a9fa608..dfbd6ea 100644 >>>> --- a/cpu-exec.c >>>> +++ b/cpu-exec.c >>>> @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState >>>> /* main execution loop */ >>>> >>>> volatile sig_atomic_t exit_request; >>>> +register void *ebp asm("ebp"); >>>> >>>> int cpu_exec(CPUState *env) >>>> { >>>> @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) >>>> >>>> /* prepare setjmp context for exception handling */ >>>> for(;;) { >>>> + int dummy = 0; >>>> + ebp = &dummy; >>> See if >>> >>> asm("" : : : "ebp"); >>> >>> also solves the problem. >> No, that doesn't fix it. >> >>>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>>> >>>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >>> Hmm. This is the first I've heard of a longjmp implementation >>> failing without a frame pointer. Presumably this is with the >>> mingw i.e. msvc libc? >> Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package >> gcc-core-4.6.1-2-mingw32-bin. >> >>> This is something that could be worked around in gcc, I suppose. >>> We recognize longjmp for some things, we could force the use of >>> a frame pointer for msvc targets too. >>> >>> For now it might be best to simply force -fno-omit-frame-pointer >>> for mingw host in the configure script. >> Here's a testcase that crashes on the longjmp: >> >> #include <stdio.h> >> #include <setjmp.h> >> >> jmp_buf env; >> >> int test(void) >> { >> int i; >> >> asm("xor %%ebp,%%ebp" ::: "ebp"); >> >> i = setjmp(env); >> printf("i = %d\n", i); >> >> if (i == 0) >> longjmp(env, 2); >> >> return i; >> } >> >> int main(void) >> { >> return test(); >> } >> >> Remove the asm statement to make it not crash. Obviously with >> omit-frame-pointer, gcc can shove anything into ebp. >> >> Bob > > This crash isn'r related to ebp existing, or not. The issue is the > hidden argument of setjmp, which is missing. If you can try the > following at top of file after include section. > > #define setjmp(BUF) _setjmpex((BUF), NULL) > int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) > _setjmp3(jmp_buf _Buf, void *_Ctx); > ... Did you mean _setjmp3 instead of _setjmpex? With _setjmp3, it works without the asm, but still crashes if I zero out ebp before the setjmp. Aren't the function arguments on the stack anyway? > > This will work as expected with or without omit-frame-pointer. > > The issue is that setjmp has a second (undocumented as usual) > argument, which has a meaning. So why does my testcase above fail with the asm, but work without the asm statement? Compile it with gcc -O2 and try it yourself. > > Regards, > Kai > > PS: _setjmp3 is an export from msvcrt.dll. So if symbol is missing > on link, simply specify msvcrt.dll as argument to link-line.
2011/10/18 Bob Breuer <breuerr@mc.net>: > Kai Tietz wrote: >> 2011/10/17 Bob Breuer <breuerr@mc.net>: >>> Richard Henderson wrote: >>>> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>>>> I don't think this is a free/g_free issue. If I use the following >>>>> patch, then I at least get the openbios messages: >>>>> >>>>> diff --git a/cpu-exec.c b/cpu-exec.c >>>>> index a9fa608..dfbd6ea 100644 >>>>> --- a/cpu-exec.c >>>>> +++ b/cpu-exec.c >>>>> @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState >>>>> /* main execution loop */ >>>>> >>>>> volatile sig_atomic_t exit_request; >>>>> +register void *ebp asm("ebp"); >>>>> >>>>> int cpu_exec(CPUState *env) >>>>> { >>>>> @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) >>>>> >>>>> /* prepare setjmp context for exception handling */ >>>>> for(;;) { >>>>> + int dummy = 0; >>>>> + ebp = &dummy; >>>> See if >>>> >>>> asm("" : : : "ebp"); >>>> >>>> also solves the problem. >>> No, that doesn't fix it. >>> >>>>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>>>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>>>> >>>>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >>>> Hmm. This is the first I've heard of a longjmp implementation >>>> failing without a frame pointer. Presumably this is with the >>>> mingw i.e. msvc libc? >>> Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package >>> gcc-core-4.6.1-2-mingw32-bin. >>> >>>> This is something that could be worked around in gcc, I suppose. >>>> We recognize longjmp for some things, we could force the use of >>>> a frame pointer for msvc targets too. >>>> >>>> For now it might be best to simply force -fno-omit-frame-pointer >>>> for mingw host in the configure script. >>> Here's a testcase that crashes on the longjmp: >>> >>> #include <stdio.h> >>> #include <setjmp.h> >>> >>> jmp_buf env; >>> >>> int test(void) >>> { >>> int i; >>> >>> asm("xor %%ebp,%%ebp" ::: "ebp"); >>> >>> i = setjmp(env); >>> printf("i = %d\n", i); >>> >>> if (i == 0) >>> longjmp(env, 2); >>> >>> return i; >>> } >>> >>> int main(void) >>> { >>> return test(); >>> } >>> >>> Remove the asm statement to make it not crash. Obviously with >>> omit-frame-pointer, gcc can shove anything into ebp. >>> >>> Bob >> >> This crash isn'r related to ebp existing, or not. The issue is the >> hidden argument of setjmp, which is missing. If you can try the >> following at top of file after include section. >> >> #define setjmp(BUF) _setjmpex((BUF), NULL) >> int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) >> _setjmp3(jmp_buf _Buf, void *_Ctx); >> ... > > Did you mean _setjmp3 instead of _setjmpex? With _setjmp3, it works > without the asm, but still crashes if I zero out ebp before the setjmp. > Aren't the function arguments on the stack anyway? Yes, I mean _setjmp3 (pasto from headers and missed the second line prototyping _setjmp3). I repeat myself here. setjmp() has an hidden arguement, which is passed on x86 on stack. By not passing this required argument, setjmp will take a random-value from stack. In your case 'i'. btw if you would pre-initialize 'i' with zero, I would assume you won't see a crash, but anyway this is just by chance. For this I suggest to use here _setjmp3 instead, as here second-argument is documented as being present. Btw I tested your code with i686-pc-mingw32 version 4.6.x and 4.7.x gcc version. With my suggested pattern, I don't see a crash for your provide test-code with, or without zero-ing ebp. Kai
Kai Tietz wrote: > 2011/10/18 Bob Breuer <breuerr@mc.net>: >> Kai Tietz wrote: >>> 2011/10/17 Bob Breuer <breuerr@mc.net>: >>>> Richard Henderson wrote: >>>>> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>>>>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>>>>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>>>>> >>>>>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >>>>> Hmm. This is the first I've heard of a longjmp implementation >>>>> failing without a frame pointer. Presumably this is with the >>>>> mingw i.e. msvc libc? >>>> Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package >>>> gcc-core-4.6.1-2-mingw32-bin. >>>> >>>>> This is something that could be worked around in gcc, I suppose. >>>>> We recognize longjmp for some things, we could force the use of >>>>> a frame pointer for msvc targets too. >>>>> >>>>> For now it might be best to simply force -fno-omit-frame-pointer >>>>> for mingw host in the configure script. >>>> Here's a testcase that crashes on the longjmp: >>>> >>>> #include <stdio.h> >>>> #include <setjmp.h> >>>> >>>> jmp_buf env; >>>> >>>> int test(void) >>>> { >>>> int i; >>>> >>>> asm("xor %%ebp,%%ebp" ::: "ebp"); >>>> >>>> i = setjmp(env); >>>> printf("i = %d\n", i); >>>> >>>> if (i == 0) >>>> longjmp(env, 2); >>>> >>>> return i; >>>> } >>>> >>>> int main(void) >>>> { >>>> return test(); >>>> } >>>> >>>> Remove the asm statement to make it not crash. Obviously with >>>> omit-frame-pointer, gcc can shove anything into ebp. >>>> >>>> Bob >>> This crash isn'r related to ebp existing, or not. The issue is the >>> hidden argument of setjmp, which is missing. If you can try the >>> following at top of file after include section. >>> >>> #define setjmp(BUF) _setjmpex((BUF), NULL) >>> int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) >>> _setjmp3(jmp_buf _Buf, void *_Ctx); >>> ... >> Did you mean _setjmp3 instead of _setjmpex? With _setjmp3, it works >> without the asm, but still crashes if I zero out ebp before the setjmp. >> Aren't the function arguments on the stack anyway? > > Yes, I mean _setjmp3 (pasto from headers and missed the second line > prototyping _setjmp3). > I repeat myself here. setjmp() has an hidden arguement, which is > passed on x86 on stack. By not passing this required argument, setjmp > will take a random-value from stack. In your case 'i'. btw if you > would pre-initialize 'i' with zero, I would assume you won't see a > crash, but anyway this is just by chance. > For this I suggest to use here _setjmp3 instead, as here > second-argument is documented as being present. > > Btw I tested your code with i686-pc-mingw32 version 4.6.x and 4.7.x > gcc version. With my suggested pattern, I don't see a crash for your > provide test-code with, or without zero-ing ebp. We probably have a difference in build or run environment. I've double-checked with another machine and can get the same crash in longjmp when running the test executable on both WinXP and Win2k, but not on Win7. So it looks like Microsoft may have changed this "feature" somewhere between WinXP and Win7. The msvcrt implementation of longjmp (or at least the one I'm looking at) does a ebp based access using the saved value of ebp. Here's the relevant disassembly of longjmp: 0x7801e6f3 in longjmpex () from C:\WINNT\system32\msvcrt.dll (gdb) disas Dump of assembler code for function longjmpex: 0x7801e6ef <+0>: mov 0x4(%esp),%ebx => 0x7801e6f3 <+4>: mov (%ebx),%ebp ... 0x7801e73d <+78>: call 0x7800bd5e <abnormal_termination+56> ... 0x7800bd5e <+56>: push %ebx 0x7800bd5f <+57>: push %ecx 0x7800bd60 <+58>: mov $0x7803dc64,%ebx => 0x7800bd65 <+63>: mov 0x8(%ebp),%ecx It crashes on the access of 0x8(%ebp). Those are the only 2 places where this version of longjmp touches ebp. Is it possible to force a stackframe by just adding a suitable attribute to either the setjmp function prototype, or the function which calls setjmp? Bob
On 10/19/2011 02:05 PM, Bob Breuer wrote: > Is it possible to force a > stackframe by just adding a suitable attribute to either the setjmp > function prototype, or the function which calls setjmp? The only thing I can think of that'll be portable to a large number of versions of GCC is { int n; char *p; asm("" : "=r"(n) : "0"(1)); p = __builtin_alloca(n); asm("" : : "r"(p)); } The first asm prevents constant propagation of the 1 to the alloca; the second asm prevents the alloca from being considered dead code. r~
Hi, all I think this issue causes the gdb crash on XP. You can see the thread: http://sourceware.org/ml/gdb/2011-10/msg00056.html My many friends and I can reproduce this crash issue, but no problem on Win7. On Thu, Oct 20, 2011 at 5:05 AM, Bob Breuer <breuerr@mc.net> wrote: > Kai Tietz wrote: >> 2011/10/18 Bob Breuer <breuerr@mc.net>: >>> Kai Tietz wrote: >>>> 2011/10/17 Bob Breuer <breuerr@mc.net>: >>>>> Richard Henderson wrote: >>>>>> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>>>>>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>>>>>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>>>>>> >>>>>>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >>>>>> Hmm. This is the first I've heard of a longjmp implementation >>>>>> failing without a frame pointer. Presumably this is with the >>>>>> mingw i.e. msvc libc? >>>>> Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package >>>>> gcc-core-4.6.1-2-mingw32-bin. >>>>> >>>>>> This is something that could be worked around in gcc, I suppose. >>>>>> We recognize longjmp for some things, we could force the use of >>>>>> a frame pointer for msvc targets too. >>>>>> >>>>>> For now it might be best to simply force -fno-omit-frame-pointer >>>>>> for mingw host in the configure script. >>>>> Here's a testcase that crashes on the longjmp: >>>>> >>>>> #include <stdio.h> >>>>> #include <setjmp.h> >>>>> >>>>> jmp_buf env; >>>>> >>>>> int test(void) >>>>> { >>>>> int i; >>>>> >>>>> asm("xor %%ebp,%%ebp" ::: "ebp"); >>>>> >>>>> i = setjmp(env); >>>>> printf("i = %d\n", i); >>>>> >>>>> if (i == 0) >>>>> longjmp(env, 2); >>>>> >>>>> return i; >>>>> } >>>>> >>>>> int main(void) >>>>> { >>>>> return test(); >>>>> } >>>>> >>>>> Remove the asm statement to make it not crash. Obviously with >>>>> omit-frame-pointer, gcc can shove anything into ebp. >>>>> >>>>> Bob >>>> This crash isn'r related to ebp existing, or not. The issue is the >>>> hidden argument of setjmp, which is missing. If you can try the >>>> following at top of file after include section. >>>> >>>> #define setjmp(BUF) _setjmpex((BUF), NULL) >>>> int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) >>>> _setjmp3(jmp_buf _Buf, void *_Ctx); >>>> ... >>> Did you mean _setjmp3 instead of _setjmpex? With _setjmp3, it works >>> without the asm, but still crashes if I zero out ebp before the setjmp. >>> Aren't the function arguments on the stack anyway? >> >> Yes, I mean _setjmp3 (pasto from headers and missed the second line >> prototyping _setjmp3). >> I repeat myself here. setjmp() has an hidden arguement, which is >> passed on x86 on stack. By not passing this required argument, setjmp >> will take a random-value from stack. In your case 'i'. btw if you >> would pre-initialize 'i' with zero, I would assume you won't see a >> crash, but anyway this is just by chance. >> For this I suggest to use here _setjmp3 instead, as here >> second-argument is documented as being present. >> >> Btw I tested your code with i686-pc-mingw32 version 4.6.x and 4.7.x >> gcc version. With my suggested pattern, I don't see a crash for your >> provide test-code with, or without zero-ing ebp. > > > We probably have a difference in build or run environment. I've > double-checked with another machine and can get the same crash in > longjmp when running the test executable on both WinXP and Win2k, but > not on Win7. So it looks like Microsoft may have changed this "feature" > somewhere between WinXP and Win7. > > The msvcrt implementation of longjmp (or at least the one I'm looking > at) does a ebp based access using the saved value of ebp. Here's the > relevant disassembly of longjmp: > > 0x7801e6f3 in longjmpex () from C:\WINNT\system32\msvcrt.dll > (gdb) disas > Dump of assembler code for function longjmpex: > 0x7801e6ef <+0>: mov 0x4(%esp),%ebx > => 0x7801e6f3 <+4>: mov (%ebx),%ebp > ... > 0x7801e73d <+78>: call 0x7800bd5e <abnormal_termination+56> > ... > 0x7800bd5e <+56>: push %ebx > 0x7800bd5f <+57>: push %ecx > 0x7800bd60 <+58>: mov $0x7803dc64,%ebx > => 0x7800bd65 <+63>: mov 0x8(%ebp),%ecx > > It crashes on the access of 0x8(%ebp). Those are the only 2 places > where this version of longjmp touches ebp. Is it possible to force a > stackframe by just adding a suitable attribute to either the setjmp > function prototype, or the function which calls setjmp? > > Bob >
On 2011-10-20 AM 6:05, Bob Breuer wrote: > > We probably have a difference in build or run environment. I've > double-checked with another machine and can get the same crash in > longjmp when running the test executable on both WinXP and Win2k, but > not on Win7. So it looks like Microsoft may have changed this "feature" > somewhere between WinXP and Win7. YEES! It does crash in winxp. > > The msvcrt implementation of longjmp (or at least the one I'm looking > at) does a ebp based access using the saved value of ebp. Here's the > relevant disassembly of longjmp: > > 0x7801e6f3 in longjmpex () from C:\WINNT\system32\msvcrt.dll > (gdb) disas > Dump of assembler code for function longjmpex: > 0x7801e6ef<+0>: mov 0x4(%esp),%ebx > => 0x7801e6f3<+4>: mov (%ebx),%ebp > ... > 0x7801e73d<+78>: call 0x7800bd5e<abnormal_termination+56> > ... > 0x7800bd5e<+56>: push %ebx > 0x7800bd5f<+57>: push %ecx > 0x7800bd60<+58>: mov $0x7803dc64,%ebx > => 0x7800bd65<+63>: mov 0x8(%ebp),%ecx > > It crashes on the access of 0x8(%ebp). Those are the only 2 places > where this version of longjmp touches ebp. Is it possible to force a > stackframe by just adding a suitable attribute to either the setjmp > function prototype, or the function which calls setjmp? and we had relevant report in ruby. http://redmine.ruby-lang.org/issues/5375 Kai, would you mind if i reopen this bug you rejected? http://gcc.gnu.org/bugzilla/show_bug.cgi?id=49230 > > Bob > >
2011/10/20 xunxun <xunxun1982@gmail.com>: > Hi, all > > I think this issue causes the gdb crash on XP. > You can see the thread: http://sourceware.org/ml/gdb/2011-10/msg00056.html > > My many friends and I can reproduce this crash issue, but no problem on Win7. > > On Thu, Oct 20, 2011 at 5:05 AM, Bob Breuer <breuerr@mc.net> wrote: >> Kai Tietz wrote: >>> 2011/10/18 Bob Breuer <breuerr@mc.net>: >>>> Kai Tietz wrote: >>>>> 2011/10/17 Bob Breuer <breuerr@mc.net>: >>>>>> Richard Henderson wrote: >>>>>>> On 10/17/2011 07:09 AM, Bob Breuer wrote: >>>>>>>> Google finds a mention of longjmp failing with -fomit-frame-pointer: >>>>>>>> http://lua-users.org/lists/lua-l/2005-02/msg00158.html >>>>>>>> >>>>>>>> Looks like gcc 4.6 turns on -fomit-frame-pointer by default. >>>>>>> Hmm. This is the first I've heard of a longjmp implementation >>>>>>> failing without a frame pointer. Presumably this is with the >>>>>>> mingw i.e. msvc libc? >>>>>> Yeah, mingw from www.mingw.org which I believe uses msvcrt.dll, package >>>>>> gcc-core-4.6.1-2-mingw32-bin. >>>>>> >>>>>>> This is something that could be worked around in gcc, I suppose. >>>>>>> We recognize longjmp for some things, we could force the use of >>>>>>> a frame pointer for msvc targets too. >>>>>>> >>>>>>> For now it might be best to simply force -fno-omit-frame-pointer >>>>>>> for mingw host in the configure script. >>>>>> Here's a testcase that crashes on the longjmp: >>>>>> >>>>>> #include <stdio.h> >>>>>> #include <setjmp.h> >>>>>> >>>>>> jmp_buf env; >>>>>> >>>>>> int test(void) >>>>>> { >>>>>> int i; >>>>>> >>>>>> asm("xor %%ebp,%%ebp" ::: "ebp"); >>>>>> >>>>>> i = setjmp(env); >>>>>> printf("i = %d\n", i); >>>>>> >>>>>> if (i == 0) >>>>>> longjmp(env, 2); >>>>>> >>>>>> return i; >>>>>> } >>>>>> >>>>>> int main(void) >>>>>> { >>>>>> return test(); >>>>>> } >>>>>> >>>>>> Remove the asm statement to make it not crash. Obviously with >>>>>> omit-frame-pointer, gcc can shove anything into ebp. >>>>>> >>>>>> Bob >>>>> This crash isn'r related to ebp existing, or not. The issue is the >>>>> hidden argument of setjmp, which is missing. If you can try the >>>>> following at top of file after include section. >>>>> >>>>> #define setjmp(BUF) _setjmpex((BUF), NULL) >>>>> int __cdecl __attribute__ ((__nothrow__,__returns_twice__)) >>>>> _setjmp3(jmp_buf _Buf, void *_Ctx); >>>>> ... >>>> Did you mean _setjmp3 instead of _setjmpex? With _setjmp3, it works >>>> without the asm, but still crashes if I zero out ebp before the setjmp. >>>> Aren't the function arguments on the stack anyway? >>> >>> Yes, I mean _setjmp3 (pasto from headers and missed the second line >>> prototyping _setjmp3). >>> I repeat myself here. setjmp() has an hidden arguement, which is >>> passed on x86 on stack. By not passing this required argument, setjmp >>> will take a random-value from stack. In your case 'i'. btw if you >>> would pre-initialize 'i' with zero, I would assume you won't see a >>> crash, but anyway this is just by chance. >>> For this I suggest to use here _setjmp3 instead, as here >>> second-argument is documented as being present. >>> >>> Btw I tested your code with i686-pc-mingw32 version 4.6.x and 4.7.x >>> gcc version. With my suggested pattern, I don't see a crash for your >>> provide test-code with, or without zero-ing ebp. >> >> >> We probably have a difference in build or run environment. I've >> double-checked with another machine and can get the same crash in >> longjmp when running the test executable on both WinXP and Win2k, but >> not on Win7. So it looks like Microsoft may have changed this "feature" >> somewhere between WinXP and Win7. >> >> The msvcrt implementation of longjmp (or at least the one I'm looking >> at) does a ebp based access using the saved value of ebp. Here's the >> relevant disassembly of longjmp: >> >> 0x7801e6f3 in longjmpex () from C:\WINNT\system32\msvcrt.dll >> (gdb) disas >> Dump of assembler code for function longjmpex: >> 0x7801e6ef <+0>: mov 0x4(%esp),%ebx >> => 0x7801e6f3 <+4>: mov (%ebx),%ebp >> ... >> 0x7801e73d <+78>: call 0x7800bd5e <abnormal_termination+56> >> ... >> 0x7800bd5e <+56>: push %ebx >> 0x7800bd5f <+57>: push %ecx >> 0x7800bd60 <+58>: mov $0x7803dc64,%ebx >> => 0x7800bd65 <+63>: mov 0x8(%ebp),%ecx >> >> It crashes on the access of 0x8(%ebp). Those are the only 2 places >> where this version of longjmp touches ebp. Is it possible to force a >> stackframe by just adding a suitable attribute to either the setjmp >> function prototype, or the function which calls setjmp? >> >> Bob >> > > > > -- > Best Regards, > xunxun This now makes sense. I use here Vista 64-bit, and Win7 64-bit and I didn't found the issue. But well, it is indeed related to different msvcrt-version. So there might be some need to have for a function using setjmp the frame-pointer enabled. I can confirm this by an older msvcrt.dll version on my 64-bit box, too. So bug can be re-opened. Thanks, Kai
diff --git a/cpu-exec.c b/cpu-exec.c index a9fa608..dfbd6ea 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -180,6 +180,7 @@ static void cpu_handle_debug_exception(CPUState /* main execution loop */ volatile sig_atomic_t exit_request; +register void *ebp asm("ebp"); int cpu_exec(CPUState *env) { @@ -233,6 +234,8 @@ int cpu_exec(CPUState *env) /* prepare setjmp context for exception handling */ for(;;) { + int dummy = 0; + ebp = &dummy; if (setjmp(env->jmp_env) == 0) { /* if an exception is pending, we execute it here */ if (env->exception_index >= 0) {