diff mbox series

[v2,02/21] nptl: Fix testcases for new pthread cancellation mechanism

Message ID 1519679016-12241-3-git-send-email-adhemerval.zanella@linaro.org
State New
Headers show
Series nptl: Fix Race conditions in pthread cancellation (BZ#12683) | expand

Commit Message

Adhemerval Zanella Netto Feb. 26, 2018, 9:03 p.m. UTC
From: Adhemerval Zanella <adhemerval.zanella@linaro.com>


With upcoming fix for BZ#12683, pthread cancellation does not act for:

  1. If syscall is blocked but with some side effects already having
     taken place (e.g. a partial read or write).
  2. After the syscall has returned.

The main change is due the fact programs need to act in syscalls with
side-effects (for instance, to avoid leak of allocated resources or
handle partial read/write).

This patch changes the NPTL testcase that assumes the old behavior and
also remove the tst-cancel-wrappers.sh test (which checks for symbols
that will not exist anymore).  For tst-cancel{2,3} case it remove the
pipe close because it might cause the write syscall to return with
side effects if the close is executed before the pthread cancel.

It also changes how to call the read syscall on tst-backtrace{5,6}
to use syscall instead of read cancelable syscall to avoid need to
handle the cancelable bridge function calls.  It requires a change
on powerpc syscall implementation to create a stackframe, since
powerpc backtrace rely on such information.

Checked on i686-linux-gnu, x86_64-linux-gnu, x86_64-linux-gnux32,
aarch64-linux-gnu, arm-linux-gnueabihf, powerpc64le-linux-gnu,
powerpc-linux-gnu, sparcv9-linux-gnu, and sparc64-linux-gnu.

	* debug/tst-backtrace5.c (handle_signal): Check for syscall
	instead of read.
	(fn): Issue the read syscall instead of call the cancellable
	syscall.
	* nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove
	tst-cancel-wrappers.sh.
	* nptl/tst-cancel-wrappers.sh: Remove file.
	* nptl/tst-cancel2.c (do_test): Do not close pipe.
	* nptl/tst-cancel3.c (do_test): Likewise.
	* nptl/tst-cancel4.c (tf_write): Handle cancelled syscall with
	side-effects.
	(tf_send): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/syscall.S (syscall): Create stack
	frame.
---
 ChangeLog                   | 14 ++++++-
 debug/tst-backtrace5.c      | 28 ++++++++------
 nptl/Makefile               | 17 +--------
 nptl/tst-cancel-wrappers.sh | 92 ---------------------------------------------
 nptl/tst-cancel2.c          |  3 --
 nptl/tst-cancel3.c          |  3 --
 nptl/tst-cancel4.c          |  8 ++++
 7 files changed, 39 insertions(+), 126 deletions(-)
 delete mode 100644 nptl/tst-cancel-wrappers.sh

-- 
2.7.4

Comments

Andreas Schwab Feb. 26, 2018, 9:43 p.m. UTC | #1
On Feb 26 2018, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:

> @@ -743,6 +747,10 @@ tf_send (void *arg)

>    char mem[WRITE_BUFFER_SIZE];

>  

>    send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0);

> +  /* Thez send can return a value higher than 0 (meaning partial send)


s/Thez/The/

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 58CA 54C7 6D53 942B 1756  01D3 44D5 214B 8276 4ED5
"And now for something completely different."
Adhemerval Zanella Netto Feb. 27, 2018, 12:05 p.m. UTC | #2
On 26/02/2018 18:43, Andreas Schwab wrote:
> On Feb 26 2018, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:

> 

>> @@ -743,6 +747,10 @@ tf_send (void *arg)

>>    char mem[WRITE_BUFFER_SIZE];

>>  

>>    send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0);

>> +  /* Thez send can return a value higher than 0 (meaning partial send)

> 

> s/Thez/The/

> 

> Andreas.

> 


Ack, fixed locally.
Zack Weinberg May 7, 2018, 2:49 a.m. UTC | #3
On 26 Feb 2018, Adhemerval Zanella wrote:
> With upcoming fix for BZ#12683, pthread cancellation does not act for:

>

>   1. If syscall is blocked but with some side effects already having

>      taken place (e.g. a partial read or write).

>   2. After the syscall has returned.

>

> The main change is due the fact programs need to act in syscalls with

> side-effects (for instance, to avoid leak of allocated resources or

> handle partial read/write).

>

> This patch changes the NPTL testcase that assumes the old behavior and

> also remove the tst-cancel-wrappers.sh test (which checks for symbols

> that will not exist anymore).


It's OK and expected that we have to adjust test cases that were
expecting the old behavior ...

> For tst-cancel{2,3} case it remove the pipe close because it might

> cause the write syscall to return with side effects if the close is

> executed before the pthread cancel.


... however, this change appears to be wrong.  If cancellation is
broken, these tests will now deadlock rather than failing cleanly.

If I understand correctly, the problem you're trying to avoid is that
the 'tf' thread could conceivably receive the closed-pipe event before
the cancellation signal, even though the 'do_test' thread triggers the
cancellation signal first.  I don't know of any way to fix this 100%,
but I think it would be good enough to use pthread_timedjoin_np to
sleep for a hundred milliseconds or so in the 'do_test' thread, and
then close the pipe if the 'tf' thread is still alive.

(tst-cancel4.c appears to be trying to ensure that cancellations are
pending with a pthread_barrier_t, but as far as I know there's no
guarantee that if a thread does

   pthread_cancel(th);
   pthread_barrier_wait(ba);

where 'th' also waits on 'ba', the SIGCANCEL will actually be
delivered before the barrier unblocks, either.  Feh.)

> It also changes how to call the read syscall on tst-backtrace{5,6}

> to use syscall instead of read cancelable syscall to avoid need to

> handle the cancelable bridge function calls.  It requires a change

> on powerpc syscall implementation to create a stackframe, since

> powerpc backtrace rely on such information.


It doesn't look technically difficult to me to handle an additional
stack frame or two in the trace.  They're always going to be there,
aren't they?  In the new world order, the stack trace will always be

 0  handle_signal
 1  <signal trampoline>
 2  __syscall_cancel_arch
 3  __syscall_cancel
 4  read
 5  fn
 6  fn
 7  fn
 8  do_test

won't it?  I think teaching the backtrace logic about this would be
better than needing to use a raw syscall() and then mess with the
PowerPC implementation of syscall().  I might feel differently about
this change if __read_nocancel were a public API, but it isn't...

> Checked on i686-linux-gnu, x86_64-linux-gnu, x86_64-linux-gnux32,

> aarch64-linux-gnu, arm-linux-gnueabihf, powerpc64le-linux-gnu,

> powerpc-linux-gnu, sparcv9-linux-gnu, and sparc64-linux-gnu.


When you say checked, do you mean you actually ran the test cases, or
did you just compile them (perhaps with a cross-compiler)?

>       * nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove

>       tst-cancel-wrappers.sh.

>       * nptl/tst-cancel-wrappers.sh: Remove file.


This part is OK.

>       * nptl/tst-cancel4.c (tf_write): Handle cancelled syscall with

>       side-effects.

>       (tf_send): Likewise.


This part is also OK.  I think the test can still fail spuriously due
to races, but this one can't deadlock, at least, so we can live with it.

>       * sysdeps/unix/sysv/linux/powerpc/syscall.S (syscall): Create stack

>       frame.


This ChangeLog entry belongs to patch 1.

zw
Adhemerval Zanella Netto May 7, 2018, 5:13 p.m. UTC | #4
On 06/05/2018 23:49, Zack Weinberg wrote:
> On 26 Feb 2018, Adhemerval Zanella wrote:

>> With upcoming fix for BZ#12683, pthread cancellation does not act for:

>>

>>   1. If syscall is blocked but with some side effects already having

>>      taken place (e.g. a partial read or write).

>>   2. After the syscall has returned.

>>

>> The main change is due the fact programs need to act in syscalls with

>> side-effects (for instance, to avoid leak of allocated resources or

>> handle partial read/write).

>>

>> This patch changes the NPTL testcase that assumes the old behavior and

>> also remove the tst-cancel-wrappers.sh test (which checks for symbols

>> that will not exist anymore).

> 

> It's OK and expected that we have to adjust test cases that were

> expecting the old behavior ...

> 

>> For tst-cancel{2,3} case it remove the pipe close because it might

>> cause the write syscall to return with side effects if the close is

>> executed before the pthread cancel.

> 

> ... however, this change appears to be wrong.  If cancellation is

> broken, these tests will now deadlock rather than failing cleanly.


On current cancellation implementation the thread will finish regardless
and sigcancel_handler will act whether there is side-effects or not
(the pipe close). The issue is cancellation should not happen if syscall
returns but some side effects already took place, in this case the pipe
close.

> 

> If I understand correctly, the problem you're trying to avoid is that

> the 'tf' thread could conceivably receive the closed-pipe event before

> the cancellation signal, even though the 'do_test' thread triggers the

> cancellation signal first.  I don't know of any way to fix this 100%,

> but I think it would be good enough to use pthread_timedjoin_np to

> sleep for a hundred milliseconds or so in the 'do_test' thread, and

> then close the pipe if the 'tf' thread is still alive.


Yes, although for this specific case I am not sure if this could happen
in practice.  I assume if a thread issues a 'signal' followed by a 'close', 
the signal target thread will receive the events in a ordered manner, i.e, 
the signal handler will be activated before the syscall sees any 
side-effects (the close).  It seems to be Linux behaviour, but I am not
sure if a different system might act differently.

And I try to avoid the timing check, such as pthread_timedjoin_np,
because they tend to quite fragile in practice for such cases (due either 
to system load when testing glibc, machine performance, etc.).

I will remove the close removal changes in next iteration.

> 

> (tst-cancel4.c appears to be trying to ensure that cancellations are

> pending with a pthread_barrier_t, but as far as I know there's no

> guarantee that if a thread does

> 

>    pthread_cancel(th);

>    pthread_barrier_wait(ba);

> 

> where 'th' also waits on 'ba', the SIGCANCEL will actually be

> delivered before the barrier unblocks, either.  Feh.)

> 

>> It also changes how to call the read syscall on tst-backtrace{5,6}

>> to use syscall instead of read cancelable syscall to avoid need to

>> handle the cancelable bridge function calls.  It requires a change

>> on powerpc syscall implementation to create a stackframe, since

>> powerpc backtrace rely on such information.

> 

> It doesn't look technically difficult to me to handle an additional

> stack frame or two in the trace.  They're always going to be there,

> aren't they?  In the new world order, the stack trace will always be

> 

>  0  handle_signal

>  1  <signal trampoline>

>  2  __syscall_cancel_arch

>  3  __syscall_cancel

>  4  read

>  5  fn

>  6  fn

>  7  fn

>  8  do_test

> 

> won't it?  I think teaching the backtrace logic about this would be

> better than needing to use a raw syscall() and then mess with the

> PowerPC implementation of syscall().  I might feel differently about

> this change if __read_nocancel were a public API, but it isn't...


With your current suggestion to powerpc syscall bits, there is no need
to actually change the powerpc syscall implementation besides an
additional CFI mechanism.  But I do not mind to change the testcase on
the bz12683 fix itself, the only advantage I see is by using indirect
syscall there is no need to actually change it again.

> 

>> Checked on i686-linux-gnu, x86_64-linux-gnu, x86_64-linux-gnux32,

>> aarch64-linux-gnu, arm-linux-gnueabihf, powerpc64le-linux-gnu,

>> powerpc-linux-gnu, sparcv9-linux-gnu, and sparc64-linux-gnu.

> 

> When you say checked, do you mean you actually ran the test cases, or

> did you just compile them (perhaps with a cross-compiler)?


It is a full make check on native machines.

> 

>>       * nptl/Makefile [$(run-built-tests) = yes] (tests-special): Remove

>>       tst-cancel-wrappers.sh.

>>       * nptl/tst-cancel-wrappers.sh: Remove file.

> 

> This part is OK.

> 

>>       * nptl/tst-cancel4.c (tf_write): Handle cancelled syscall with

>>       side-effects.

>>       (tf_send): Likewise.

> 

> This part is also OK.  I think the test can still fail spuriously due

> to races, but this one can't deadlock, at least, so we can live with it.

> 

>>       * sysdeps/unix/sysv/linux/powerpc/syscall.S (syscall): Create stack

>>       frame.

> 

> This ChangeLog entry belongs to patch 1.


Ack. I will remove it.

> 

> zw

>
Zack Weinberg May 8, 2018, 1:35 p.m. UTC | #5
On Mon, May 7, 2018 at 1:13 PM, Adhemerval Zanella
<adhemerval.zanella@linaro.org> wrote:
> On 06/05/2018 23:49, Zack Weinberg wrote:

>> On 26 Feb 2018, Adhemerval Zanella wrote:

>>> For tst-cancel{2,3} case it remove the pipe close because it might

>>> cause the write syscall to return with side effects if the close is

>>> executed before the pthread cancel.

>>

>> ... however, this change appears to be wrong.  If cancellation is

>> broken, these tests will now deadlock rather than failing cleanly.

>

> On current cancellation implementation the thread will finish regardless

> and sigcancel_handler will act whether there is side-effects or not

> (the pipe close). The issue is cancellation should not happen if syscall

> returns but some side effects already took place, in this case the pipe

> close.


I think maybe I didn't explain clearly enough what I'm worried about
here.  What the test case does _when cancellation works_ is sensible.
But this is a test case, it also needs to behave sensibly when
cancellation _doesn't_ work.  Imagine a new port where, for some
reason, the cancellation mechanism is so broken that read/write aren't
acting as cancellation points at all. Without the close,
tst-cancel{2,3} will block forever in read/write.  We have the
test-driver timeout as a backstop, but we shouldn't rely on it.

> Yes, although for this specific case I am not sure if this could happen

> in practice.  I assume if a thread issues a 'signal' followed by a 'close',

> the signal target thread will receive the events in a ordered manner, i.e,

> the signal handler will be activated before the syscall sees any

> side-effects (the close).  It seems to be Linux behaviour, but I am not

> sure if a different system might act differently.


I don't think POSIX makes any requirements, but yes, in practice the
signal should always arrive first.

> And I try to avoid the timing check, such as pthread_timedjoin_np,

> because they tend to quite fragile in practice for such cases (due either

> to system load when testing glibc, machine performance, etc.).


This is reasonable.

For the new cancellation mechanism in general, we don't have a good
way of arranging for SIGCANCEL to arrive at exactly the critical
points within the syscall sequence, do we?  I am tempted to try to
write a test case that scripts gdb and single-steps through a call to
open() and fires SIGCANCEL at each instruction.

>> won't it?  I think teaching the backtrace logic about this would be

>> better than needing to use a raw syscall() and then mess with the

>> PowerPC implementation of syscall().  I might feel differently about

>> this change if __read_nocancel were a public API, but it isn't...

>

> With your current suggestion to powerpc syscall bits, there is no need

> to actually change the powerpc syscall implementation besides an

> additional CFI mechanism.  But I do not mind to change the testcase on

> the bz12683 fix itself, the only advantage I see is by using indirect

> syscall there is no need to actually change it again.


I don't feel especially strongly about this now we have a way that
doesn't add actual instructions to powerpc syscall().

zw
Adhemerval Zanella Netto May 8, 2018, 5:26 p.m. UTC | #6
On 08/05/2018 10:35, Zack Weinberg wrote:
> On Mon, May 7, 2018 at 1:13 PM, Adhemerval Zanella

> <adhemerval.zanella@linaro.org> wrote:

>> On 06/05/2018 23:49, Zack Weinberg wrote:

>>> On 26 Feb 2018, Adhemerval Zanella wrote:

>>>> For tst-cancel{2,3} case it remove the pipe close because it might

>>>> cause the write syscall to return with side effects if the close is

>>>> executed before the pthread cancel.

>>>

>>> ... however, this change appears to be wrong.  If cancellation is

>>> broken, these tests will now deadlock rather than failing cleanly.

>>

>> On current cancellation implementation the thread will finish regardless

>> and sigcancel_handler will act whether there is side-effects or not

>> (the pipe close). The issue is cancellation should not happen if syscall

>> returns but some side effects already took place, in this case the pipe

>> close.

> 

> I think maybe I didn't explain clearly enough what I'm worried about

> here.  What the test case does _when cancellation works_ is sensible.

> But this is a test case, it also needs to behave sensibly when

> cancellation _doesn't_ work.  Imagine a new port where, for some

> reason, the cancellation mechanism is so broken that read/write aren't

> acting as cancellation points at all. Without the close,

> tst-cancel{2,3} will block forever in read/write.  We have the

> test-driver timeout as a backstop, but we shouldn't rely on it.


Well, adding a timing mechanism (either by alarm, pthread_timedjoin, etc)
is basically what the test-driver backstop is actually doing, with the
advantage it is another process no susceptible to possible memory 
corruptions or other execution failures.  I don't see much gain in
add more hardening in test itself.

> 

>> Yes, although for this specific case I am not sure if this could happen

>> in practice.  I assume if a thread issues a 'signal' followed by a 'close',

>> the signal target thread will receive the events in a ordered manner, i.e,

>> the signal handler will be activated before the syscall sees any

>> side-effects (the close).  It seems to be Linux behaviour, but I am not

>> sure if a different system might act differently.

> 

> I don't think POSIX makes any requirements, but yes, in practice the

> signal should always arrive first.

> 

>> And I try to avoid the timing check, such as pthread_timedjoin_np,

>> because they tend to quite fragile in practice for such cases (due either

>> to system load when testing glibc, machine performance, etc.).

> 

> This is reasonable.

> 

> For the new cancellation mechanism in general, we don't have a good

> way of arranging for SIGCANCEL to arrive at exactly the critical

> points within the syscall sequence, do we?  I am tempted to try to

> write a test case that scripts gdb and single-steps through a call to

> open() and fires SIGCANCEL at each instruction.


I can't really think any explicit way to actually check it, a gdb/ptrace
is the close think I can think off as well.

> 

>>> won't it?  I think teaching the backtrace logic about this would be

>>> better than needing to use a raw syscall() and then mess with the

>>> PowerPC implementation of syscall().  I might feel differently about

>>> this change if __read_nocancel were a public API, but it isn't...

>>

>> With your current suggestion to powerpc syscall bits, there is no need

>> to actually change the powerpc syscall implementation besides an

>> additional CFI mechanism.  But I do not mind to change the testcase on

>> the bz12683 fix itself, the only advantage I see is by using indirect

>> syscall there is no need to actually change it again.

> 

> I don't feel especially strongly about this now we have a way that

> doesn't add actual instructions to powerpc syscall().

> 

> zw

> 


Right, I will my current version on next version.
diff mbox series

Patch

diff --git a/debug/tst-backtrace5.c b/debug/tst-backtrace5.c
index 0e6fb1a..a6d66c8 100644
--- a/debug/tst-backtrace5.c
+++ b/debug/tst-backtrace5.c
@@ -23,6 +23,7 @@ 
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
+#include <sys/syscall.h>
 #include <signal.h>
 #include <unistd.h>
 
@@ -33,7 +34,7 @@ 
 #endif
 
 /* The backtrace should include at least handle_signal, a signal
-   trampoline, read, 3 * fn, and do_test.  */
+   trampoline, syscall, 3 * fn, and do_test.  */
 #define NUM_FUNCTIONS 7
 
 void
@@ -71,16 +72,18 @@  handle_signal (int signum)
     }
   /* Do not check name for signal trampoline.  */
   i = 2;
-  if (!match (symbols[i++], "read"))
+
+  if (match (symbols[i], "__kernel_vsyscall"))
+    i++;
+
+  /* We are using syscall(...) instead of read.  */
+  if (!match (symbols[i++], "syscall"))
     {
-      /* Perhaps symbols[2] is __kernel_vsyscall?  */
-      if (!match (symbols[i++], "read"))
-	{
-	  FAIL ();
-	  return;
-	}
+      FAIL ();
+      return;
     }
-  for (; i < n - 1; i++)
+
+  for (; i < n - 2; i++)
     if (!match (symbols[i], "fn"))
       {
 	FAIL ();
@@ -123,8 +126,11 @@  fn (int c, int flags)
       _exit (0);
     }
 
-  /* In the parent.  */
-  read (pipefd[0], r, 1);
+  /* To avoid need to handle cancellation syscall backtrace (which call
+     the function using both the generic bridge (__syscall_cancel) and
+     the architecture defined one (__syscall_cancel_arch), issue the
+     syscall directly.  */
+  syscall (__NR_read, pipefd[0], r, 1);
 
   return 0;
 }
diff --git a/nptl/Makefile b/nptl/Makefile
index de37fb4..76ecf6c 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -452,8 +452,7 @@  tests-reverse += tst-cancel5 tst-cancel23 tst-vfork1x tst-vfork2x
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-stack3-mem.out $(objpfx)tst-oddstacklimit.out
 ifeq ($(build-shared),yes)
-tests-special += $(objpfx)tst-tls6.out $(objpfx)tst-cleanup0-cmp.out \
-		 $(objpfx)tst-cancel-wrappers.out
+tests-special += $(objpfx)tst-tls6.out $(objpfx)tst-cleanup0-cmp.out
 endif
 endif
 
@@ -682,7 +681,7 @@  $(objpfx)$(multidir)/crtn.o: $(objpfx)crtn.o $(objpfx)$(multidir)/
 endif
 
 generated += libpthread_nonshared.a \
-	     multidir.mk tst-atfork2.mtrace tst-cancel-wrappers.out \
+	     multidir.mk tst-atfork2.mtrace \
 	     tst-tls6.out
 
 generated += $(objpfx)tst-atfork2.mtrace \
@@ -694,18 +693,6 @@  LDFLAGS-pthread.so += -e __nptl_main
 $(objpfx)pt-interp.os: $(common-objpfx)runtime-linker.h
 endif
 
-ifeq ($(run-built-tests),yes)
-ifeq (yes,$(build-shared))
-$(objpfx)tst-cancel-wrappers.out: tst-cancel-wrappers.sh
-	$(SHELL) $< '$(NM)' \
-		    $(common-objpfx)libc_pic.a \
-		    $(common-objpfx)libc.a \
-		    $(objpfx)libpthread_pic.a \
-		    $(objpfx)libpthread.a > $@; \
-	$(evaluate-test)
-endif
-endif
-
 tst-exec4-ARGS = $(host-test-program-cmd)
 
 $(objpfx)tst-execstack: $(libdl)
diff --git a/nptl/tst-cancel-wrappers.sh b/nptl/tst-cancel-wrappers.sh
deleted file mode 100644
index 0c5b614..0000000
--- a/nptl/tst-cancel-wrappers.sh
+++ /dev/null
@@ -1,92 +0,0 @@ 
-#!/bin/sh
-# Test whether all cancelable functions are cancelable.
-# Copyright (C) 2002-2018 Free Software Foundation, Inc.
-# This file is part of the GNU C Library.
-# Contributed by Jakub Jelinek <jakub@redhat.com>, 2002.
-
-# 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/>.
-
-NM="$1"; shift
-while [ $# -gt 0 ]; do
-  ( $NM -P $1; echo 'end[end]:' ) | gawk ' BEGIN {
-C["accept"]=1
-C["close"]=1
-C["connect"]=1
-C["creat"]=1
-C["fcntl"]=1
-C["fdatasync"]=1
-C["fsync"]=1
-C["msgrcv"]=1
-C["msgsnd"]=1
-C["msync"]=1
-C["nanosleep"]=1
-C["open"]=1
-C["open64"]=1
-C["pause"]=1
-C["poll"]=1
-C["pread"]=1
-C["pread64"]=1
-C["pselect"]=1
-C["pwrite"]=1
-C["pwrite64"]=1
-C["read"]=1
-C["readv"]=1
-C["recv"]=1
-C["recvfrom"]=1
-C["recvmsg"]=1
-C["select"]=1
-C["send"]=1
-C["sendmsg"]=1
-C["sendto"]=1
-C["sigpause"]=1
-C["sigsuspend"]=1
-C["sigwait"]=1
-C["sigwaitinfo"]=1
-C["tcdrain"]=1
-C["wait"]=1
-C["waitid"]=1
-C["waitpid"]=1
-C["write"]=1
-C["writev"]=1
-C["__xpg_sigpause"]=1
-}
-/:$/ {
-  if (seen)
-    {
-      if (!seen_enable || !seen_disable)
-	{
-	  printf "in '$1'(%s) %s'\''s cancellation missing\n", object, seen
-	  ret = 1
-	}
-    }
-  seen=""
-  seen_enable=""
-  seen_disable=""
-  object=gensub(/^.*\[(.*)\]:$/, "\\1", 1, $0)
-  next
-}
-{
-  if (C[$1] && $2 ~ /^[TW]$/)
-    seen=$1
-  else if ($1 ~ /^([.]|)__(libc|pthread)_enable_asynccancel$/ && $2 == "U")
-    seen_enable=1
-  else if ($1 ~ /^([.]|)__(libc|pthread)_disable_asynccancel$/ && $2 == "U")
-    seen_disable=1
-}
-END {
-  exit ret
-}' || exit
-  shift
-done
diff --git a/nptl/tst-cancel2.c b/nptl/tst-cancel2.c
index e2926bd..45e9a61 100644
--- a/nptl/tst-cancel2.c
+++ b/nptl/tst-cancel2.c
@@ -73,9 +73,6 @@  do_test (void)
       return 1;
     }
 
-  /* This will cause the write in the child to return.  */
-  close (fd[0]);
-
   if (pthread_join (th, &r) != 0)
     {
       puts ("join failed");
diff --git a/nptl/tst-cancel3.c b/nptl/tst-cancel3.c
index a82c8f2..67f6543 100644
--- a/nptl/tst-cancel3.c
+++ b/nptl/tst-cancel3.c
@@ -75,9 +75,6 @@  do_test (void)
       return 1;
     }
 
-  /* This will cause the read in the child to return.  */
-  close (fd[0]);
-
   if (pthread_join (th, &r) != 0)
     {
       puts ("join failed");
diff --git a/nptl/tst-cancel4.c b/nptl/tst-cancel4.c
index 0532538..2614f9a 100644
--- a/nptl/tst-cancel4.c
+++ b/nptl/tst-cancel4.c
@@ -166,6 +166,10 @@  tf_write  (void *arg)
   char buf[WRITE_BUFFER_SIZE];
   memset (buf, '\0', sizeof (buf));
   s = write (fd, buf, sizeof (buf));
+  /* The write can return a value higher than 0 (meaning partial write)
+     due to the SIGCANCEL, but the thread may still be pending
+     cancellation.  */
+  pthread_testcancel ();
 
   pthread_cleanup_pop (0);
 
@@ -743,6 +747,10 @@  tf_send (void *arg)
   char mem[WRITE_BUFFER_SIZE];
 
   send (tempfd2, mem, arg == NULL ? sizeof (mem) : 1, 0);
+  /* Thez send can return a value higher than 0 (meaning partial send)
+     due to the SIGCANCEL, but the thread may still be pending
+     cancellation.  */
+  pthread_testcancel ();
 
   pthread_cleanup_pop (0);