@@ -1,3 +1,33 @@
+2016-04-26 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ [BZ #19957]
+ * sysdeps/unix/sysv/linux/Makefile [$(subdir) == nptl] (test): Remove
+ tst-getpid2.
+ (test): Add tst-clone2.
+ * sysdeps/unix/sysv/linux/tst-clone2.c: New file.
+ * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Do not change
+ pid/tid fields for CLONE_VM.
+ * sysdeps/unix/sysv/linux/alpha/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/arm/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/ia64/clone2.S (__clone): Likewise,
+ * sysdeps/unix/sysv/linux/i386/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/mips/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/m68k/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/nios2/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc32/clone.S (__clone):
+ Likewise.
+ * sysdeps/unix/sysv/linux/powerpc/powerpc64/clone.S (__clone):
+ Likewise.
+ * sysdeps/unix/sysv/linux/s390/s390-32/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/s390/s390-64/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/sh/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc32/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/sparc/sparc64/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/tile/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/x86_64/clone.S (__clone): Likewise.
+ * sysdeps/unix/sysv/linux/tst-getpid2.c: Remove file.
+
2016-04-26 Joseph Myers <joseph@codesourcery.com>
[BZ #19996]
@@ -42,7 +42,7 @@ sysdep_headers += sys/mount.h sys/acct.h sys/sysctl.h \
bits/socket_type.h bits/syscall.h bits/sysctl.h \
bits/mman-linux.h
-tests += tst-clone tst-fanotify tst-personality
+tests += tst-clone tst-clone2 tst-fanotify tst-personality
# Generate the list of SYS_* macros for the system calls (__NR_* macros).
@@ -194,7 +194,7 @@ CFLAGS-gai.c += -DNEED_NETLINK
endif
ifeq ($(subdir),nptl)
-tests += tst-setgetname tst-align-clone tst-getpid1 tst-getpid2 \
+tests += tst-setgetname tst-align-clone tst-getpid1 \
tst-thread-affinity-pthread tst-thread-affinity-pthread2 \
tst-thread-affinity-sched
endif
@@ -72,17 +72,15 @@ thread_start:
cfi_undefined (x30)
mov x29, 0
- tbnz x11, #CLONE_THREAD_BIT, 3f
- mov x0, #-1
- tbnz x11, #CLONE_VM_BIT, 2f
+ tbnz x11, #CLONE_VM_BIT, 1f
+
mov x8, #SYS_ify(getpid)
svc 0x0
-2:
mrs x1, tpidr_el0
sub x1, x1, #PTHREAD_SIZEOF
str w0, [x1, #PTHREAD_PID_OFFSET]
str w0, [x1, #PTHREAD_TID_OFFSET]
-3:
+1:
/* Pick the function arg and execute. */
mov x0, x12
@@ -24,7 +24,6 @@
#include <bits/errno.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags,
void *arg, pid_t *ptid, void *tls, pid_t *ctid);
@@ -94,7 +93,7 @@ thread_start:
/* Check and see if we need to reset the PID. */
ldq t0, 16(sp)
- lda t1, CLONE_THREAD
+ lda t1, CLONE_VM
and t0, t1, t2
beq t2, 2f
1:
@@ -123,11 +122,7 @@ thread_start:
.align 4
2:
rduniq
- lda t1, CLONE_VM
mov v0, s0
- lda v0, -1
- and t0, t1, t2
- bne t2, 3f
lda v0, __NR_getxpid
callsys
3:
@@ -70,19 +70,16 @@ PSEUDO_END (__clone)
1:
.fnstart
.cantunwind
- tst ip, #CLONE_THREAD
- bne 3f
+ tst ip, #CLONE_VM
+ bne 2f
GET_TLS (lr)
mov r1, r0
- tst ip, #CLONE_VM
ldr r7, =SYS_ify(getpid)
- ite ne
- movne r0, #-1
- swieq 0x0
+ swi 0x0
NEGOFF_ADJ_BASE (r1, TID_OFFSET)
str r0, NEGOFF_OFF1 (r1, TID_OFFSET)
str r0, NEGOFF_OFF2 (r1, PID_OFFSET, TID_OFFSET)
-3:
+2:
@ pick the function arg and call address off the stack and execute
ldr r0, [sp, #4]
ldr ip, [sp], #8
@@ -133,19 +133,13 @@ ENTRY(__clone)
.LthreadStart:
# define CLONE_VM_BIT 23 /* 0x00000100 */
-# define CLONE_THREAD_BIT 15 /* 0x00010000 */
/* Load original clone flags.
- If CLONE_THREAD was passed, don't reset the PID/TID.
- If CLONE_VM was passed, we need to store -1 to PID/TID.
- If CLONE_VM and CLONE_THREAD were not set store the result
- of getpid to PID/TID. */
+ If CLONE_VM was passed, don't modify PID/TID.
+ Otherwise store the result of getpid to PID/TID. */
ldw -56(%sp), %r26
- bb,<,n %r26, CLONE_THREAD_BIT, 1f
- bb,< %r26, CLONE_VM_BIT, 2f
- ldi -1, %ret0
+ bb,<,n %r26, CLONE_VM_BIT, 1f
ble 0x100(%sr2, %r0)
ldi __NR_getpid, %r20
-2:
mfctl %cr27, %r26
stw %ret0, PID_THREAD_OFFSET(%r26)
stw %ret0, TID_THREAD_OFFSET(%r26)
@@ -40,7 +40,6 @@
#define SYS_clone 120
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
.text
ENTRY (__clone)
@@ -108,7 +107,7 @@ L(thread_start):
cfi_undefined (eip);
/* Note: %esi is zero. */
movl %esi,%ebp /* terminate the stack frame */
- testl $CLONE_THREAD, %edi
+ testl $CLONE_VM, %edi
je L(newpid)
L(haspid):
call *%ebx
@@ -124,9 +123,6 @@ L(here):
.subsection 2
L(newpid):
- testl $CLONE_VM, %edi
- movl $-1, %eax
- jne L(nomoregetpid)
movl $SYS_ify(getpid), %eax
ENTER_KERNEL
L(nomoregetpid):
@@ -67,12 +67,10 @@ ENTRY(__clone2)
(CHILD) mov loc0=gp
(PARENT) ret
;;
- tbit.nz p6,p0=in3,16 /* CLONE_THREAD */
- tbit.z p7,p10=in3,8 /* CLONE_VM */
+ tbit.nz p6,p0=in3,8 /* CLONE_VM */
(p6) br.cond.dptk 1f
;;
mov r15=SYS_ify (getpid)
-(p10) addl r8=-1,r0
(p7) break __BREAK_SYSCALL
;;
add r9=PID,r13
@@ -25,7 +25,6 @@
#include <tls.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
void *parent_tidptr, void *tls, void *child_tidptr) */
@@ -100,16 +99,10 @@ thread_start:
cfi_undefined (pc) /* Mark end of stack */
subl %fp, %fp /* terminate the stack frame */
/* Check and see if we need to reset the PID. */
- movel %d1, %a1
- andl #CLONE_THREAD, %d1
- jne donepid
- movel %a1, %d1
- movel #-1, %d0
andl #CLONE_VM, %d1
- jne gotpid
+ jne donepid
movel #SYS_ify (getpid), %d0
trap #0
-gotpid:
movel %a0, -(%sp)
movel %d0, -(%sp)
bsrl __m68k_read_tp@PLTPC
@@ -131,9 +131,8 @@ L(thread_start):
/* The stackframe has been created on entry of clone(). */
/* Check and see if we need to reset the PID. */
- LONG_L a0,(PTRSIZE*2)(sp)
- and a1,a0,CLONE_THREAD
- beqz a1,L(restore_pid)
+ and a1,a0,CLONE_VM
+ beqz a1,L(restore_pid)
L(donepid):
/* Restore the arg for user's function. */
@@ -153,12 +152,8 @@ L(donepid):
#endif
L(restore_pid):
- and a1,a0,CLONE_VM
- li v0,-1
- bnez a1,L(gotpid)
li v0,__NR_getpid
syscall
-L(gotpid):
READ_THREAD_POINTER(v1)
INT_S v0,PID_OFFSET(v1)
INT_S v0,TID_OFFSET(v1)
@@ -26,7 +26,6 @@
#include <tcb-offsets.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
void *parent_tidptr, void *tls, void *child_tidptr) */
@@ -71,13 +70,9 @@ thread_start:
/* We expect the argument registers to be preserved across system
calls and across task cloning, so flags should be in r4 here. */
- andhi r2, r4, %hi(CLONE_THREAD)
+ andi r2, r4, CLONE_VM
bne r2, zero, 2f
- andi r3, r4, CLONE_VM
- movi r2, -1
- bne r3, zero, 3f
DO_CALL (getpid, 0)
-3:
stw r2, PID_OFFSET(r23)
stw r2, TID_OFFSET(r23)
2:
@@ -76,13 +76,11 @@ ENTRY (__clone)
crandc cr1*4+eq,cr1*4+eq,cr0*4+so
bne- cr1,L(parent) /* The '-' is to minimise the race. */
- andis. r0,r28,CLONE_THREAD>>16
- bne+ r0,L(oldpid)
- andi. r0,r28,CLONE_VM
- li r3,-1
- bne- r0,L(nomoregetpid)
+ /* If CLONE_VM is set do not update the pid/tid field. */
+ andi. r0,r29,CLONE_VM
+ bne+ cr0,L(oldpid)
+
DO_CALL(SYS_ify(getpid))
-L(nomoregetpid):
stw r3,TID(r2)
stw r3,PID(r2)
L(oldpid):
@@ -78,13 +78,11 @@ ENTRY (__clone)
crandc cr1*4+eq,cr1*4+eq,cr0*4+so
bne- cr1,L(parent) /* The '-' is to minimise the race. */
- andis. r0,r29,CLONE_THREAD>>16
+ /* If CLONE_VM is set do not update the pid/tid field. */
+ rldicl. r0,r29,56,63 /* flags & CLONE_VM. */
bne+ cr0,L(oldpid)
- andi. r0,r29,CLONE_VM
- li r3,-1
- bne- cr0,L(nomoregetpid)
+
DO_CALL(SYS_ify(getpid))
-L(nomoregetpid):
stw r3,TID(r13)
stw r3,PID(r13)
L(oldpid):
@@ -54,13 +54,10 @@ error:
PSEUDO_END (__clone)
thread_start:
- tmh %r3,1 /* CLONE_THREAD == 0x00010000 */
- jne 1f
- lhi %r2,-1
tml %r3,256 /* CLONE_VM == 0x00000100 */
- jne 2f
+ jne 1f
svc SYS_ify(getpid)
-2: ear %r3,%a0
+ ear %r3,%a0
st %r2,PID(%r3)
st %r2,TID(%r3)
1:
@@ -55,13 +55,10 @@ error:
PSEUDO_END (__clone)
thread_start:
- tmh %r3,1 /* CLONE_THREAD == 0x00010000 */
+ tmll %r3,256 /* CLONE_VM == 0x00000100 */
jne 1f
- lhi %r2,-1
- tml %r3,256 /* CLONE_VM == 0x00000100 */
- jne 2f
svc SYS_ify(getpid)
-2: ear %r3,%a0
+ ear %r3,%a0
sllg %r3,%r3,32
ear %r3,%a1
st %r2,PID(%r3)
@@ -67,15 +67,11 @@ ENTRY(__clone)
/* terminate the stack frame */
mov #0, r14
mov r4, r0
- shlr16 r0
- tst #1, r0 // CLONE_THREAD = (1 << 16)
+ shlr8 r0
+ tst #1, r0 // CLONE_VM = (1 << 8)
bf/s 4f
mov r4, r0
/* new pid */
- shlr8 r0
- tst #1, r0 // CLONE_VM = (1 << 8)
- bf/s 3f
- mov #-1, r0
mov #+SYS_ify(getpid), r3
trapa #0x15
3:
@@ -25,7 +25,6 @@
#include <sysdep.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@@ -80,15 +79,10 @@ END(__clone)
.type __thread_start,@function
__thread_start:
- sethi %hi(CLONE_THREAD), %l0
- andcc %g4, %l0, %g0
+ andcc %g4, CLONE_VM, %g0
bne 1f
- andcc %g4, CLONE_VM, %g0
- bne,a 2f
- mov -1,%o0
set __NR_getpid,%g1
ta 0x10
-2:
st %o0,[%g7 + PID]
st %o0,[%g7 + TID]
1:
@@ -25,7 +25,6 @@
#include <sysdep.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* int clone(int (*fn)(void *arg), void *child_stack, int flags, void *arg,
pid_t *ptid, void *tls, pid_t *ctid); */
@@ -77,15 +76,11 @@ END(__clone)
.type __thread_start,@function
__thread_start:
- sethi %hi(CLONE_THREAD), %l0
- andcc %g4, %l0, %g0
+ andcc %g4, CLONE_VM, %g0
bne,pt %icc, 1f
- andcc %g4, CLONE_VM, %g0
- bne,a,pn %icc, 2f
- mov -1,%o0
set __NR_getpid,%g1
ta 0x6d
-2: st %o0,[%g7 + PID]
+ st %o0,[%g7 + PID]
st %o0,[%g7 + TID]
1:
mov %g0, %fp /* terminate backtrace */
@@ -164,43 +164,31 @@ ENTRY (__clone)
cfi_def_cfa_offset (FRAME_SIZE)
cfi_undefined (lr)
/* Check and see if we need to reset the PID, which we do if
- CLONE_THREAD isn't set, i.e. we're not staying in the thread group.
- If CLONE_VM is set, we're doing some kind of thread-like clone,
- so we set the tid/pid to -1 to disable using the cached values
- in getpid(). Otherwise (if CLONE_VM isn't set), it's a
+ CLONE_VM isn't set, i.e. we're do not share the same pthread_t
+ with parent. Otherwise (if CLONE_VM isn't set), it's a
fork-like clone, and we go ahead and write the cached values
from the true system pid (retrieved via __NR_getpid syscall). */
#ifdef __tilegx__
{
moveli r0, hw1_last(CLONE_VM)
- moveli r1, hw1_last(CLONE_THREAD)
}
{
shl16insli r0, r0, hw0(CLONE_VM)
- shl16insli r1, r1, hw0(CLONE_THREAD)
}
#else
{
moveli r0, lo16(CLONE_VM)
- moveli r1, lo16(CLONE_THREAD)
}
{
auli r0, r0, ha16(CLONE_VM)
- auli r1, r1, ha16(CLONE_THREAD)
}
#endif
{
and r0, r30, r0
- and r1, r30, r1
- }
- BNEZ r1, .Lno_reset_pid /* CLONE_THREAD is set */
- {
- movei r0, -1
- BNEZ r0, .Lgotpid /* CLONE_VM is set */
}
+ BNEZ r0, .Lno_reset_pid /* CLONE_VM is set */
moveli TREG_SYSCALL_NR_NAME, __NR_getpid
swint1
-.Lgotpid:
ADDLI_PTR r2, tp, PID_OFFSET
{
ST4 r2, r0
new file mode 100644
@@ -0,0 +1,178 @@
+/* Test if CLONE_VM does not change pthread pid/tid field (BZ #19957)
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <sched.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <tls.h> /* for THREAD_* macros. */
+
+static int sig;
+static int pipefd[2];
+
+static int
+f (void *a)
+{
+ close (pipefd[0]);
+
+ pid_t pid = THREAD_GETMEM (THREAD_SELF, pid);
+ pid_t tid = THREAD_GETMEM (THREAD_SELF, tid);
+
+ while (write (pipefd[1], &pid, sizeof pid) < 0)
+ continue;
+ while (write (pipefd[1], &tid, sizeof tid) < 0)
+ continue;
+
+ return 0;
+}
+
+
+static int
+clone_test (int clone_flags)
+{
+ sig = SIGRTMIN;
+ sigset_t ss;
+ sigemptyset (&ss);
+ sigaddset (&ss, sig);
+ if (sigprocmask (SIG_BLOCK, &ss, NULL) != 0)
+ {
+ printf ("sigprocmask failed: %m\n");
+ return 1;
+ }
+
+ if (pipe2 (pipefd, O_CLOEXEC))
+ {
+ printf ("sigprocmask failed: %m\n");
+ return 1;
+ }
+
+ pid_t ppid = getpid ();
+
+#ifdef __ia64__
+ extern int __clone2 (int (*__fn) (void *__arg), void *__child_stack_base,
+ size_t __child_stack_size, int __flags,
+ void *__arg, ...);
+ char st[256 * 1024] __attribute__ ((aligned));
+ pid_t p = __clone2 (f, st, sizeof (st), clone_flags, 0);
+#else
+ char st[128 * 1024] __attribute__ ((aligned));
+#if _STACK_GROWS_DOWN
+ pid_t p = clone (f, st + sizeof (st), clone_flags, 0);
+#elif _STACK_GROWS_UP
+ pid_t p = clone (f, st, clone_flags, 0);
+#else
+#error "Define either _STACK_GROWS_DOWN or _STACK_GROWS_UP"
+#endif
+#endif
+ close (pipefd[1]);
+
+ if (p == -1)
+ {
+ printf ("clone failed: %m\n");
+ return 1;
+ }
+
+ pid_t pid, tid;
+ if (read (pipefd[0], &pid, sizeof pid) != sizeof pid)
+ {
+ printf ("read pid failed: %m\n");
+ kill (p, SIGKILL);
+ return 1;
+ }
+ if (read (pipefd[0], &tid, sizeof tid) != sizeof tid)
+ {
+ printf ("read pid failed: %m\n");
+ kill (p, SIGKILL);
+ return 1;
+ }
+
+ close (pipefd[0]);
+
+ int ret = 0;
+
+ /* For CLONE_VM glibc clone implementation does not change the pthread
+ pid/tid field. */
+ if ((clone_flags & CLONE_VM) == CLONE_VM)
+ {
+ if ((ppid != pid) || (ppid != tid))
+ {
+ printf ("parent pid (%i) != received pid/tid (%i/%i)\n",
+ (int)ppid, (int)pid, (int)tid);
+ ret = 1;
+ }
+ }
+ /* For any other flag clone updates the new pthread pid and tid with
+ the clone return value. */
+ else
+ {
+ if ((p != pid) || (p != tid))
+ {
+ printf ("child pid (%i) != received pid/tid (%i/%i)\n",
+ (int)p, (int)pid, (int)tid);
+ ret = 1;
+ }
+ }
+
+ int e;
+ if (waitpid (p, &e, __WCLONE) != p)
+ {
+ puts ("waitpid failed");
+ kill (p, SIGKILL);
+ return 1;
+ }
+ if (!WIFEXITED (e))
+ {
+ if (WIFSIGNALED (e))
+ printf ("died from signal %s\n", strsignal (WTERMSIG (e)));
+ else
+ puts ("did not terminate correctly");
+ return 1;
+ }
+ if (WEXITSTATUS (e) != 0)
+ {
+ printf ("exit code %d\n", WEXITSTATUS (e));
+ return 1;
+ }
+
+ return ret;
+}
+
+int
+do_test (void)
+{
+ /* First, check that the clone implementation, without any flag, updates
+ the struct pthread to contain the new PID and TID. */
+ int ret = clone_test (0);
+ /* Second, check that with CLONE_VM the struct pthread PID and TID fields
+ remain unmodified after the clone. Any modifications would cause problem
+ for the parent as described in bug 19957. */
+ ret += clone_test (CLONE_VM);
+ return ret;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
deleted file mode 100644
@@ -1,2 +0,0 @@
-#define TEST_CLONE_FLAGS CLONE_VM
-#include "tst-getpid1.c"
@@ -24,7 +24,6 @@
#include <asm-syntax.h>
#define CLONE_VM 0x00000100
-#define CLONE_THREAD 0x00010000
/* The userland implementation is:
int clone (int (*fn)(void *arg), void *child_stack, int flags, void *arg),
@@ -92,14 +91,11 @@ L(thread_start):
the outermost frame obviously. */
xorl %ebp, %ebp
- testq $CLONE_THREAD, %rdi
+ andq $CLONE_VM, %rdi
jne 1f
- testq $CLONE_VM, %rdi
- movl $-1, %eax
- jne 2f
movl $SYS_ify(getpid), %eax
syscall
-2: movl %eax, %fs:PID
+ movl %eax, %fs:PID
movl %eax, %fs:TID
1: