[PATCH] USE_SEIZE: fix detaching from stopped processes

Dmitry V. Levin ldv at altlinux.org
Tue Jun 18 20:36:20 UTC 2013


On Tue, Jun 18, 2013 at 06:18:14PM +0200, Denys Vlasenko wrote:
> * strace.c (detach) [USE_SEIZE]: If PTRACE_SEIZE API is in use, stop
> the tracee using PTRACE_INTERRUPT instead of sending it a SIGSTOP.
> In a subsequent waitpid loop, wait for either SIGSTOP or SIGTRAP.
> 
> Signed-off-by: Denys Vlasenko <dvlasenk at redhat.com>
> ---
>  strace.c | 33 ++++++++++++++++++++++-----------
>  1 file changed, 22 insertions(+), 11 deletions(-)
> 
> diff --git a/strace.c b/strace.c
> index 87aad48..af8156d 100644
> --- a/strace.c
> +++ b/strace.c
> @@ -733,7 +733,7 @@ static int
>  detach(struct tcb *tcp)
>  {
>  	int error;
> -	int status, sigstop_expected;
> +	int status, stop_expected;
>  
>  	if (tcp->flags & TCB_BPTSET)
>  		clearbpt(tcp);
> @@ -749,15 +749,15 @@ detach(struct tcb *tcp)
>  #endif
>  
>  	error = 0;
> -	sigstop_expected = 0;
> +	stop_expected = 0;
>  	if (tcp->flags & TCB_ATTACHED) {
>  		/*
>  		 * We attached but possibly didn't see the expected SIGSTOP.
>  		 * We must catch exactly one as otherwise the detached process
>  		 * would be left stopped (process state T).
>  		 */
> -		sigstop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
> -		error = ptrace(PTRACE_DETACH, tcp->pid, (char *) 1, 0);
> +		stop_expected = (tcp->flags & TCB_IGNORE_ONE_SIGSTOP);
> +		error = ptrace(PTRACE_DETACH, tcp->pid, 0, 0);
>  		if (error == 0) {
>  			/* On a clear day, you can see forever. */
>  		}
> @@ -769,15 +769,24 @@ detach(struct tcb *tcp)
>  			if (errno != ESRCH)
>  				perror_msg("detach: checking sanity");
>  		}
> -		else if (!sigstop_expected && my_tkill(tcp->pid, SIGSTOP) < 0) {
> -			if (errno != ESRCH)
> -				perror_msg("detach: stopping child");
> +		else if (!stop_expected) {
> +			/* Process is running, need to stop it first */
> +			if (use_seize)
> +				error = ptrace(PTRACE_INTERRUPT, tcp->pid, 0, 0);
> +			else
> +				error = my_tkill(tcp->pid, SIGSTOP);
> +			if (!error)
> +				stop_expected = 1;
> +			else if (errno != ESRCH) {
> +				if (use_seize)
> +					perror_msg("detach: ptrace(PTRACE_INTERRUPT, ...)");
> +				else
> +					perror_msg("detach: stopping child");
> +			}
>  		}
> -		else
> -			sigstop_expected = 1;
>  	}
>  
> -	if (sigstop_expected) {
> +	if (stop_expected) {
>  		for (;;) {
>  #ifdef __WALL
>  			if (waitpid(tcp->pid, &status, __WALL) < 0) {
> @@ -810,7 +819,9 @@ detach(struct tcb *tcp)
>  				/* Au revoir, mon ami. */
>  				break;
>  			}
> -			if (WSTOPSIG(status) == SIGSTOP) {
> +			if (WSTOPSIG(status) == SIGSTOP
> +			 || WSTOPSIG(status) == SIGTRAP /* may be generated by PTRACE_INTERRUPT stop */
> +			) {

In case of PTRACE_INTERRUPT this WSTOPSIG(status) is not plain SIGTRAP
but (SIGTRAP | 0x80), which also may happen in other !use_seize cases.
That is, the right check seems to be
	WSTOPSIG(status) == SIGSTOP ||
	(use_seize && WSTOPSIG(status) == (SIGTRAP | 0x80))
It also passes both tests/detach-sleeping and tests/detach-stopped.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20130619/f1379273/attachment.bin>


More information about the Strace-devel mailing list