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