Fix backtraces on cancellation points

This commit is contained in:
Justine Tunney 2022-11-04 19:55:41 -07:00
parent 022536cab6
commit 0d7c265392
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
4 changed files with 22 additions and 13 deletions

View file

@ -948,9 +948,9 @@ static dontdiscard __asan_die_f *__asan_report_memory_fault(
static void *__asan_morgue_add(void *p) { static void *__asan_morgue_add(void *p) {
return atomic_exchange_explicit( return atomic_exchange_explicit(
__asan_morgue.p + (atomic_fetch_add_explicit(&__asan_morgue.i, 1, __asan_morgue.p + (atomic_fetch_add_explicit(&__asan_morgue.i, 1,
memory_order_acquire) & memory_order_acq_rel) &
(ARRAYLEN(__asan_morgue.p) - 1)), (ARRAYLEN(__asan_morgue.p) - 1)),
p, memory_order_release); p, memory_order_acq_rel);
} }
static void __asan_morgue_flush(void) { static void __asan_morgue_flush(void) {

View file

@ -53,7 +53,6 @@ static ssize_t GetDevRandom(char *p, size_t n) {
pthread_cleanup_push((void *)sys_close, (void *)(intptr_t)fd); pthread_cleanup_push((void *)sys_close, (void *)(intptr_t)fd);
rc = sys_read(fd, p, n); rc = sys_read(fd, p, n);
pthread_cleanup_pop(1); pthread_cleanup_pop(1);
close(fd);
return rc; return rc;
} }

View file

@ -108,6 +108,9 @@ __pid: .quad 0
.endobj __pid,globl,hidden .endobj __pid,globl,hidden
.previous .previous
systemfive_cp:
push %rbp
mov %rsp,%rbp
systemfive_cancellable: # our pthread_cancel() miracle code systemfive_cancellable: # our pthread_cancel() miracle code
cmpb $0,__tls_enabled(%rip) # inspired by the musl libc design! cmpb $0,__tls_enabled(%rip) # inspired by the musl libc design!
je 1f # we handle linux and bsd together! je 1f # we handle linux and bsd together!
@ -118,12 +121,12 @@ systemfive_cancellable: # our pthread_cancel() miracle code
testb $PT_NOCANCEL,0x00(%r10) # PosixThread::flags testb $PT_NOCANCEL,0x00(%r10) # PosixThread::flags
jnz 1f # canceler no cancelling jnz 1f # canceler no cancelling
cmp $0,0x04(%r10) # PosixThread::cancelled cmp $0,0x04(%r10) # PosixThread::cancelled
jne _pthread_cancel_sys # tail call for masked mode jne systemfive_cancel # tail call for masked mode
.weak _pthread_cancel_sys # must be linked if we're cancelled
1: mov %rcx,%r10 # move the fourth argument 1: mov %rcx,%r10 # move the fourth argument
clc # no cancellable system calls exist clc # no cancellable system calls exist
syscall # that have 7+ args on the bsd OSes syscall # that have 7+ args on the bsd OSes
systemfive_cancellable_end: # i/o calls park here for long time systemfive_cancellable_end: # i/o calls park here for long time
pop %rbp
jc systemfive_errno jc systemfive_errno
jmp 0f jmp 0f
jc 3f # we're now out of the limbo state! jc 3f # we're now out of the limbo state!
@ -143,10 +146,15 @@ systemfive_cancellable_end: # i/o calls park here for long time
jnz systemfive_errno # cancellation is disabled jnz systemfive_errno # cancellation is disabled
cmp $0,0x04(%rcx) # PosixThread::cancelled cmp $0,0x04(%rcx) # PosixThread::cancelled
je systemfive_errno # we aren't actually cancelled je systemfive_errno # we aren't actually cancelled
jmp _pthread_cancel_sys # now we are in fact cancelled jmp 1f # now we are in fact cancelled
.endfn systemfive_cancellable,globl,hidden systemfive_cancel:
pop %rbp
1: jmp _pthread_cancel_sys # must be linked if we're cancelled
.weak _pthread_cancel_sys
.globl systemfive_cancellable_end .globl systemfive_cancellable_end
.hidden systemfive_cancellable_end .globl systemfive_cancellable
.globl systemfive_cancel
.endfn systemfive_cp
.Lanchorpoint: .Lanchorpoint:
#if SupportsLinux() || SupportsMetal() #if SupportsLinux() || SupportsMetal()
@ -155,7 +163,7 @@ systemfive_linux:
cmp $0xfff,%eax # checks if unsupported by platform cmp $0xfff,%eax # checks if unsupported by platform
je systemfive_enosys # never taken branches cost nothing je systemfive_enosys # never taken branches cost nothing
btr $11,%eax # 0x800 means a call is cancellable btr $11,%eax # 0x800 means a call is cancellable
jc systemfive_cancellable # it is handled by the holiest code jc systemfive_cp # it is handled by the holiest code
mov %rcx,%r10 # syscall instruction clobbers %rcx mov %rcx,%r10 # syscall instruction clobbers %rcx
push %rbp # linux never reads args from stack push %rbp # linux never reads args from stack
mov %rsp,%rbp # having frame will help backtraces mov %rsp,%rbp # having frame will help backtraces
@ -210,7 +218,7 @@ systemfive_bsd:
cmp $0xfff,%ax cmp $0xfff,%ax
je systemfive_enosys je systemfive_enosys
btr $11,%eax # checks/reset the 800 cancellable bit btr $11,%eax # checks/reset the 800 cancellable bit
jc systemfive_cancellable jc systemfive_cp
mov %rcx,%r10 mov %rcx,%r10
syscall # bsd will need arg on stack sometimes syscall # bsd will need arg on stack sometimes
jc systemfive_errno # bsd sets carry flag if %rax is errno jc systemfive_errno # bsd sets carry flag if %rax is errno

View file

@ -34,8 +34,10 @@
#include "libc/thread/thread.h" #include "libc/thread/thread.h"
#include "libc/thread/tls.h" #include "libc/thread/tls.h"
extern const char systemfive_cancellable[] hidden; int systemfive_cancel(void);
extern const char systemfive_cancellable_end[] hidden;
extern const char systemfive_cancellable[];
extern const char systemfive_cancellable_end[];
int _pthread_cancel_sys(void) { int _pthread_cancel_sys(void) {
struct PosixThread *pt; struct PosixThread *pt;
@ -57,7 +59,7 @@ static void OnSigCancel(int sig, siginfo_t *si, void *ctx) {
if ((pt->flags & PT_ASYNC) || if ((pt->flags & PT_ASYNC) ||
(systemfive_cancellable <= (char *)uc->uc_mcontext.rip && (systemfive_cancellable <= (char *)uc->uc_mcontext.rip &&
(char *)uc->uc_mcontext.rip < systemfive_cancellable_end)) { (char *)uc->uc_mcontext.rip < systemfive_cancellable_end)) {
uc->uc_mcontext.rip = (intptr_t)_pthread_cancel_sys; uc->uc_mcontext.rip = (intptr_t)systemfive_cancel;
} else { } else {
tkill(atomic_load_explicit(&tib->tib_tid, memory_order_relaxed), sig); tkill(atomic_load_explicit(&tib->tib_tid, memory_order_relaxed), sig);
} }