1 #!/bin/bash
2
3 # Copyright 2019 Joyent, Inc.
4
5 if [[ -z "$AWK" || -z "$WORKDIR" ]]; then
6 printf '$AWK and $WORKDIR must be set\n' >&2
7 exit 1
8 fi
9
10 TEMP0=$WORKDIR/test.temp.0
11 TEMP1=$WORKDIR/test.temp.1
12 TEMP2=$WORKDIR/test.temp.2
13 TEMP3=$WORKDIR/test.temp.3
14
15 RESULT=0
16
17 fail() {
18 echo "$1" >&2
19 RESULT=1
20 }
21
22 echo T.misc: miscellaneous buglets now watched for
23
24 rm -f core
25
26 echo 'The big brown over the lazy doe
27 The big brown over the lazy dog
28 x
29 The big brown over the lazy dog' > $TEMP0
30 echo 'failed
31 succeeded
32 failed
33 succeeded' > $TEMP1
34 $AWK '{ if (match($0, /^The big brown over the lazy dog/) == 0) {
35 printf("failed\n")
36 } else {
37 printf("succeeded\n")
38 }
39 } ' $TEMP0 > $TEMP2
40 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc ghosh RE bug'
41
42 echo '123
43 1234567890
44 12345678901' > $TEMP0
45 echo '12345678901' > $TEMP1
46 $AWK 'length($0) > 10' $TEMP0 > $TEMP2
47 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc last number bug'
48
49 # check some \ sequences in strings (ascii)
50 echo HIJKL > $TEMP1
51 echo $TEMP0 | $AWK '{ print "H\x49\x4a\x4BL" }' > $TEMP2
52 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc hex string cvt'
53
54 echo 012x45 > $TEMP1
55 $AWK 'BEGIN { print "0\061\62x\0645" }' > $TEMP2
56 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc oct string cvt'
57
58 # $i++ means ($i)++
59 echo 3 5 | $AWK '{ i = 1; print $i++ ; print $1, i }' > $TEMP1
60 echo '3
61 4 1' > $TEMP2
62 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc bad field increment'
63
64 # makes sure that fields are recomputed even if self-assignment
65 # take into account that subtracting from NF now rebuilds the record
66 echo 'a b c
67 s p q r
68 x y z' > $TEMP0
69 echo 'a
70 s p
71 x' > $TEMP1
72 $AWK '{ NF -= 2; $1 = $1; print }' < $TEMP0 > $TEMP2
73 diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad field self-assignment"
74
75 echo '1
76 1' > $TEMP1
77 $AWK 'BEGIN {x = 1; print x; x = x; print x}' > $TEMP2
78 diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad self-assignment"
79
80 echo 573109312 | $AWK '{print $1*4}' > $TEMP1
81 echo 2292437248 > $TEMP2
82 diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad overflow"
83
84 # note that there are 8-bit characters in the echo
85 # some shells will probably screw this up.
86 echo '#
87 code 1
88 code 2' |
89 $AWK '/^#/' > $TEMP1
90 echo '#' > $TEMP2
91 diff $TEMP1 $TEMP2 || fail "BAD: T.misc bad match of 8-bit char"
92
93 echo hello |
94 $AWK 'BEGIN { FILENAME = "/etc/passwd" }
95 { print $0 }' >/dev/null
96 if [[ $? -eq 139 ]]; then fail "BAD: T.misc /etc/passwd dropped core"; fi
97
98 echo hello |
99 $AWK ' function foo(foo) {
100 foo = 1
101 foo()
102 }
103 { foo(bar) }
104 ' >/dev/null 2>&1
105 if [[ $? -eq 139 ]]; then
106 fail "BAD: T.misc function foo(foo) dropped core"
107 rm -f core
108 fi
109
110 echo '2
111 10' |
112 $AWK '{ x[NR] = $0 } # test whether $0 is NUM as well as STR
113 END { if (x[1] > x[2]) print "BAD: T.misc: $0 is not NUM" }'
114
115
116 $AWK 'BEGIN {
117 npad = substr("alexander" " ",1,15)
118 print npad
119 }' > $TEMP0
120 grep '\\' $TEMP0 && fail "BAD: T.misc alexander fails"
121
122 # This should give an error about function arguments
123 $AWK '
124 function foo(x) { print "x is" x }
125 BEGIN { foo(foo) }
126 ' 2> $TEMP0
127 grep "can't use function foo" $TEMP0 >/dev/null || fail "BAD: T.misc fcn args"
128
129
130 # gawk defref test; should give error about undefined function
131 $AWK 'BEGIN { foo() }' 2> $TEMP0
132 grep "calling undefined function foo" $TEMP0 >/dev/null || fail "BAD: T.misc undefined function"
133
134
135 # gawk arrayparm test; should give error about function
136 $AWK '
137 BEGIN {
138 foo[1]=1;
139 foo[2]=2;
140 bug1(foo);
141 }
142 function bug1(i) {
143 for (i in foo) {
144 bug2(i);
145 delete foo[i];
146 print i,1,bot[1];
147 }
148 }
149 function bug2(arg) {
150 bot[arg]=arg;
151 }
152 ' 2> $TEMP0
153 grep "can.t assign to foo" $TEMP0 >/dev/null || fail "BAD: T.misc foo bug"
154
155
156 # This should be a syntax error
157 $AWK '
158 !x = y
159 ' 2> $TEMP0
160 grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error !x=y fails"
161
162 # This should print bbb
163 $AWK '
164 BEGIN { up[1] = "a"
165 for (i in up) gsub("a", "A", x)
166 print x x "bbb"
167 exit
168 }
169 ' > $TEMP0
170 grep bbb $TEMP0 >/dev/null || fail "BAD: T.misc gsub failed"
171
172 echo yes |
173 $AWK '
174 BEGIN {
175 printf "push return" >"/dev/null"
176 getline ans <"/dev/null"
177 } '
178 if [[ $? -eq 139 ]]; then fail "BAD: T.misc getline ans dropped core"; fi
179
180 $AWK 'BEGIN { unireghf() }
181 function unireghf(hfeed) { hfeed[1] = 0 }'
182 if [[ $? -eq 139 ]]; then fail "BAD: T.misc unireghf dropped core"; fi
183
184 echo x | $AWK '/[/]/' 2> $TEMP0
185 grep 'nonterminated character class' $TEMP0 >/dev/null || error 'BAD: T.misc nonterminated fails'
186 if [[ $? -eq 139 ]]; then fail "BAD: T.misc nonterminated dropped core"; fi
187
188 $AWK '
189 function f() { return 12345 }
190 BEGIN { printf "<%s>\n", f() }
191 ' > $TEMP0
192 grep '<12345>' $TEMP0 >/dev/null || fail 'BAD: T.misc <12345> fails'
193
194 echo 'abc
195 def
196
197 ghi
198 jkl' > $TEMP0
199 $AWK '
200 BEGIN { RS = ""
201 while (getline <"'$TEMP0'")
202 print
203 }' > $TEMP1
204 $AWK 'END {print NR}' $TEMP1 | grep 4 >/dev/null || fail 'BAD: T.misc abcdef fails'
205
206
207 # The following should not produce a warning about changing a constant
208 # nor about a curdled tempcell list
209 $AWK 'function f(x) { x = 2 }
210 BEGIN { f(1) }' > $TEMP0
211 grep '^' $TEMP0 && fail 'BAD: test constant change fails'
212
213 # The following should not produce a warning about a curdled tempcell list
214 $AWK 'function f(x) { x }
215 BEGIN { f(1) }' > $TEMP0
216 grep '^' $TEMP0 && fail 'BAD: test tempcell list fails'
217
218 $AWK 'BEGIN { print 9, a=10, 11; print a; exit }' > $TEMP1
219 echo '9 10 11
220 10' > $TEMP2
221 diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (embedded expression)'
222
223 echo "abc defgh ijkl" | $AWK '
224 { $1 = ""; line = $0; print line; print $0; $0 = line; print $0 }' > $TEMP1
225 echo " defgh ijkl
226 defgh ijkl
227 defgh ijkl" > $TEMP2
228 diff $TEMP1 $TEMP2 || fail 'BAD: T.misc (assignment to $0)'
229
230 $AWK '
231 function min(a, b)
232 {
233 if (a < b)
234 return a
235 else
236 return b
237 }
238 BEGIN { exit }
239 '
240 if [[ $? -eq 139 ]]; then fail "BAD: T.misc function min dropped core"; fi
241
242 # The following should not give a syntax error message:
243 $AWK '
244 function expand(chart) {
245 getline chart < "CHAR.ticks"
246 }
247 ' > $TEMP0
248 grep '^' $TEMP0 >/dev/null && fail 'BAD: T.misc expand error'
249
250 $AWK 'BEGIN { print 1e40 }' >/dev/null
251 if [[ $? -eq 139 ]]; then fail "BAD: T.misc 1E40 dropped core"; fi
252
253 # The following syntax error should not dump core:
254 $AWK '
255 $NF==3 {first=1}
256 $NF==2 && first==0 && (abs($1-o1)>120||abs($2-o2)>120) {print $0}
257 $NF==2 {o1=%1; o2=$2; first=0}
258 ' 2>/dev/null
259 if [[ $? -eq 139 ]]; then fail "BAD: T.misc first/abs dropped core"; fi
260
261 # The following syntax error should not dump core:
262 $AWK '{ n = split($1, address, !); print address[1] }' 2> $TEMP0
263 grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc split error'
264 if [[ $? -eq 139 ]]; then fail "BAD: T.misc split! dropped core"; fi
265
266 # The following should cause a syntax error message
267 $AWK 'BEGIN {"hello"}' 2> $TEMP0
268 grep 'illegal statement' $TEMP0 >/dev/null || fail 'BAD: T.misc hello error'
269
270 # The following should give a syntax error message:
271 $AWK '
272 function pile(c, r) {
273 r = ++pile[c]
274 }
275
276 { pile($1) }
277 ' 2> $TEMP0
278 grep 'context is' $TEMP0 >/dev/null || fail 'BAD: T.misc pile error'
279
280 # This should complain about missing atan2 argument:
281 $AWK 'BEGIN { atan2(1) }' 2> $TEMP0
282 grep 'requires two arg' $TEMP0 >/dev/null || fail 'BAD: T.misc atan2 error'
283
284 # This should not core dump:
285 $AWK 'BEGIN { f() }
286 function f(A) { delete A[1] }
287 '
288 if [[ $? -eq 139 ]]; then fail "BAD: T.misc delete dropped core"; fi
289
290 # nasty one: should not be able to overwrite constants
291 $AWK 'BEGIN { gsub(/ana/,"anda","banana")
292 printf "the monkey ate a %s\n", "banana" }
293 ' >/dev/null 2> $TEMP0
294 grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc gsub banana error'
295
296 # nasty one: should not be able to overwrite constants
297 $AWK 'BEGIN { sub(/ana/,"anda","banana")
298 printf "the monkey ate a %s\n", "banana" }
299 ' >/dev/null 2> $TEMP0
300 grep 'syntax error' $TEMP0 >/dev/null || fail 'BAD: T.misc sub banana error'
301
302 # line numbers used to double-count comments
303 $AWK '#
304 #
305 #
306 /x
307 ' >/dev/null 2> $TEMP0
308 grep 'line [45]' $TEMP0 >/dev/null || fail 'BAD: T.misc lineno'
309
310 echo 'x
\y' > $TEMP1
311 $AWK 'BEGIN { print "x\f\r\b\v\a\\y" }' > $TEMP2
312 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird chars'
313
314 echo 0 > $TEMP1
315 $AWK ' BEGIN { exit }
316 { print }
317 END { print NR }' > $TEMP2
318 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc BEGIN exit'
319
320 echo 1 > $TEMP1
321 $AWK ' { exit }
322 END { print NR }' /etc/passwd > $TEMP2
323 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit'
324
325 echo 1 > $TEMP1
326 $AWK ' {i = 1; while (i <= NF) {if (i == NF) exit; i++ } }
327 END { print NR }' /etc/passwd > $TEMP2
328 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 2'
329
330 echo 1 > $TEMP1
331 $AWK ' function f() {
332 i = 1; while (i <= NF) {if (i == NF) return NR; i++ }
333 }
334 { if (f() == 1) exit }
335 END { print NR }' /etc/passwd > $TEMP2
336 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return'
337
338 echo 1 > $TEMP1
339 $AWK ' function f() {
340 split("a b c", arr)
341 for (i in arr) {if (i == 3) return NR; i++ }
342 }
343 { if (f() == 1) exit }
344 END { print NR }' /etc/passwd > $TEMP2
345 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc while return'
346
347 echo 1 > $TEMP1
348 $AWK ' {i = 1; do { if (i == NF) exit; i++ } while (i <= NF) }
349 END { print NR }' /etc/passwd > $TEMP2
350 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 3'
351
352 echo 1 > $TEMP1
353 $AWK ' function f() {
354 i = 1; do { if (i == NF) return NR; i++ } while (i <= NF)
355 }
356 { if (f() == 1) exit }
357 END { print NR }' /etc/passwd > $TEMP2
358 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc do return'
359
360 echo 1 > $TEMP1
361 $AWK ' {i = 1; do { if (i == NF) break; i++ } while (i <= NF); exit }
362 END { print NR }' /etc/passwd > $TEMP2
363 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 4'
364
365 echo 1 > $TEMP1
366 $AWK ' { n = split($0, x)
367 for (i in x) {
368 if (i == 1)
369 exit } }
370 END { print NR }' /etc/passwd > $TEMP2
371 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc immmediate exit 5'
372
373 echo XXXXXXXX > $TEMP1
374 $AWK 'BEGIN { s = "ab\fc\rd\be"
375 t = s; gsub("[" s "]", "X", t); print t }' > $TEMP2
376 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc weird escapes in char class'
377
378 $AWK '{}' /etc/passwd glop/glop > $TEMP0 2> $TEMP2
379 grep "can't open.*glop" $TEMP2 >/dev/null || fail "BAD: T.misc can't open"
380
381 echo '
382
383
384 a
385 aa
386
387 b
388
389
390 c
391
392 ' > $TEMP0
393 echo 3 > $TEMP1
394 $AWK 'BEGIN { RS = "" }; END { print NR }' $TEMP0 > $TEMP2
395 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc RS botch'
396
397 $AWK 'BEGIN \
398 {
399 print "hello, world"
400 }
401 }}}' > $TEMP1 2> $TEMP2
402 grep 'source line 5' $TEMP2 >/dev/null 2>&1 || fail 'BAD: T.misc continuation line number'
403
404
405 echo 111 222 333 > $TEMP0
406 $AWK '{ f[1]=1; f[2]=2; print $f[1], $f[1]++, $f[2], f[1], f[2] }' $TEMP0 > $TEMP2
407 echo 111 111 222 2 2 > $TEMP1
408 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc $f[1]++'
409
410
411 # These should be syntax errors
412 $AWK . 2> $TEMP0
413 grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error . fails"
414
415 $AWK .. 2> $TEMP0
416 grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .. fails"
417
418 $AWK .E. 2> $TEMP0
419 grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .E. fails"
420
421 $AWK .++. 2> $TEMP0
422 grep "syntax error" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error .++. fails"
423
424
425
426 # These should be syntax errors
427 $AWK '$' 2> $TEMP0
428 grep "unexpected" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error $ fails"
429
430 $AWK '{print $' 2> $TEMP0
431 grep "unexpected" $TEMP0 >/dev/null || fail "BAD: T.misc syntax error \$2 fails"
432
433 $AWK '"' 2> $TEMP0
434 grep "non-terminated" $TEMP0 >/dev/null || fail "BAD: T.misc bare quote fails"
435
436
437 # %c of 0 is explicit null byte
438
439 echo '3' > $TEMP1
440 $AWK 'BEGIN {printf("%c%c\n", 0, 0) }' | wc | $AWK '{print $3}' > $TEMP2
441 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc null byte'
442
443 # non-terminated RE
444
445 $AWK /xyz > $TEMP0 2>&1
446 grep "non-terminated" $TEMP0 >/dev/null || fail "BAD: T.misc non-terminated RE"
447
448 # next several were infinite loops, found by brian tsang.
449 # this is his example:
450
451 $AWK 'BEGIN {
452 switch (substr("x",1,1)) {
453 case /ask.com/:
454 break
455 case "google":
456 break
457 }
458 }' > $TEMP0 2>&1
459 grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 1"
460
461 $AWK 'BEGIN { s { c /./ } }' > $TEMP0 2>&1
462 grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 2"
463
464 $AWK 'BEGIN { s { c /../ } }' > $TEMP0 2>&1
465 grep "illegal statement" $TEMP0 >/dev/null || fail "BAD: T.misc looping syntax error 3"
466
467 $AWK 'BEGIN {printf "%2$s %1$s\n", "a", "b"}' >$TEMP0 2>&1
468 grep "'$' not permitted in awk formats" $TEMP0 >/dev/null || fail "BAD: T.misc '$' not permitted in formats"
469
470 echo 'a
471 b c
472 de fg hi' > $TEMP0
473 $AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1
474 awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2
475 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0'
476
477 echo 'fg hi' > $TEMP0
478 $AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1
479 awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2
480 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0'
481
482 echo '' > $TEMP0
483 $AWK 'END { print NF, $0 }' $TEMP0 > $TEMP1
484 awk '{ print NF, $0 }' $TEMP0| tail -1 > $TEMP2
485 cmp -s $TEMP1 $TEMP2 || fail 'BAD: T.misc END must preserve $0'
486
487
488 LC_ALL= LC_NUMERIC=ru_RU.ISO8859-5 $AWK 'BEGIN {
489 "echo 1,200" | getline;
490 if ($1 == 1.2) {
491 printf "good ";
492 } else {
493 printf "bad ";
494 }
495 n = 2.3;
496 print ($1 + 0.1), (n + 0.1);
497 }' > $TEMP1
498 echo 'good 1,3 2,4' > $TEMP2
499 diff $TEMP1 $TEMP2 || fail 'BAD: T.misc LC_NUMERIC should change radix'
500
501 $AWK 'function foo(q) {
502 return (q = q);
503 }
504 BEGIN { print foo("h"); }' > $TEMP1
505 echo 'h' > $TEMP2
506 diff $TEMP1 $TEMP2 || fail 'BAD: T.misc return tempcell'
507
508 $AWK -v RECSIZE=8192 'BEGIN {
509 for (c = 0; c < 3; c++) {
510 a = (RECSIZE % 2 > 0 ? "5" : "55");
511 while (length(a) < RECSIZE + c) {
512 a = a " 5";
513 }
514 $0 = a;
515 print $2;
516 }
517 }' > $TEMP1
518 printf '5\n5\n5\n' > $TEMP2
519 diff $TEMP1 $TEMP2 || fail 'BAD: T.misc initial fields overflow'
520
521 exit $RESULT