This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] cygwin+bash: bash reorders script output bug identified/fixed


Hi,

I've figured out why bash reorders output from my shell script. I've
attached a new, simpler script to reproduce the bug
Just run

      ./w.sh

If it fails, then lines in output.txt are reordered
(i.e. script output something).
Please retry a few times, it's not 100% reproducable.

Summary:
* It's a bash bug, not a cygwin bug.
* defining RECYCLES_PIDS in execute_cmd.c solves the problem.
* RECYCLES_PID is intended for LynxOs, which recycles pids
      quickly according to a comment in execute_cmd.c
* All OS are potentially affected, bash basically assumes
      that 2 pid values are never identical.

It seems that there are 2 possible solutions:
A) enable RECYCLES_PID in bash.
      * I'd propose that, minimal patch attached.
B) work around the bash bug in cygwin.
      fork.cc already contains a special function that prevents 2
          consecutive fork() calls from reusing the same pid:
          slow_pid_reuse().

But it doesn't work in this context:

When bash executes a command, it sometimes creates a subprocess.
make_child saves the new pid in a global variable (last_made_pid).
execute_command_internal() calls execute_simple_command() and checks
if last_made_pid has changed during the call. If last_made_pid has not
changed (command was a builtin, handled without fork()), then wait_for()
is not called by execute_command_internal(), to prevent bash from
hanging.

I.e. if the same pid is used for 2 consecutive command subprocesses,
bash fails, because it thinks the command was a builtin and doesn't wait
until the external process exits.

My probem is caused by process_substitute: The function handles command
substitution, and that function saves & restores last_made_pid.

Thus the same pid value must not be used for 2 consecutive _command_
subprocesses, which is different from 2 consecutive fork() calls.

I don't see how fork.cc could work around that bash bug. I'd propose the
attached patch, that enables RECYCLES_PIDS for cygwin.

Note: I've manually edited both configure.in and configure, because I
don't have autoconf installed. Please test before applying the patch.
Obviously I'd prefer if RECYCLES_PIDS is unconditionally enabled in
all OS.

--
      Manfred
<<<<<< bugbash output:

Configuration Information [Automatically generated, do not change]:
Machine: i686
OS: cygwin
Compiler: i686-pc-cygwin-gcc
Compilation CFLAGS:  -DPROGRAM='bash.exe' -DCONF_HOSTTYPE='i686'
-DCONF_OSTYPE='cygwin' -DCONF_MACHTYPE='i686-pc-cygwin'
-DCONF_VENDOR='pc' -DSHELL -DHAVE_CONFIG_H  -I.  -I../bash-2.05b
-I../bash-2.05b/include -I../bash-2.05b/lib -g -O2
uname output: CYGWIN_NT-5.0 AB 1.3.12(0.54/3/2) 2002-07-03 16:42 i686
unknown
Machine Type: i686-pc-cygwin

Bash Version: 2.05b
Patch Level: 0
Release Status: release

<<<<<<<
cygwin version: 1.3.12-1
<<<<<<<


#!/bin/bash
# the comments explain what's needed to trigger the bug
#
fnc() {
# e.g. process id 1000
	n=1
	while [ $n -lt 50 ];do 
		n=$[$n+1]
		rm -f m-$n.txt
		# subprocess created for rm.
		# process id 1001, saved in last_made_pid.
		echo "YYY  $n" > lfile.txt
		echo "W    $n"
		for i in 0 1 2 3 4 5 6 7 8 9 10;do 
			mu=`echo $n $i | gawk '{printf("%f\n",$1+$2);}'`
			# several subprocesses created by
			# process_substitute.
			# consecutive pid values are never identical,
			# bug process_substitute always restores 
			# last_made_pid to 1001.
			echo "$mu" >> m-$n.txt
		done
		echo "XX   $n"
		cat lfile.txt
		# subprocess created, pid 1001.
		# result: execute_command_internal thinks that it's
		# a builtin and doesn't wait until cat exits.
		echo "ZZZZ $n"
		# echo prints "ZZZZ $n"
		# now cat runs, and outputs YYY --> YYY after ZZZZ
		rm -f m-$n.txt
	done
}

rm -f m-*.txt
fnc > output.txt
rm lfile.txt
#
# now check if the output file is correct
#
gawk ' {i++} /W/{if (i%4 != 1) printf("%s\n",$0);} /X/{if (i%4 != 2) printf("%s\n",$0);} /Y/{if (i%4 != 3) printf("%s\n",$0);} /Z/{if (i%4 != 0) printf("%s\n",$0);}' < output.txt



Attachment: patch-bash
Description: application/java-applet

--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]