mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 08:26:14 +00:00
70 lines
1.9 KiB
C
70 lines
1.9 KiB
C
#include <pthread.h>
|
|
#include <signal.h>
|
|
#include <setjmp.h>
|
|
#include <errno.h>
|
|
#include <assert.h>
|
|
|
|
static sigjmp_buf env;
|
|
|
|
/*
|
|
* Starting with glibc 2.20 some pthread calls may execute
|
|
* an xend instruction unconditionally when a lock is used in
|
|
* a way that is invalid so defined a sigill handler that can
|
|
* convert these invalid instructions to a normal error.
|
|
*/
|
|
static void sigill_handler( int signum, siginfo_t *siginfo, void *sigcontext ) {
|
|
unsigned char *pc = siginfo->si_addr;
|
|
assert( pc[0] == 0x0f && pc[1] == 0x01 && pc[2] == 0xd5 );
|
|
siglongjmp( env, EPERM );
|
|
}
|
|
|
|
/*
|
|
* Same as above, but in case we do recognize the xend,
|
|
* but detect it is invalid (used outside a transaction)
|
|
* and generate a segv. Unfortunately then si_addr is,
|
|
* just zero, so we cannot add an assert/sanity check.
|
|
*/
|
|
static void segv_handler( int signum, siginfo_t *siginfo, void *sigcontext ) {
|
|
siglongjmp( env, EPERM );
|
|
}
|
|
|
|
/*
|
|
* Wrapper for pthread_rwlock_unlock which may execute xend
|
|
* unconditionally when used on a lock that is not locked.
|
|
*
|
|
* Note that we return 0 instead of EPERM because that is what
|
|
* glibc normally does - error reporting is optional.
|
|
*/
|
|
static int safe_pthread_rwlock_unlock( pthread_rwlock_t *rwlock ) {
|
|
struct sigaction sa_ill, sa_segv;
|
|
struct sigaction oldsa_ill, oldsa_segv;
|
|
int r;
|
|
|
|
sa_ill.sa_handler = NULL;
|
|
sa_ill.sa_sigaction = sigill_handler;
|
|
sigemptyset( &sa_ill.sa_mask );
|
|
sa_ill.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction( SIGILL, &sa_ill, &oldsa_ill );
|
|
|
|
sa_segv.sa_handler = NULL;
|
|
sa_segv.sa_sigaction = segv_handler;
|
|
sigemptyset( &sa_segv.sa_mask );
|
|
sa_segv.sa_flags = SA_SIGINFO;
|
|
|
|
sigaction( SIGSEGV, &sa_segv, &oldsa_segv );
|
|
|
|
if ( ( r = sigsetjmp( env, 1 ) ) == 0 ) {
|
|
r = pthread_rwlock_unlock( rwlock );
|
|
} else {
|
|
r = 0;
|
|
}
|
|
|
|
sigaction( SIGILL, &oldsa_ill, NULL );
|
|
sigaction( SIGSEGV, &oldsa_segv, NULL );
|
|
|
|
return r;
|
|
}
|
|
|
|
#define pthread_rwlock_unlock safe_pthread_rwlock_unlock
|