summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-08-29 14:01:46 -0400
committerRich Felker <dalias@aerifal.cx>2018-08-29 14:01:46 -0400
commit35cd7c0950b1cb98b62e6dfb2be87e345dac75dd (patch)
tree2d2e13ac6f781cfb1504021e7860d05919082896
parent0ec49dab6794166d67fae4764ce7fdea42ea6103 (diff)
downloadmusl-35cd7c0950b1cb98b62e6dfb2be87e345dac75dd.tar.gz
fix async thread cancellation on sh-fdpic
if __cp_cancel was reached via __syscall_cp, r12 will necessarily still contain a GOT pointer (for libc.so or for the static-linked main program) valid for entering __cancel. however, in the case of async cancellation, r12 may contain any scratch value; it's not necessarily even a valid GOT pointer for the code that was interrupted. unlike in commit 0ec49dab6794166d67fae4764ce7fdea42ea6103 where the corresponding issue was fixed for powerpc64, there is fundamentally no way for fdpic code to recompute its GOT pointer. so a new mechanism is introduced for cancel_handler to write a GOT register value into the interrupted context on archs where it is needed.
-rw-r--r--arch/sh/pthread_arch.h5
-rw-r--r--src/thread/pthread_cancel.c3
2 files changed, 8 insertions, 0 deletions
diff --git a/arch/sh/pthread_arch.h b/arch/sh/pthread_arch.h
index 41fefacf..a7dd27a6 100644
--- a/arch/sh/pthread_arch.h
+++ b/arch/sh/pthread_arch.h
@@ -10,3 +10,8 @@ static inline struct pthread *__pthread_self()
#define TP_ADJ(p) ((char *)(p) + sizeof(struct pthread))
#define MC_PC sc_pc
+
+#ifdef __FDPIC__
+#define MC_GOT sc_regs[12]
+#define CANCEL_GOT (*(uintptr_t *)((char *)__syscall_cp_asm+sizeof(uintptr_t)))
+#endif
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
index bf07dbeb..5d458af2 100644
--- a/src/thread/pthread_cancel.c
+++ b/src/thread/pthread_cancel.c
@@ -61,6 +61,9 @@ static void cancel_handler(int sig, siginfo_t *si, void *ctx)
if (self->cancelasync || pc >= (uintptr_t)__cp_begin && pc < (uintptr_t)__cp_end) {
uc->uc_mcontext.MC_PC = (uintptr_t)__cp_cancel;
+#ifdef CANCEL_GOT
+ uc->uc_mcontext.MC_GOT = CANCEL_GOT;
+#endif
return;
}