This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 8/8] nptl: ppc32: Fix Race conditions in pthread cancellation, (BZ#12683)
- From: Adhemerval Zanella <azanella at linux dot vnet dot ibm dot com>
- To: "GNU C. Library" <libc-alpha at sourceware dot org>
- Date: Wed, 08 Oct 2014 18:33:02 -0300
- Subject: [PATCH 8/8] nptl: ppc32: Fix Race conditions in pthread cancellation, (BZ#12683)
- Authentication-results: sourceware.org; auth=none
This patches adds the ppc32 modification required for the BZ#12683
fix.
--
* sysdeps/powerpc/nptl/pthreaddef.h (__pthread_get_ip): Add powerpc32
support.
* sysdeps/unix/sysv/linux/i386/fcntl.c (__fcntl_nocancel): Remove calls
to enable/disable asynchronous cancellation and use call cancellable
syscall entrypoint when required.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S (__socket):
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h (PSEUDO):
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
[SYSCALL_CANCEL_ERROR]: New macro.
[SYSCALL_CANCEL_ERRNO]: New macro.
---
diff --git a/sysdeps/powerpc/nptl/pthreaddef.h b/sysdeps/powerpc/nptl/pthreaddef.h
index 5fe1cdb..5402154 100644
--- a/sysdeps/powerpc/nptl/pthreaddef.h
+++ b/sysdeps/powerpc/nptl/pthreaddef.h
@@ -38,7 +38,11 @@
static inline
const char * __pthread_get_ip (const ucontext_t *uc)
{
+# ifdef __powerpc64__
return (char *)uc->uc_mcontext.gp_regs[PT_NIP];
+# else
+ return (char *)uc->uc_mcontext.uc_regs->gregs[PT_NIP];
+# endif
}
#endif
diff --git a/sysdeps/unix/sysv/linux/i386/fcntl.c b/sysdeps/unix/sysv/linux/i386/fcntl.c
index 570ed4d..b59aa5b 100644
--- a/sysdeps/unix/sysv/linux/i386/fcntl.c
+++ b/sysdeps/unix/sysv/linux/i386/fcntl.c
@@ -23,7 +23,7 @@
#include <sys/syscall.h>
-#ifndef NO_CANCELLATION
+#ifndef IS_IN_rtld
int
__fcntl_nocancel (int fd, int cmd, ...)
{
@@ -36,7 +36,7 @@ __fcntl_nocancel (int fd, int cmd, ...)
return INLINE_SYSCALL (fcntl64, 3, fd, cmd, arg);
}
-#endif /* NO_CANCELLATION */
+#endif
int
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S b/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
index 2261484..787d53c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/socket.S
@@ -40,7 +40,7 @@
/* 0(r1) and 4(r1) are reserved by the ABI, 8(r1), 12(r1), 16(r1) are used
for temp saves. 44(r1) is used to save r30. */
-#define stackblock 20
+#define STACKBLOCK 20
#ifndef __socket
# ifndef NO_WEAK_ALIAS
@@ -55,63 +55,58 @@ ENTRY(__socket)
stwu r1,-48(r1)
cfi_adjust_cfa_offset(48)
#if NARGS >= 1
- stw r3,stackblock(r1)
+ stw r3,STACKBLOCK(r1)
#endif
#if NARGS >= 2
- stw r4,4+stackblock(r1)
+ stw r4,4+STACKBLOCK(r1)
#endif
#if NARGS >= 3
- stw r5,8+stackblock(r1)
+ stw r5,8+STACKBLOCK(r1)
#endif
#if NARGS >= 4
- stw r6,12+stackblock(r1)
+ stw r6,12+STACKBLOCK(r1)
#endif
#if NARGS >= 5
- stw r7,16+stackblock(r1)
+ stw r7,16+STACKBLOCK(r1)
#endif
#if NARGS >= 6
- stw r8,20+stackblock(r1)
+ stw r8,20+STACKBLOCK(r1)
#endif
#if NARGS >= 7
#error too many arguments!
#endif
-#if defined NEED_CANCELLATION && defined CENABLE
+#ifdef NEED_CANCELLATION
SINGLE_THREAD_P
- bne- .Lsocket_cancel
+ bne- L(socket_cancel)
#endif
- li r3,P(SOCKOP_,socket)
- addi r4,r1,stackblock
- DO_CALL(SYS_ify(socketcall))
- addi r1,r1,48
- PSEUDO_RET
-
-#if defined NEED_CANCELLATION && defined CENABLE
-.Lsocket_cancel:
+#ifndef NEED_CANCELLATION
+ li r3,P(SOCKOP_,socket)
+ addi r4,r1,STACKBLOCK
+ DO_CALL(SYS_ify(socketcall))
+ addi r1,r1,48
+ bnslr+
+ b __syscall_error@local
+#else
+L(socket_cancel):
mflr r9
+ SETUP_PIC;
stw r9,52(r1)
cfi_offset (lr, 4)
- CENABLE
- stw r3,16(r1)
- li r3,P(SOCKOP_,socket)
- addi r4,r1,stackblock
- DO_CALL(SYS_ify(socketcall))
- mfcr r0
- stw r3,8(r1)
- stw r0,12(r1)
- lwz r3,16(r1)
- CDISABLE
- lwz r4,52(r1)
- lwz r0,12(r1)
- lwz r3,8(r1)
- mtlr r4
- mtcr r0
+
+ li r3,SYS_ify(socketcall)
+ li r4,P(SOCKOP_,socket)
+ addi r5,r1,STACKBLOCK
+ CANCEL_JUMPTARGET
+ lwz r9,52(r1)
addi r1,r1,48
- PSEUDO_RET
+ cfi_adjust_cfa_offset(-48)
+ mtlr r9
+ cfi_restore(lr)
+ b __syscall_cancel_error@local;
#endif
-
-PSEUDO_END (__socket)
+END (__socket)
#ifndef NO_WEAK_ALIAS
weak_alias (__socket, socket)
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
index b6eedcb..4015d998 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep-cancel.h
@@ -25,90 +25,73 @@
#if !defined NOT_IN_libc || defined IS_IN_libpthread || defined IS_IN_librt
+# ifdef NOT_IN_libc
+# define SETUP_PIC \
+ bcl 20,31,got_label; \
+got_label:
+
+# define CANCEL_JUMPTARGET \
+ stw r30,8(r1); \
+ mflr r30; \
+ addis r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@ha; \
+ addi r30,r30,_GLOBAL_OFFSET_TABLE_-got_label@l; \
+ bl __syscall_cancel@plt; \
+ lwz r30,8(r1)
+# else
+# define SETUP_PIC
+# if defined SHARED && defined PIC
+# define CANCEL_JUMPTARGET \
+ bl __GI___syscall_cancel@locaL
+# else
+# define CANCEL_JUMPTARGET \
+ bl __syscall_cancel
+# endif
+# endif
+
# undef PSEUDO
# define PSEUDO(name, syscall_name, args) \
.section ".text"; \
ENTRY (name) \
SINGLE_THREAD_P; \
- bne- .Lpseudo_cancel; \
- .type __##syscall_name##_nocancel,@function; \
- .globl __##syscall_name##_nocancel; \
- __##syscall_name##_nocancel: \
+ bne- L(pseudo_cancel); \
DO_CALL (SYS_ify (syscall_name)); \
- PSEUDO_RET; \
- .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \
- .Lpseudo_cancel: \
- stwu 1,-48(1); \
- cfi_adjust_cfa_offset (48); \
- mflr 9; \
- stw 9,52(1); \
+ bnslr+; \
+ b __syscall_error@local; \
+ L(pseudo_cancel): \
+ stwu r1,-16(r1); \
+ cfi_adjust_cfa_offset (16); \
+ mflr r0; \
+ SETUP_PIC; \
+ stw r0,20(r1); \
cfi_offset (lr, 4); \
- DOCARGS_##args; /* save syscall args around CENABLE. */ \
- CENABLE; \
- stw 3,16(1); /* store CENABLE return value (MASK). */ \
- UNDOCARGS_##args; /* restore syscall args. */ \
- DO_CALL (SYS_ify (syscall_name)); \
- mfcr 0; /* save CR/R3 around CDISABLE. */ \
- stw 3,8(1); \
- stw 0,12(1); \
- lwz 3,16(1); /* pass MASK to CDISABLE. */ \
- CDISABLE; \
- lwz 4,52(1); \
- lwz 0,12(1); /* restore CR/R3. */ \
- lwz 3,8(1); \
- mtlr 4; \
- mtcr 0; \
- addi 1,1,48;
-
-# define DOCARGS_0
-# define UNDOCARGS_0
-
-# define DOCARGS_1 stw 3,20(1); DOCARGS_0
-# define UNDOCARGS_1 lwz 3,20(1); UNDOCARGS_0
-
-# define DOCARGS_2 stw 4,24(1); DOCARGS_1
-# define UNDOCARGS_2 lwz 4,24(1); UNDOCARGS_1
-
-# define DOCARGS_3 stw 5,28(1); DOCARGS_2
-# define UNDOCARGS_3 lwz 5,28(1); UNDOCARGS_2
-
-# define DOCARGS_4 stw 6,32(1); DOCARGS_3
-# define UNDOCARGS_4 lwz 6,32(1); UNDOCARGS_3
-
-# define DOCARGS_5 stw 7,36(1); DOCARGS_4
-# define UNDOCARGS_5 lwz 7,36(1); UNDOCARGS_4
-
-# define DOCARGS_6 stw 8,40(1); DOCARGS_5
-# define UNDOCARGS_6 lwz 8,40(1); UNDOCARGS_5
-
-# ifdef IS_IN_libpthread
-# define CENABLE bl __pthread_enable_asynccancel@local
-# define CDISABLE bl __pthread_disable_asynccancel@local
-# elif !defined NOT_IN_libc
-# define CENABLE bl __libc_enable_asynccancel@local
-# define CDISABLE bl __libc_disable_asynccancel@local
-# elif defined IS_IN_librt
-# define CENABLE bl __librt_enable_asynccancel@local
-# define CDISABLE bl __librt_disable_asynccancel@local
-# else
-# error Unsupported library
-# endif
+ mr r9,r8; \
+ mr r8,r7; \
+ mr r7,r6; \
+ mr r6,r5; \
+ mr r5,r4; \
+ mr r4,r3; \
+ li r3,SYS_ify (syscall_name); \
+ CANCEL_JUMPTARGET; \
+ lwz r0,20(r1); \
+ addi r1,r1,16; \
+ cfi_adjust_cfa_offset (-16); \
+ mtlr r0; \
+ cfi_restore (lr); \
+ b __syscall_cancel_error@local;
+
+# undef PSEUDO_RET
+# define PSEUDO_RET
# ifndef __ASSEMBLER__
-# define SINGLE_THREAD_P \
- __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
- header.multiple_threads) == 0, 1)
+# define SINGLE_THREAD_P \
+ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \
+ header.multiple_threads) == 0, 1)
# else
-# define SINGLE_THREAD_P \
- lwz 10,MULTIPLE_THREADS_OFFSET(2); \
+# define SINGLE_THREAD_P \
+ lwz 10,MULTIPLE_THREADS_OFFSET(2); \
cmpwi 10,0
# endif
-#elif !defined __ASSEMBLER__
-
-# define SINGLE_THREAD_P (1)
-# define NO_CANCELLATION 1
-
#endif
#ifndef __ASSEMBLER__
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
index 1a5e37a..7701d66 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/sysdep.h
@@ -168,6 +168,14 @@
sc_ret; \
})
+#undef SYSCALL_CANCEL_ERROR
+#define SYSCALL_CANCEL_ERROR(err) \
+ (err > 0xfffffffffffff000UL)
+
+#undef SYSCALL_CANCEL_ERRNO
+#define SYSCALL_CANCEL_ERRNO(err) \
+ (-err)
+
/* Define a macro which expands inline into the wrapper code for a system
call. This use is for internal calls that do not need to handle errors
normally. It will never touch errno.