linux-user: fix segfault deadlock

When entering the guest we take a lock to ensure that nobody else messes
with our TB chaining while we're doing it. If we get a segfault inside that
code, we manage to work on, but will not unlock the lock.

This patch forces unlocking of that lock in the segv handler. I'm not sure
this is the right approach though. Maybe we should rather make sure we don't
segfault in the code? I would greatly appreciate someone more intelligible
than me to look at this :).

Example code to trigger this is at: http://csgraf.de/tmp/conftest.c

Reported-by: Fabio Erculiani <lxnay@sabayon.org>
Signed-off-by: Alexander Graf <agraf@suse.de>
This commit is contained in:
Alexander Graf
2012-01-13 17:05:41 +01:00
committed by Andreas Färber
parent 1b71cc7ca0
commit 6129f046f7
2 changed files with 14 additions and 0 deletions

View File

@@ -24,6 +24,12 @@
#include <pthread.h> #include <pthread.h>
#define spin_lock pthread_mutex_lock #define spin_lock pthread_mutex_lock
#define spin_unlock pthread_mutex_unlock #define spin_unlock pthread_mutex_unlock
static inline void spin_unlock_safe(pthread_mutex_t *lock)
{
/* unlocking an unlocked mutex results in undefined behavior */
pthread_mutex_trylock(lock);
pthread_mutex_unlock(lock);
}
#define spinlock_t pthread_mutex_t #define spinlock_t pthread_mutex_t
#define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER #define SPIN_LOCK_UNLOCKED PTHREAD_MUTEX_INITIALIZER
@@ -46,4 +52,8 @@ static inline void spin_unlock(spinlock_t *lock)
{ {
} }
static inline void spin_unlock_safe(spinlock_t *lock)
{
}
#endif #endif

View File

@@ -88,6 +88,10 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address,
qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set); pc, address, is_write, *(unsigned long *)old_set);
#endif #endif
/* Maybe we're still holding the TB fiddling lock? */
spin_unlock_safe(&tb_lock);
/* XXX: locking issue */ /* XXX: locking issue */
if (is_write && h2g_valid(address) if (is_write && h2g_valid(address)
&& page_unprotect(h2g(address), pc, puc)) { && page_unprotect(h2g(address), pc, puc)) {