On Mon, Mar 26, 2012 at 07:23:58PM +0200, Peter Maydell wrote:
> 2012/3/26 Cédric VINCENT <cedric.vinc...@st.com>:
> > the function cpu_restore_state() isn't expected to be called in user-mode,
> 
> Is this really true? host_signal_handler() calls cpu_signal_handler()
> calls handle_cpu_signala) calls cpu_restore_state() so hopefully
> it's OK to be called in at least *some* situations...

Actually it's not that OK, the code below [1] exposes a threading
issue in this specific part of QEMU:

    * the first thread makes invalid memory references, that way QEMU
      reaches the given situation (host_signal_handler ->
      cpu_signal_handler -> handle_cpu_signal -> cpu_restore_state ->
      gen_intermediate_code) without acquiring "tb_lock".

    * at the same time, the second thread executes code that wasn't
      translated before, that way the TCG is invoked with "tb_lock"
      acquired.  Note that in this example I used a self modifying
      block just to simulate a not-yet-translated code.

This example triggers an invalid memory reference and/or an assertion
in the TCG part of QEMU.


> NB the whole tb_lock thing is broken anyway.

Because of such bugs or are there other reasons?  Maybe we could add a
simple sanity check in gen_intermediate_code() functions to be sure
that "tb_lock" is acquired when they are called.

Regards,
Cédric.

[1] I wrote this example for ARM and SH4, but this problem appears for
    any guest CPU:

#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/syscall.h>
#include <signal.h>
#include <stdlib.h>
#include <strings.h>
#include <stdint.h>

pid_t gettid(void)
{
        return syscall(SYS_gettid);
}

void handler(int signo)
{
        printf("Thread %d received signal %d\n", gettid(), signo);
}

void *routine(void *arg)
{
        pid_t tid = (pid_t)arg;

        while (1) {
            *(int *)NULL = 1;
            sleep(1);
        }
}

int main(void)
{
    struct sigaction action;
    pthread_t thread;
    int status;

    bzero(&action, sizeof(action));
    action.sa_handler = handler;
    sigfillset(&action.sa_mask);

    status = sigaction(SIGSEGV, &action, NULL);
    if (status < 0) {
        puts("can't regsiter sighandler, bye!");
        exit(EXIT_FAILURE);
    }

    status = pthread_create(&thread, NULL, routine, (void *)gettid());
    if (status) {
            puts("can't create a thread, bye!");
            exit(EXIT_FAILURE);
    }

#if defined(__SH4__)
    uint8_t self_modifying_code[] = {
        // _start
        0x00, 0xc7,  // mova    @(4, pc), r0
        0x01, 0x61,  // mov.w   @r0, r1
        0x11, 0x20,  // mov.w   r1, @r0
        0xfb, 0xaf,  // bra     _start
        0x09, 0x00,  // nop
    };

    asm volatile ("jmp @%0 \n nop" : : "r" (self_modifying_code));
#elif defined(__arm__)
    uint32_t self_modifying_code[] = {
        // _start:
        0xe1a0000f,  // mov     r0, pc
        0xe5901000,  // ldr     r1, [r0]
        0xe5801000,  // str     r1, [r0]
        0xeafffffb,  // b       _start
    };

    asm volatile ("mov pc, %0" : : "r" (self_modifying_code));
#else
    #error "unsupported architecture."
#endif

    puts("should'nt be reached, bye!");
    exit(EXIT_FAILURE);
}

Reply via email to