bin/165164: [PATCH][bin] xargs incorrect pointer passed to waitchildren function

Matthew Story matthewstory at gmail.com
Wed Feb 15 05:20:06 UTC 2012


>Number:         165164
>Category:       bin
>Synopsis:       [PATCH][bin] xargs incorrect pointer passed to waitchildren function
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 15 05:20:05 UTC 2012
>Closed-Date:
>Last-Modified:
>Originator:     Matthew Story
>Release:        9.0
>Organization:
>Environment:
FreeBSD matt9fromouterspace 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan  3 07:15:25 UTC 2012     root at obrian.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
*argv is manipulated in main to account for Jflag replacement strings (moving argv into av, and leaving *argv a pointer to the first argument following a Jflag replacement string argument || NULL if Jflag not set):

    if (*argv == NULL)
        cnt = strlen(*bxp++ = echo);
    else {
        do {
            if (Jflag && strcmp(*argv, replstr) == 0) {
                char **avj;
                jfound = 1;
                argv++;
                for (avj = argv; *avj; avj++)
                    cnt += strlen(*avj) + 1;
                break;
            }   
            cnt += strlen(*bxp++ = *argv) + 1;
        } while (*++argv != NULL);
    } 

*argv is then passed to parse_input, which passes *av to prerun, which in turn passes *av (locally argv) to waitchildren for diagnostic purposes, while the calls from parse_input itself pass *argv to waitchildren for diagnostic purposes.  This incongruity means that calls directly from parse_input (only in cases after EOF has been seen) take either NULL or the first argument after a Jflag string argument as utility name for diagnostic purposes, leading to output like:

xargs: (null): No such file or directory
>How-To-Repeat:
Found this issue after applying patch from PR 165155, which provides POSIX-compliant diagnostic information on exit 255 and children terminated by signals.  Condition exists, but is masked for the most part by a race on line 568 (WNOHANG wait immediately following vfork, execvp), if you comment out that line:

/* waitchildren(*argv, 0); */

You will reliably see the following behavior:

$ # this will work unless you have a this_does_not_exist in your PATH
$ echo "hi" | ./xargs -P10 -n1 this_does_not_exist
xargs: (null): No such file or directory
$ # this should read: xargs: hi: No such file or directory
$ echo "this_does_not_exist" | ./xargs -J % % sh
xargs: sh: No such file or directory

You can alternalively apply the patch from PR 165155, and the following will always yield the (null) error condition:

$ jot - 1 10 | ./xargs -P10 -n12 sh -c 'sleep 1; exit 255'
xargs: (null): exited with status 255, aborting

This issue should be resolved prior to patching PR 165155, I will make a note in that ticket as well.  Following applying the patch:

$ echo "hi" | ./xargs blah
xargs: blah: No such file or directory
$ echo "hi" | ./xargs -J % % sh   
xargs: hi: No such file or directory

And for the PR 165155 case:

$ jot - 1 10 | ./xargs -P10 -n12 sh -c 'sleep 1; exit 255'
xargs: sh: exited with status 255, aborting
>Fix:
Apply patch.  This program looks like it needs a larger re-factor, but the solution provided in the patch is to send *av to waitchildren instead of *argv (which is a pointer to the first argument following a Jflag replacement string || null) to make the behavior congruent with the argument list passed to prerun (locally argv).

Patch attached with submission follows:

--- a/usr.bin/xargs/xargs.c	2012-02-14 22:54:29.000000000 -0500
+++ b/usr.bin/xargs/xargs.c	2012-02-14 16:46:37.000000000 -0500
@@ -281,7 +281,7 @@
 	case EOF:
 		/* No arguments since last exec. */
 		if (p == bbp) {
-			waitchildren(*argv, 1);
+			waitchildren(*av, 1);
 			exit(rval);
 		}
 		goto arg1;
@@ -368,7 +368,7 @@
 			}
 			prerun(argc, av);
 			if (ch == EOF || foundeof) {
-				waitchildren(*argv, 1);
+				waitchildren(*av, 1);
 				exit(rval);
 			}
 			p = bbp;


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list