1#
2# CDDL HEADER START
3#
4# The contents of this file are subject to the terms of the
5# Common Development and Distribution License (the "License").
6# You may not use this file except in compliance with the License.
7#
8# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9# or http://www.opensolaris.org/os/licensing.
10# See the License for the specific language governing permissions
11# and limitations under the License.
12#
13# When distributing Covered Code, include this CDDL HEADER in each
14# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15# If applicable, add the following below this CDDL HEADER, with the
16# fields enclosed by brackets "[]" replaced with your own identifying
17# information: Portions Copyright [yyyy] [name of copyright owner]
18#
19# CDDL HEADER END
20#
21
22#
23# Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24#
25
26#
27# This test checks whether the issue described in CR #6687139
28# ("command substitution, exec, and stdout redirection cause
29# allocation loop") has been fixed:
30# -- snip --
31# The following one-liner (including back ticks) causes ksh93 to spin
32# out of control consuming all memory at a *very* rapid pace:
33#
34#    `exec program > file`
35#
36#  If "file" is a real file (as opposed to /dev/null), the file will
37#  also grow without bound.  "program" need not exist, i.e.
38#
39#    `exec > file`
40#
41#  has the same result.  Using $() instead of `` also has the same
42#  effect.
43#
44#  This works fine under all other bourne-compatible shells.
45# -- snip --
46#
47
48# test setup
49function err_exit
50{
51	print -u2 -n "\t"
52	print -u2 -r ${Command}[$1]: "${@:2}"
53	(( Errors < 127 && Errors++ ))
54}
55alias err_exit='err_exit $LINENO'
56
57set -o nounset
58Command=${0##*/}
59integer Errors=0
60
61function isvalidpid
62{
63	kill -0 ${1} 2>/dev/null && return 0
64	return 1
65}
66
67integer childpid
68typeset testdir
69integer childretval
70
71testdir="/tmp/sun_solaris_cr_6687139_pid$$_${PPID}"
72mkdir -p "${testdir}" || err_exit "Cannot create test dirctory"
73cd "${testdir}" || { err_exit "Cannot cd to test dirctory" ; exit $Errors ; }
74
75##############################################################################
76##
77## test variant 1a: Use command substitution $( ... )
78##
79
80# Run testcase with "nice" to make sure a "runaway" process can
81# still be caught&&terminated by the current shell
82nice -n 10 ${SHELL} -c 'touch z ; $(exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null &
83childpid=$!
84
85sleep 5
86
87if isvalidpid ${childpid} ; then
88	# First _stop_, then log error since the child may eat up memory
89	# VERY VERY quickly
90	kill -STOP ${childpid}
91
92	err_exit "Child still active after 5 seconds (hang ?)"
93
94	# Get sample stack trace
95	pstack ${childpid}
96	kill -KILL ${childpid}
97fi
98
99# collect child's return status
100wait ${childpid}
101childretval=$?
102
103(( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}."
104
105[[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; }
106
107
108##############################################################################
109##
110## test variant 1b: Same as test 1a but forces the shell to |fork()| for the
111## subshell
112##
113
114# Run testcase with "nice" to make sure a "runaway" process can
115# still be caught&&terminated by the current shell
116nice -n 10 ${SHELL} -c 'touch z ; $(ulimit -c 0 ; exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null &
117childpid=$!
118
119sleep 5
120
121if isvalidpid ${childpid} ; then
122	# First _stop_, then log error since the child may eat up memory
123	# VERY VERY quickly
124	kill -STOP ${childpid}
125
126	err_exit "Child still active after 5 seconds (hang ?)"
127
128	# Get sample stack trace
129	pstack ${childpid}
130	kill -KILL ${childpid}
131fi
132
133# collect child's return status
134wait ${childpid}
135childretval=$?
136
137(( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}."
138
139[[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; }
140
141
142##############################################################################
143##
144## test variant 2a: Use plain subshell ( ... )
145##
146
147# Run testcase with "nice" to make sure a "runaway" process can
148# still be caught&&terminated by the current shell
149nice -n 10 ${SHELL} -c 'touch z ; (exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null &
150childpid=$!
151
152sleep 5
153
154if isvalidpid ${childpid} ; then
155	# First _stop_, then log error since the child may eat up memory
156	# VERY VERY quickly
157	kill -STOP ${childpid}
158
159	err_exit "Child still active after 5 seconds (hang ?)"
160
161	# Get sample stack trace
162	pstack ${childpid}
163	kill -KILL ${childpid}
164fi
165
166# collect child's return status
167wait ${childpid}
168childretval=$?
169
170(( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}."
171
172[[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; }
173
174
175##############################################################################
176##
177## test variant 2b: Same as test 2a but forces the shell to |fork()| for the
178## subshell
179##
180
181# Run testcase with "nice" to make sure a "runaway" process can
182# still be caught&&terminated by the current shell
183nice -n 10 ${SHELL} -c 'touch z ; (ulimit -c 0 ; exec nosuchprogram_for_cr_6687139 > z) ; rm z' 2>/dev/null &
184childpid=$!
185
186sleep 5
187
188if isvalidpid ${childpid} ; then
189	# First _stop_, then log error since the child may eat up memory
190	# VERY VERY quickly
191	kill -STOP ${childpid}
192
193	err_exit "Child still active after 5 seconds (hang ?)"
194
195	# Get sample stack trace
196	pstack ${childpid}
197	kill -KILL ${childpid}
198fi
199
200# collect child's return status
201wait ${childpid}
202childretval=$?
203
204(( childretval == 0 )) || err_exit "Child returned non-zero exit code ${childretval}."
205
206[[ ! -f "z" ]] || { rm "z" ; err_exit "Child did not remove test file" ; }
207
208# tests done, remove temporary test subdir
209cd /tmp
210rmdir "${testdir}" || err_exit "Could not remove temporary test directory ${testdir}"
211
212
213# tests done
214exit $((Errors))
215