10 * Starting with glibc 2.20 some pthread calls may execute
11 * an xend instruction unconditionally when a lock is used in
12 * a way that is invalid so defined a sigill handler that can
13 * convert these invalid instructions to a normal error.
15 static void sigill_handler( int signum
, siginfo_t
*siginfo
, void *sigcontext
) {
16 unsigned char *pc
= siginfo
->si_addr
;
17 assert( pc
[0] == 0x0f && pc
[1] == 0x01 && pc
[2] == 0xd5 );
18 siglongjmp( env
, EPERM
);
22 * Same as above, but in case we do recognize the xend,
23 * but detect it is invalid (used outside a transaction)
24 * and generate a segv. Unfortunately then si_addr is,
25 * just zero, so we cannot add an assert/sanity check.
27 static void segv_handler( int signum
, siginfo_t
*siginfo
, void *sigcontext
) {
28 siglongjmp( env
, EPERM
);
32 * Wrapper for pthread_rwlock_unlock which may execute xend
33 * unconditionally when used on a lock that is not locked.
35 * Note that we return 0 instead of EPERM because that is what
36 * glibc normally does - error reporting is optional.
38 static int safe_pthread_rwlock_unlock( pthread_rwlock_t
*rwlock
) {
39 struct sigaction sa_ill
, sa_segv
;
40 struct sigaction oldsa_ill
, oldsa_segv
;
43 sa_ill
.sa_handler
= NULL
;
44 sa_ill
.sa_sigaction
= sigill_handler
;
45 sigemptyset( &sa_ill
.sa_mask
);
46 sa_ill
.sa_flags
= SA_SIGINFO
;
48 sigaction( SIGILL
, &sa_ill
, &oldsa_ill
);
50 sa_segv
.sa_handler
= NULL
;
51 sa_segv
.sa_sigaction
= segv_handler
;
52 sigemptyset( &sa_segv
.sa_mask
);
53 sa_segv
.sa_flags
= SA_SIGINFO
;
55 sigaction( SIGSEGV
, &sa_segv
, &oldsa_segv
);
57 if ( ( r
= sigsetjmp( env
, 1 ) ) == 0 ) {
58 r
= pthread_rwlock_unlock( rwlock
);
63 sigaction( SIGILL
, &oldsa_ill
, NULL
);
64 sigaction( SIGSEGV
, &oldsa_segv
, NULL
);
69 #define pthread_rwlock_unlock safe_pthread_rwlock_unlock