Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Peter Maydell
On 2 July 2011 08:50, Jan Kiszka jan.kis...@web.de wrote:
 From: Jan Kiszka jan.kis...@siemens.com

 Recent compilers look deep into cpu_exec, find longjmp as a noreturn
 function and decide to smash some stack variables as they won't be used
 again. This may lead to env becoming invalid after return from setjmp,
 causing crashes. Fix it by reloading env from cpu_single_env in that
 case.

Can you give more details of what compiler/platform this was
a problem for? My reading of the C standard is that the compiler
isn't allowed to trash env across this longjmp, because it's
a variable of automatic scope which isn't modified between the
setjmp and the longjmp...

(We've been looking at this because reloading from cpu_single_env is
the wrong fix in the case of user-mode where there are multiple-threads.)

Thanks
-- PMM



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Paolo Bonzini

On 08/11/2011 01:30 PM, Peter Maydell wrote:

  Recent compilers look deep into cpu_exec, find longjmp as a noreturn
  function and decide to smash some stack variables as they won't be used
  again. This may lead to env becoming invalid after return from setjmp,
  causing crashes. Fix it by reloading env from cpu_single_env in that
  case.

Can you give more details of what compiler/platform this was
a problem for? My reading of the C standard is that the compiler
isn't allowed to trash env across this longjmp, because it's
a variable of automatic scope which isn't modified between the
setjmp and the longjmp...


longjmp can destroy any non-volatile variable (-Wclobbered warns about 
this).


Paolo



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Peter Maydell
On 11 August 2011 13:16, Paolo Bonzini pbonz...@redhat.com wrote:
 On 08/11/2011 01:30 PM, Peter Maydell wrote:
 Can you give more details of what compiler/platform this was
 a problem for? My reading of the C standard is that the compiler
 isn't allowed to trash env across this longjmp, because it's
 a variable of automatic scope which isn't modified between the
 setjmp and the longjmp...

 longjmp can destroy any non-volatile variable (-Wclobbered warns about
 this).

All accessible objects have values [...] as of the time the longjmp
function was called, except that the values of objects of automatic
storage duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the setjmp
invocation and longjmp call are indeterminate.
 -- C99 section 7.13.2.1 para 3.

So variables may only be destroyed if they are all of:
 * local to the function calling setjmp
 * not volatile
 * changed between setjmp and longjmp

We don't change env between the setjmp and longjmp so the compiler
should not trash it. (Indeed according to Jan in
http://lists.gnu.org/archive/html/qemu-devel/2011-07/msg00144.html
-Wclobbered doesn't complain about this code.)

-- PMM



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Paolo Bonzini

On 08/11/2011 02:40 PM, Peter Maydell wrote:

All accessible objects have values [...] as of the time the longjmp
function was called, except that the values of objects of automatic
storage duration that are local to the function containing the
invocation of the corresponding setjmp macro that do not have
volatile-qualified type and have been changed between the setjmp
invocation and longjmp call are indeterminate.
  -- C99 section 7.13.2.1 para 3.

So variables may only be destroyed if they are all of:
  * local to the function calling setjmp
  * not volatile
  * changed between setjmp and longjmp


I didn't remember this third part.  Thanks for bringing up facts. :)


We don't change env between the setjmp and longjmp so the compiler
should not trash it. (Indeed according to Jan in
http://lists.gnu.org/archive/html/qemu-devel/2011-07/msg00144.html
-Wclobbered doesn't complain about this code.)


Then it's a compiler bug, not smartness.  Making env volatile (or making 
a volatile copy if there is a performance impact) should still be enough 
to work around it.


Paolo



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Peter Maydell
On 11 August 2011 14:13, Paolo Bonzini pbonz...@redhat.com wrote:
 On 08/11/2011 02:40 PM, Peter Maydell wrote:
 We don't change env between the setjmp and longjmp so the compiler
 should not trash it. (Indeed according to Jan in
 http://lists.gnu.org/archive/html/qemu-devel/2011-07/msg00144.html
 -Wclobbered doesn't complain about this code.)

 Then it's a compiler bug, not smartness.  Making env volatile (or making a
 volatile copy if there is a performance impact) should still be enough to
 work around it.

Yes. (It would have to be a volatile copy, I think, env is a function
parameter and I don't think you can make those volatile.)
https://bugs.launchpad.net/qemu/+bug/823902 includes some discussion
of the effects on the test of adding the volatile copy.

-- PMM



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Paolo Bonzini

On 08/11/2011 03:31 PM, Peter Maydell wrote:


Then it's a compiler bug, not smartness.  Making env volatile
(or making a volatile copy if there is a performance impact)
should still be enough to work around it.

Yes. (It would have to be a volatile copy, I think, env is a function
parameter and I don't think you can make those volatile.)
https://bugs.launchpad.net/qemu/+bug/823902  includes some discussion
of the effects on the test of adding the volatile copy.


I'm not sure about what to read from there:


If I make cpu_single_env thread local with __thread and leave
0d101... in, then again it works reliably on 32bit Lucid, and is
flaky on 64 bit Oneiric (5/10 2 hangs, 3 segs)

I've also tried using a volatile local variable in cpu_exec to hold
a copy of env and restore that rather than cpu_single_env. With this
it's solid on 32bit lucid and flaky on 64bit Oneirc; these failures
on 64bit OO look like it running off the end of the code buffer (all
0 code), jumping to non-existent code addresses and a seg in
tb_reset_jump_recursive2.


It looks like neither a thread-local cpu_single_env nor a volatile copy 
fix the bug?!?


I cannot think off-hand of a reason why thread-local cpu_single_env 
should not work for iothread under Unix, BTW.  Since cpu_single_env is 
only set/used by a thread at a time (under the global lock), its users 
cannot distinguish between a thread-local variable and a global.


The only problem would be Windows, which runs cpu_signal in a thread 
different than the CPU thread.  But that can be fixed easily in 
qemu_cpu_kick_thread.


Paolo



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread David Gilbert
On 11 August 2011 15:10, Paolo Bonzini pbonz...@redhat.com wrote:

 I'm not sure about what to read from there:

 If I make cpu_single_env thread local with __thread and leave
 0d101... in, then again it works reliably on 32bit Lucid, and is
 flaky on 64 bit Oneiric (5/10 2 hangs, 3 segs)

 I've also tried using a volatile local variable in cpu_exec to hold
 a copy of env and restore that rather than cpu_single_env. With this
 it's solid on 32bit lucid and flaky on 64bit Oneirc; these failures
 on 64bit OO look like it running off the end of the code buffer (all
 0 code), jumping to non-existent code addresses and a seg in
 tb_reset_jump_recursive2.

 It looks like neither a thread-local cpu_single_env nor a volatile copy fix
 the bug?!?

As I say at the bottom of that bug I'm assuming I'm hitting multiple bugs.
Although it's not clear to me why I don't hit them on 32bit lucid.

Dave



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Peter Maydell
On 11 August 2011 15:10, Paolo Bonzini pbonz...@redhat.com wrote:
 On 08/11/2011 03:31 PM, Peter Maydell wrote:

 Then it's a compiler bug, not smartness.  Making env volatile
 (or making a volatile copy if there is a performance impact)
 should still be enough to work around it.

 Yes. (It would have to be a volatile copy, I think, env is a function
 parameter and I don't think you can make those volatile.)
 https://bugs.launchpad.net/qemu/+bug/823902  includes some discussion
 of the effects on the test of adding the volatile copy.

 I'm not sure about what to read from there:

 If I make cpu_single_env thread local with __thread and leave
 0d101... in, then again it works reliably on 32bit Lucid, and is
 flaky on 64 bit Oneiric (5/10 2 hangs, 3 segs)

 I've also tried using a volatile local variable in cpu_exec to hold
 a copy of env and restore that rather than cpu_single_env. With this
 it's solid on 32bit lucid and flaky on 64bit Oneirc; these failures
 on 64bit OO look like it running off the end of the code buffer (all
 0 code), jumping to non-existent code addresses and a seg in
 tb_reset_jump_recursive2.

 It looks like neither a thread-local cpu_single_env nor a volatile copy fix
 the bug?!?

My guess is that we're running into the various other problems qemu has
with significantly multithreaded programs in user-mode, which makes it
a bit hard to disentangle this specific regression. (In particular
segfaults in tb_reset_jump_recursive2 are almost certainly bug 668799.)

 I cannot think off-hand of a reason why thread-local cpu_single_env should
 not work for iothread under Unix, BTW.  Since cpu_single_env is only
 set/used by a thread at a time (under the global lock), its users cannot
 distinguish between a thread-local variable and a global.

Thanks for the clarification. As you say, as long as we don't ever
try to access it from another thread we're fine...

 The only problem would be Windows, which runs cpu_signal in a thread
 different than the CPU thread.  But that can be fixed easily in
 qemu_cpu_kick_thread.

...and we just need to fix this.

-- PMM



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-08-11 Thread Paolo Bonzini

On 08/11/2011 04:24 PM, Peter Maydell wrote:

I cannot think off-hand of a reason why thread-local cpu_single_env should
not work for iothread under Unix, BTW.  Since cpu_single_env is only
set/used by a thread at a time (under the global lock), its users cannot
distinguish between a thread-local variable and a global.


Thanks for the clarification. As you say, as long as we don't ever
try to access it from another thread we're fine...


Yes, and the current usage of the lock should be enough of a guarantee.


The only problem would be Windows, which runs cpu_signal in a thread
different than the CPU thread.  But that can be fixed easily in
qemu_cpu_kick_thread.


...and we just need to fix this.


Untested (uncompiled) patch follows:

diff --git a/cpus.c b/cpus.c
index 6bf4e3f..04e52fe 100644
--- a/cpus.c
+++ b/cpus.c
@@ -179,10 +179,10 @@ static void cpu_handle_guest_debug(CPUState *env)
 }

 #ifdef CONFIG_IOTHREAD
-static void cpu_signal(int sig)
+static inline void do_cpu_kick(CPUState *env)
 {
-if (cpu_single_env) {
-cpu_exit(cpu_single_env);
+if (env) {
+cpu_exit(env);
 }
 exit_request = 1;
 }
@@ -476,6 +476,13 @@ static void qemu_kvm_init_cpu_signals(CPUState *env)
 }
 }

+#ifdef CONFIG_IOTHREAD
+static void cpu_signal(int sig)
+{
+do_cpu_kick(cpu_single_env);
+}
+#endif
+
 static void qemu_tcg_init_cpu_signals(void)
 {
 #ifdef CONFIG_IOTHREAD
@@ -858,7 +865,7 @@ static void qemu_cpu_kick_thread(CPUState *env)
 #else /* _WIN32 */
 if (!qemu_cpu_is_self(env)) {
 SuspendThread(env-thread-thread);
-cpu_signal(0);
+do_cpu_kick(env);
 ResumeThread(env-thread-thread);
 }
 #endif



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-07-12 Thread Blue Swirl
Thanks, applied.

On Sat, Jul 2, 2011 at 10:50 AM, Jan Kiszka jan.kis...@web.de wrote:
 From: Jan Kiszka jan.kis...@siemens.com

 Recent compilers look deep into cpu_exec, find longjmp as a noreturn
 function and decide to smash some stack variables as they won't be used
 again. This may lead to env becoming invalid after return from setjmp,
 causing crashes. Fix it by reloading env from cpu_single_env in that
 case.

 Signed-off-by: Jan Kiszka jan.kis...@siemens.com
 ---
  cpu-exec.c |    4 
  1 files changed, 4 insertions(+), 0 deletions(-)

 diff --git a/cpu-exec.c b/cpu-exec.c
 index 20e3ec4..de0d716 100644
 --- a/cpu-exec.c
 +++ b/cpu-exec.c
 @@ -587,6 +587,10 @@ int cpu_exec(CPUState *env)
                 /* reset soft MMU for next block (it can currently
                    only be set by a memory fault) */
             } /* for(;;) */
 +        } else {
 +            /* Reload env after longjmp - the compiler may have smashed all
 +             * local variables as longjmp is marked 'noreturn'. */
 +            env = cpu_single_env;
         }
     } /* for(;;) */





Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-07-03 Thread Paolo Bonzini

On 07/02/2011 11:43 AM, Jan Kiszka wrote:

  static const char *pch;
+static char *saved_key;
  static jmp_buf expr_env;

  #define MD_TLONG 0
@@ -4254,8 +4255,11 @@ static const mon_cmd_t *monitor_parse_command(Monitor 
*mon,
  }
  typestr++;
  }
-if (get_expr(mon,val,p))
+saved_key = key;
+if (get_expr(mon,val,p)) {
+key = saved_key;
  goto fail;
+}


Please make saved_key a volatile local instead.

Paolo



Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-07-02 Thread Blue Swirl
On Sat, Jul 2, 2011 at 10:50 AM, Jan Kiszka jan.kis...@web.de wrote:
 From: Jan Kiszka jan.kis...@siemens.com

 Recent compilers look deep into cpu_exec, find longjmp as a noreturn
 function and decide to smash some stack variables as they won't be used
 again. This may lead to env becoming invalid after return from setjmp,
 causing crashes. Fix it by reloading env from cpu_single_env in that
 case.

Nice. Could you try if gcc flag -Wclobbered catches something using
your compiler without your patch:

commit f826f0d0f5cf5dd18a0d34159c1a3bc8f2e6ddf4
Author: Blue Swirl blauwir...@gmail.com
Date:   Sun Sep 26 11:58:38 2010 +

Add gcc warning -Wclobbered

Signed-off-by: Blue Swirl blauwir...@gmail.com

diff --git a/configure b/configure
index 88159ac..2417205 100755
--- a/configure
+++ b/configure
@@ -1038,7 +1038,7 @@ fi
 gcc_flags=-Wold-style-declaration -Wold-style-definition -Wtype-limits
 gcc_flags=-Wformat-security -Wformat-y2k -Winit-self
-Wignored-qualifiers $gcc_flags
 gcc_flags=-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags
-gcc_flags=-fstack-protector-all -Wendif-labels $gcc_flags
+gcc_flags=-fstack-protector-all -Wendif-labels -Wclobbered $gcc_flags
 cat  $TMPC  EOF
 int main(void) { return 0; }
 EOF


 Signed-off-by: Jan Kiszka jan.kis...@siemens.com
 ---
  cpu-exec.c |    4 
  1 files changed, 4 insertions(+), 0 deletions(-)

 diff --git a/cpu-exec.c b/cpu-exec.c
 index 20e3ec4..de0d716 100644
 --- a/cpu-exec.c
 +++ b/cpu-exec.c
 @@ -587,6 +587,10 @@ int cpu_exec(CPUState *env)
                 /* reset soft MMU for next block (it can currently
                    only be set by a memory fault) */
             } /* for(;;) */
 +        } else {
 +            /* Reload env after longjmp - the compiler may have smashed all
 +             * local variables as longjmp is marked 'noreturn'. */
 +            env = cpu_single_env;
         }
     } /* for(;;) */





Re: [Qemu-devel] [PATCH] tcg: Reload local variables after return from longjmp

2011-07-02 Thread Jan Kiszka
On 2011-07-02 11:08, Blue Swirl wrote:
 On Sat, Jul 2, 2011 at 10:50 AM, Jan Kiszka jan.kis...@web.de wrote:
 From: Jan Kiszka jan.kis...@siemens.com

 Recent compilers look deep into cpu_exec, find longjmp as a noreturn
 function and decide to smash some stack variables as they won't be used
 again. This may lead to env becoming invalid after return from setjmp,
 causing crashes. Fix it by reloading env from cpu_single_env in that
 case.
 
 Nice. Could you try if gcc flag -Wclobbered catches something using
 your compiler without your patch:
 
 commit f826f0d0f5cf5dd18a0d34159c1a3bc8f2e6ddf4
 Author: Blue Swirl blauwir...@gmail.com
 Date:   Sun Sep 26 11:58:38 2010 +
 
 Add gcc warning -Wclobbered
 
 Signed-off-by: Blue Swirl blauwir...@gmail.com
 
 diff --git a/configure b/configure
 index 88159ac..2417205 100755
 --- a/configure
 +++ b/configure
 @@ -1038,7 +1038,7 @@ fi
  gcc_flags=-Wold-style-declaration -Wold-style-definition -Wtype-limits
  gcc_flags=-Wformat-security -Wformat-y2k -Winit-self
 -Wignored-qualifiers $gcc_flags
  gcc_flags=-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags
 -gcc_flags=-fstack-protector-all -Wendif-labels $gcc_flags
 +gcc_flags=-fstack-protector-all -Wendif-labels -Wclobbered $gcc_flags
  cat  $TMPC  EOF
  int main(void) { return 0; }
  EOF

Neither native gcc 4.5.0 nor mingw's 4.6.0 detect this issue. However,
4.6 found this - and 3 false positives:

diff --git a/monitor.c b/monitor.c
index 67ceb46..d7edbbb 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3253,6 +3253,7 @@ static const mon_cmd_t qmp_query_cmds[] = {
 /***/
 
 static const char *pch;
+static char *saved_key;
 static jmp_buf expr_env;
 
 #define MD_TLONG 0
@@ -4254,8 +4255,11 @@ static const mon_cmd_t *monitor_parse_command(Monitor 
*mon,
 }
 typestr++;
 }
-if (get_expr(mon, val, p))
+saved_key = key;
+if (get_expr(mon, val, p)) {
+key = saved_key;
 goto fail;
+}
 /* Check if 'i' is greater than 32-bit */
 if ((c == 'i')  ((val  32)  0x)) {
 monitor_printf(mon, \'%s\' has failed: , cmdname);


But the right way to deal with it is to return error codes and get rid
of this setjmp/longjmp mess for get_expr.

Jan



signature.asc
Description: OpenPGP digital signature