Subject: bin/236: ash(1) parser is broken w.r.t. backgnd commands
To: None <gnats-admin>
From: Mark Weaver <mhw@cs.brown.edu>
List: netbsd-bugs
Date: 04/27/1994 20:20:02
>Number:         236
>Category:       bin
>Synopsis:       ash(1) parser is broken w.r.t. backgnd commands
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    gnats-admin (Utility Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   mhw
>Arrival-Date:   Wed Apr 27 20:20:02 1994
>Originator:     Mark Weaver
>Organization:
--------------------------------------------------------------------
Email: Mark_Weaver@brown.edu           | Brown University
PGP Key: finger mhw@cs.brown.edu       | Dept of Computer Science
>Release:        current-940427
>Environment:

System: NetBSD cis-ts3-slip4.cis.brown.edu 0.9a EXCELSIOR#2 i386

>Description:
	Typing "sleep 1; sleep 10 &" executes the equivalent (roughly)
	of "{ sleep 1; sleep 10; } &".  This is because the parser is
	broken w.r.t. lists.  When a "&" is encountered in a list, all
	the prior commands are grouped together and backgrounded, instead
	of only the previous and-or construct being backgrounded.

	This bug was reported earlier as well, claiming that the problem
	occured within if statements only.  Actually, it happens in any
	list.  However, in the outer body of the shell script, a list is
	terminated at each newline (as a memory optimization), so the
	problem went unnoticed.

>How-To-Repeat:

$ sleep 1; sleep 10 &
$ jobs
[1] 321                       sleep 1; sleep 10
$

(first command above returns immediately)

mhw ~ % cat t
#!/bin/sh

(
sleep 2
echo 1
echo 2 &
echo 3
wait
)
mhw ~ % sh t
3
1
2

(with a 2 second pause after the 3 is printed)

>Fix:
*** parser.c.mhw1	Fri Dec 17 00:48:39 1993
--- parser.c	Wed Apr 27 22:50:51 1994
***************
*** 144,174 ****
  STATIC union node *
  list(nlflag) {
  	union node *n1, *n2, *n3;
  
  	checkkwd = 2;
  	if (nlflag == 0 && tokendlist[peektoken()])
  		return NULL;
! 	n1 = andor();
  	for (;;) {
! 		switch (readtoken()) {
! 		case TBACKGND:
! 			if (n1->type == NCMD || n1->type == NPIPE) {
! 				n1->ncmd.backgnd = 1;
! 			} else if (n1->type == NREDIR) {
! 				n1->type = NBACKGND;
  			} else {
  				n3 = (union node *)stalloc(sizeof (struct nredir));
  				n3->type = NBACKGND;
! 				n3->nredir.n = n1;
  				n3->nredir.redirect = NULL;
! 				n1 = n3;
  			}
! 			goto tsemi;
! 		case TNL:
! 			tokpushback++;
  			/* fall through */
! tsemi:	    case TSEMI:
! 			if (readtoken() == TNL) {
  				parseheredoc();
  				if (nlflag)
  					return n1;
--- 144,188 ----
  STATIC union node *
  list(nlflag) {
  	union node *n1, *n2, *n3;
+ 	int tok;
  
  	checkkwd = 2;
  	if (nlflag == 0 && tokendlist[peektoken()])
  		return NULL;
! 	n1 = NULL;
  	for (;;) {
! 		n2 = andor();
! 		tok = readtoken();
! 		if (tok == TBACKGND) {
! 			if (n2->type == NCMD || n2->type == NPIPE) {
! 				n2->ncmd.backgnd = 1;
! 			} else if (n2->type == NREDIR) {
! 				n2->type = NBACKGND;
  			} else {
  				n3 = (union node *)stalloc(sizeof (struct nredir));
  				n3->type = NBACKGND;
! 				n3->nredir.n = n2;
  				n3->nredir.redirect = NULL;
! 				n2 = n3;
  			}
! 		}
! 		if (n1 == NULL) {
! 			n1 = n2;
! 		}
! 		else {
! 			n3 = (union node *)stalloc(sizeof (struct nbinary));
! 			n3->type = NSEMI;
! 			n3->nbinary.ch1 = n1;
! 			n3->nbinary.ch2 = n2;
! 			n1 = n3;
! 		}
! 		switch (tok) {
! 		case TBACKGND:
! 		case TSEMI:
! 			tok = readtoken();
  			/* fall through */
! 		case TNL:
! 			if (tok == TNL) {
  				parseheredoc();
  				if (nlflag)
  					return n1;
***************
*** 178,189 ****
  			checkkwd = 2;
  			if (tokendlist[peektoken()])
  				return n1;
- 			n2 = andor();
- 			n3 = (union node *)stalloc(sizeof (struct nbinary));
- 			n3->type = NSEMI;
- 			n3->nbinary.ch1 = n1;
- 			n3->nbinary.ch2 = n2;
- 			n1 = n3;
  			break;
  		case TEOF:
  			if (heredoclist)
--- 192,197 ----
>Audit-Trail:
>Unformatted:


------------------------------------------------------------------------------