1 ## compare_shells: dash bash mksh zsh
2 ## oils_failures_allowed: 1
3 ## oils_cpp_failures_allowed: 2
4 # case #24 with ulimit -f 1 is different under C++ for some reason - could be due to the python2
5 # intepreter and SIGXFSZ
6
7 #### exec builtin
8 exec echo hi
9 ## stdout: hi
10
11 #### exec builtin with redirects
12 exec 1>&2
13 echo 'to stderr'
14 ## stdout-json: ""
15 ## stderr: to stderr
16
17 #### exec builtin with here doc
18 # This has in a separate file because both code and data can be read from
19 # stdin.
20 $SH $REPO_ROOT/spec/bin/builtins-exec-here-doc-helper.sh
21 ## STDOUT:
22 x=one
23 y=two
24 DONE
25 ## END
26
27 #### exec builtin accepts --
28 exec -- echo hi
29 ## STDOUT:
30 hi
31 ## END
32 ## BUG dash status: 127
33 ## BUG dash stdout-json: ""
34
35 #### exec -- 2>&1
36 exec -- 3>&1
37 echo stdout 1>&3
38 ## STDOUT:
39 stdout
40 ## END
41 ## BUG dash status: 127
42 ## BUG dash stdout-json: ""
43 ## BUG mksh status: -11
44 ## BUG mksh stdout-json: ""
45
46 #### Exit out of function
47 f() { exit 3; }
48 f
49 exit 4
50 ## status: 3
51
52 #### Exit builtin with invalid arg
53 exit invalid
54 # Rationale: runtime errors are 1
55 ## status: 1
56 ## OK dash/bash status: 2
57 ## BUG zsh status: 0
58
59 #### Exit builtin with too many args
60 # This is a parse error in OSH.
61 exit 7 8 9
62 echo status=$?
63 ## status: 2
64 ## stdout-json: ""
65 ## BUG bash/zsh status: 0
66 ## BUG bash/zsh stdout: status=1
67 ## BUG dash status: 7
68 ## BUG dash stdout-json: ""
69 ## OK mksh status: 1
70 ## OK mksh stdout-json: ""
71
72 #### time with brace group argument
73
74 err=time-$(basename $SH).txt
75 {
76 time {
77 sleep 0.01
78 sleep 0.02
79 }
80 } 2> $err
81
82 grep --only-matching user $err
83 echo result=$?
84
85 # Regression: check fractional seconds
86 gawk '
87 BEGIN { ok = 0 }
88 match( $0, /\.([0-9]+)/, m) {
89 if (m[1] > 0) { # check fractional seconds
90 ok = 1
91 }
92 }
93 END { if (ok) { print "non-zero" } }
94 ' $err
95
96 ## status: 0
97 ## STDOUT:
98 user
99 result=0
100 non-zero
101 ## END
102
103 # time doesn't accept a block?
104 ## BUG zsh STDOUT:
105 result=1
106 ## END
107
108 # dash doesn't have time keyword
109 ## N-I dash status: 2
110 ## N-I dash stdout-json: ""
111
112
113
114 #### ulimit with no flags is like -f
115
116 ulimit > no-flags.txt
117 echo status=$?
118
119 ulimit -f > f.txt
120 echo status=$?
121
122 diff -u no-flags.txt f.txt
123 echo diff=$?
124
125 # Print everything
126 # ulimit -a
127
128 ## STDOUT:
129 status=0
130 status=0
131 diff=0
132 ## END
133
134
135 #### ulimit too many args
136
137 ulimit 1 2
138 if test $? -ne 0; then
139 echo pass
140 else
141 echo fail
142 fi
143
144 #ulimit -f
145
146 ## STDOUT:
147 pass
148 ## END
149
150 ## BUG bash/zsh STDOUT:
151 fail
152 ## END
153
154
155 #### ulimit negative flag
156
157 ulimit -f
158
159 # interpreted as a flag
160 ulimit -f -42
161 if test $? -ne 0; then
162 echo pass
163 else
164 echo fail
165 fi
166
167 ## STDOUT:
168 unlimited
169 pass
170 ## END
171
172 #### ulimit negative arg
173
174 ulimit -f
175
176 # an arg
177 ulimit -f -- -42
178 if test $? -ne 0; then
179 echo pass
180 else
181 echo fail
182 fi
183
184 ## STDOUT:
185 unlimited
186 pass
187 ## END
188
189 ## BUG mksh STDOUT:
190 unlimited
191 fail
192 ## END
193
194
195 #### ulimit -a doesn't take arg
196 case $SH in bash) exit ;; esac
197
198 ulimit -a 42
199 if test $? -ne 0; then
200 echo 'failure that was expected'
201 fi
202
203 ## STDOUT:
204 failure that was expected
205 ## END
206 ## BUG bash STDOUT:
207 ## END
208
209
210 #### ulimit doesn't accept multiple flags - reduce confusion between shells
211
212 # - bash, zsh, busybox ash accept multiple "commands", which requires custom
213 # flag parsing, like
214
215 # ulimit -f 999 -n
216 # ulimit -f 999 -n 888
217 #
218 # - dash and mksh accept a single ARG
219 #
220 # we want to make it clear we're like the latter
221
222 # can't print all and -f
223 ulimit -f -a >/dev/null
224 echo status=$?
225
226 ulimit -f -n >/dev/null
227 echo status=$?
228
229 ulimit -f -n 999 >/dev/null
230 echo status=$?
231
232 ## STDOUT:
233 status=2
234 status=2
235 status=2
236 ## END
237
238 ## BUG dash/bash/mksh STDOUT:
239 status=0
240 status=0
241 status=0
242 ## END
243
244 # zsh is better - it checks that -a and -f are exclusive
245
246 ## BUG zsh STDOUT:
247 status=1
248 status=0
249 status=0
250 ## END
251
252
253 #### YSH readability: ulimit --all the same as ulimit -a
254
255 case $SH in bash|dash|mksh|zsh) exit ;; esac
256
257 ulimit -a > short.txt
258 ulimit --all > long.txt
259
260 wc -l short.txt long.txt
261
262 diff -u short.txt long.txt
263 echo status=$?
264
265 ## STDOUT:
266 8 short.txt
267 8 long.txt
268 16 total
269 status=0
270 ## END
271
272 ## N-I bash/dash/mksh/zsh STDOUT:
273 ## END
274
275 #### ulimit accepts 'unlimited'
276
277 for arg in zz unlimited; do
278 echo " arg $arg"
279 ulimit -f
280 echo status=$?
281 ulimit -f $arg
282 if test $? -ne 0; then
283 echo 'FAILED'
284 fi
285 echo
286 done
287 ## STDOUT:
288 arg zz
289 unlimited
290 status=0
291 FAILED
292
293 arg unlimited
294 unlimited
295 status=0
296
297 ## END
298
299
300 #### ulimit of 2**32, 2**31 (int overflow)
301
302 echo -n 'one '; ulimit -f
303
304
305 ulimit -f $(( 1 << 32 ))
306
307 echo -n 'two '; ulimit -f
308
309
310 # mksh fails because it overflows signed int, turning into negative number
311 ulimit -f $(( 1 << 31 ))
312
313 echo -n 'three '; ulimit -f
314
315 ## STDOUT:
316 one unlimited
317 two 4294967296
318 three 2147483648
319 ## END
320 ## BUG mksh STDOUT:
321 one unlimited
322 two 1
323 three 1
324 ## END
325
326
327 #### ulimit that is 64 bits
328
329 # no 64-bit integers
330 case $SH in mksh) exit ;; esac
331
332 echo -n 'before '; ulimit -f
333
334 # 1 << 63 overflows signed int
335
336 # 512 is 1 << 9, so make it 62-9 = 53 bits
337
338 lim=$(( 1 << 53 ))
339 #echo $lim
340
341 # bash says this is out of range
342 ulimit -f $lim
343
344 echo -n 'after '; ulimit -f
345
346 ## STDOUT:
347 before unlimited
348 after 9007199254740992
349 ## END
350
351 ## BUG mksh STDOUT:
352 ## END
353
354
355 #### arg that would overflow 64 bits is detected
356
357 # no 64-bit integers
358 case $SH in mksh) exit ;; esac
359
360 echo -n 'before '; ulimit -f
361
362 # 1 << 63 overflows signed int
363
364 lim=$(( (1 << 62) + 1 ))
365 #echo lim=$lim
366
367 # bash detects that this is out of range
368 # so does osh-cpp, but not osh-cpython
369
370 ulimit -f $lim
371 echo -n 'after '; ulimit -f
372
373 ## STDOUT:
374 before unlimited
375 after unlimited
376 ## END
377
378 ## BUG dash/zsh STDOUT:
379 before unlimited
380 after 1
381 ## END
382
383 ## BUG mksh STDOUT:
384 ## END
385
386
387 #### ulimit -f 1 prevents files larger 512 bytes
388 trap - XFSZ # don't handle this
389
390 rm -f err.txt
391 touch err.txt
392
393 bytes() {
394 local n=$1
395 local st=0
396 for i in $(seq $n); do
397 echo -n x
398 st=$?
399 if test $st -ne 0; then
400 echo "ERROR: echo failed with status $st" >> err.txt
401 fi
402 done
403 }
404
405 ulimit -f 1
406
407 bytes 512 > ok.txt
408 echo 512 status=$?
409
410 bytes 513 > too-big.txt
411 echo 513 status=$?
412 echo
413
414 wc --bytes ok.txt too-big.txt
415 echo
416
417 cat err.txt
418
419 ## status: -25
420 ## STDOUT:
421 512 status=0
422 ## END
423
424 ## OK disabledosh status: 0
425 ## OK disabledosh STDOUT:
426 512 status=0
427 513 status=0
428
429 512 ok.txt
430 512 too-big.txt
431 1024 total
432
433 ERROR: echo failed with status 1
434 ## END
435
436 ## BUG bash status: 0
437 ## BUG bash STDOUT:
438 512 status=0
439 513 status=0
440
441 512 ok.txt
442 513 too-big.txt
443 1025 total
444
445 ## END
446
447 #### write big file with ulimit
448
449 # I think this will test write() errors, rather than the final flush() error
450 # (which is currently skipped by C++
451
452 { echo 'ulimit -f 1'
453 # More than 8 KiB may cause a flush()
454 python2 -c 'print("echo " + "X"*9000 + " >out.txt")'
455 echo 'echo inner=$?'
456 } > big.sh
457
458 $SH big.sh
459 echo outer=$?
460
461 ## STDOUT:
462 outer=153
463 ## END
464
465 # not sure why this is different
466 ## OK osh STDOUT:
467 inner=1
468 outer=0
469 ## END
470
471
472 #### ulimit -S for soft limit (default), -H for hard limit
473 case $SH in dash|zsh) exit ;; esac
474
475 # Note: ulimit -n -S 1111 is OK in osh/dash/mksh, but not bash/zsh
476 # Mus be ulimit -S -n 1111
477
478 show_state() {
479 local msg=$1
480 echo "$msg"
481 echo -n ' '; ulimit -S -t
482 echo -n ' '; ulimit -H -t
483 echo
484 }
485
486 show_state 'init'
487
488 ulimit -S -t 123456
489 show_state '-S'
490
491 ulimit -H -t 123457
492 show_state '-H'
493
494 ulimit -t 123455
495 show_state 'no flag'
496
497 echo 'GET'
498
499 ulimit -S -t 123454
500 echo -n ' '; ulimit -t
501 echo -n ' '; ulimit -S -t
502 echo -n ' '; ulimit -H -t
503
504 ## STDOUT:
505 init
506 unlimited
507 unlimited
508
509 -S
510 123456
511 unlimited
512
513 -H
514 123456
515 123457
516
517 no flag
518 123455
519 123455
520
521 GET
522 123454
523 123454
524 123455
525 ## END
526
527 ## BUG dash/zsh STDOUT:
528 ## END
529
530 #### Changing resource limit is denied
531
532 # Not sure why these don't work
533 case $SH in dash|mksh) exit ;; esac
534
535
536 flag=-t
537
538 ulimit -S -H $flag 100
539 echo both=$?
540
541 ulimit -S $flag 90
542 echo soft=$?
543
544 ulimit -S $flag 95
545 echo soft=$?
546
547 ulimit -S $flag 105
548 if test $? -ne 0; then
549 echo soft OK
550 else
551 echo soft fail
552 fi
553
554 ulimit -H $flag 200
555 if test $? -ne 0; then
556 echo hard OK
557 else
558 echo hard fail
559 fi
560
561 ## STDOUT:
562 both=0
563 soft=0
564 soft=0
565 soft OK
566 hard OK
567 ## END
568
569 ## BUG dash/mksh STDOUT:
570 ## END
571
572 #### ulimit -n limits file descriptors
573
574 # OSH bug
575 # https://oilshell.zulipchat.com/#narrow/channel/502349-osh/topic/alpine.20build.20failures.20-.20make.20-.20ulimit.20-n.2064/with/519691301
576
577 $SH -c 'ulimit -n 64; echo hi >out'
578 echo status=$?
579
580 $SH -c 'ulimit -n 0; echo hi >out'
581 echo status=$?
582
583 ## STDOUT:
584 status=0
585 status=1
586 ## END
587
588 ## OK dash STDOUT:
589 status=0
590 status=2
591 ## END