diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-10-23 21:02:15 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-10-23 21:02:15 +0200 |
| commit | 6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d (patch) | |
| tree | ed74f2d281d2dae776f3105034717c049de77946 | |
| parent | 54779a47e9fa7f85b2a2ff744b9121f31a7758a9 (diff) | |
| download | busybox-w32-6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d.tar.gz busybox-w32-6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d.tar.bz2 busybox-w32-6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d.zip | |
awk: fix segfault on closing non-opened file
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | editors/awk.c | 182 | ||||
| -rwxr-xr-x | testsuite/awk.tests | 6 |
2 files changed, 102 insertions, 86 deletions
diff --git a/editors/awk.c b/editors/awk.c index 2245cad03..fb3bf6b47 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
| @@ -283,88 +283,80 @@ enum { | |||
| 283 | #define OC_B OC_BUILTIN | 283 | #define OC_B OC_BUILTIN |
| 284 | 284 | ||
| 285 | static const char tokenlist[] ALIGN1 = | 285 | static const char tokenlist[] ALIGN1 = |
| 286 | "\1(" NTC | 286 | "\1(" NTC |
| 287 | "\1)" NTC | 287 | "\1)" NTC |
| 288 | "\1/" NTC /* REGEXP */ | 288 | "\1/" NTC /* REGEXP */ |
| 289 | "\2>>" "\1>" "\1|" NTC /* OUTRDR */ | 289 | "\2>>" "\1>" "\1|" NTC /* OUTRDR */ |
| 290 | "\2++" "\2--" NTC /* UOPPOST */ | 290 | "\2++" "\2--" NTC /* UOPPOST */ |
| 291 | "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ | 291 | "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ |
| 292 | "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ | 292 | "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ |
| 293 | "\2*=" "\2/=" "\2%=" "\2^=" | 293 | "\2*=" "\2/=" "\2%=" "\2^=" |
| 294 | "\1+" "\1-" "\3**=" "\2**" | 294 | "\1+" "\1-" "\3**=" "\2**" |
| 295 | "\1/" "\1%" "\1^" "\1*" | 295 | "\1/" "\1%" "\1^" "\1*" |
| 296 | "\2!=" "\2>=" "\2<=" "\1>" | 296 | "\2!=" "\2>=" "\2<=" "\1>" |
| 297 | "\1<" "\2!~" "\1~" "\2&&" | 297 | "\1<" "\2!~" "\1~" "\2&&" |
| 298 | "\2||" "\1?" "\1:" NTC | 298 | "\2||" "\1?" "\1:" NTC |
| 299 | "\2in" NTC | 299 | "\2in" NTC |
| 300 | "\1," NTC | 300 | "\1," NTC |
| 301 | "\1|" NTC | 301 | "\1|" NTC |
| 302 | "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ | 302 | "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ |
| 303 | "\1]" NTC | 303 | "\1]" NTC |
| 304 | "\1{" NTC | 304 | "\1{" NTC |
| 305 | "\1}" NTC | 305 | "\1}" NTC |
| 306 | "\1;" NTC | 306 | "\1;" NTC |
| 307 | "\1\n" NTC | 307 | "\1\n" NTC |
| 308 | "\2if" "\2do" "\3for" "\5break" /* STATX */ | 308 | "\2if" "\2do" "\3for" "\5break" /* STATX */ |
| 309 | "\10continue" "\6delete" "\5print" | 309 | "\10continue" "\6delete" "\5print" |
| 310 | "\6printf" "\4next" "\10nextfile" | 310 | "\6printf" "\4next" "\10nextfile" |
| 311 | "\6return" "\4exit" NTC | 311 | "\6return" "\4exit" NTC |
| 312 | "\5while" NTC | 312 | "\5while" NTC |
| 313 | "\4else" NTC | 313 | "\4else" NTC |
| 314 | 314 | ||
| 315 | "\3and" "\5compl" "\6lshift" "\2or" | 315 | "\3and" "\5compl" "\6lshift" "\2or" |
| 316 | "\6rshift" "\3xor" | 316 | "\6rshift" "\3xor" |
| 317 | "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ | 317 | "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ |
| 318 | "\3cos" "\3exp" "\3int" "\3log" | 318 | "\3cos" "\3exp" "\3int" "\3log" |
| 319 | "\4rand" "\3sin" "\4sqrt" "\5srand" | 319 | "\4rand" "\3sin" "\4sqrt" "\5srand" |
| 320 | "\6gensub" "\4gsub" "\5index" "\6length" | 320 | "\6gensub" "\4gsub" "\5index" "\6length" |
| 321 | "\5match" "\5split" "\7sprintf" "\3sub" | 321 | "\5match" "\5split" "\7sprintf" "\3sub" |
| 322 | "\6substr" "\7systime" "\10strftime" "\6mktime" | 322 | "\6substr" "\7systime" "\10strftime" "\6mktime" |
| 323 | "\7tolower" "\7toupper" NTC | 323 | "\7tolower" "\7toupper" NTC |
| 324 | "\7getline" NTC | 324 | "\7getline" NTC |
| 325 | "\4func" "\10function" NTC | 325 | "\4func" "\10function" NTC |
| 326 | "\5BEGIN" NTC | 326 | "\5BEGIN" NTC |
| 327 | "\3END" "\0" | 327 | "\3END" |
| 328 | /* compiler adds trailing "\0" */ | ||
| 328 | ; | 329 | ; |
| 329 | 330 | ||
| 330 | static const uint32_t tokeninfo[] = { | 331 | static const uint32_t tokeninfo[] = { |
| 331 | 0, | 332 | 0, |
| 332 | 0, | 333 | 0, |
| 333 | OC_REGEXP, | 334 | OC_REGEXP, |
| 334 | xS|'a', xS|'w', xS|'|', | 335 | xS|'a', xS|'w', xS|'|', |
| 335 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', | 336 | OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', |
| 336 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', | 337 | OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), |
| 337 | OC_FIELD|xV|P(5), | 338 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', |
| 338 | OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), | 339 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', |
| 339 | OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', | 340 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', |
| 340 | OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', | 341 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', |
| 341 | OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', | 342 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, |
| 342 | OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', | 343 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), |
| 343 | OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', | 344 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', |
| 344 | OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', | 345 | OC_IN|SV|P(49), /* in */ |
| 345 | OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', | ||
| 346 | OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, | ||
| 347 | OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, | ||
| 348 | OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', | ||
| 349 | OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), | ||
| 350 | OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', | ||
| 351 | OC_COLON|xx|P(67)|':', | ||
| 352 | OC_IN|SV|P(49), | ||
| 353 | OC_COMMA|SS|P(80), | 346 | OC_COMMA|SS|P(80), |
| 354 | OC_PGETLINE|SV|P(37), | 347 | OC_PGETLINE|SV|P(37), |
| 355 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', | 348 | OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', |
| 356 | OC_UNARY|xV|P(19)|'!', | 349 | 0, /* ] */ |
| 357 | 0, | 350 | 0, |
| 358 | 0, | 351 | 0, |
| 359 | 0, | 352 | 0, |
| 360 | 0, | 353 | 0, /* \n */ |
| 361 | 0, | 354 | ST_IF, ST_DO, ST_FOR, OC_BREAK, |
| 362 | ST_IF, ST_DO, ST_FOR, OC_BREAK, | 355 | OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, |
| 363 | OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, | 356 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, |
| 364 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, | 357 | OC_RETURN|Vx, OC_EXIT|Nx, |
| 365 | OC_RETURN|Vx, OC_EXIT|Nx, | ||
| 366 | ST_WHILE, | 358 | ST_WHILE, |
| 367 | 0, | 359 | 0, /* else */ |
| 368 | 360 | ||
| 369 | OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), | 361 | OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), |
| 370 | OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), | 362 | OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), |
| @@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = { | |||
| 376 | OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), | 368 | OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), |
| 377 | OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), | 369 | OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), |
| 378 | OC_GETLINE|SV|P(0), | 370 | OC_GETLINE|SV|P(0), |
| 379 | 0, 0, | 371 | 0, 0, |
| 380 | 0, | 372 | 0, |
| 381 | 0 | 373 | 0 /* END */ |
| 382 | }; | 374 | }; |
| 383 | 375 | ||
| 384 | /* internal variable names and their initial values */ | 376 | /* internal variable names and their initial values */ |
| @@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v) | |||
| 1836 | int fd, so, eo, r, rp; | 1828 | int fd, so, eo, r, rp; |
| 1837 | char c, *m, *s; | 1829 | char c, *m, *s; |
| 1838 | 1830 | ||
| 1831 | debug_printf_eval("entered %s()\n", __func__); | ||
| 1832 | |||
| 1839 | /* we're using our own buffer since we need access to accumulating | 1833 | /* we're using our own buffer since we need access to accumulating |
| 1840 | * characters | 1834 | * characters |
| 1841 | */ | 1835 | */ |
| @@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v) | |||
| 1922 | rsm->pos = p - eo; | 1916 | rsm->pos = p - eo; |
| 1923 | rsm->size = size; | 1917 | rsm->size = size; |
| 1924 | 1918 | ||
| 1919 | debug_printf_eval("returning from %s(): %d\n", __func__, r); | ||
| 1920 | |||
| 1925 | return r; | 1921 | return r; |
| 1926 | } | 1922 | } |
| 1927 | 1923 | ||
| @@ -2347,6 +2343,8 @@ static var *evaluate(node *op, var *res) | |||
| 2347 | if (!op) | 2343 | if (!op) |
| 2348 | return setvar_s(res, NULL); | 2344 | return setvar_s(res, NULL); |
| 2349 | 2345 | ||
| 2346 | debug_printf_eval("entered %s()\n", __func__); | ||
| 2347 | |||
| 2350 | v1 = nvalloc(2); | 2348 | v1 = nvalloc(2); |
| 2351 | 2349 | ||
| 2352 | while (op) { | 2350 | while (op) { |
| @@ -2367,7 +2365,7 @@ static var *evaluate(node *op, var *res) | |||
| 2367 | opn = (opinfo & OPNMASK); | 2365 | opn = (opinfo & OPNMASK); |
| 2368 | g_lineno = op->lineno; | 2366 | g_lineno = op->lineno; |
| 2369 | op1 = op->l.n; | 2367 | op1 = op->l.n; |
| 2370 | debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK)); | 2368 | debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); |
| 2371 | 2369 | ||
| 2372 | /* execute inevitable things */ | 2370 | /* execute inevitable things */ |
| 2373 | if (opinfo & OF_RES1) | 2371 | if (opinfo & OF_RES1) |
| @@ -2387,6 +2385,7 @@ static var *evaluate(node *op, var *res) | |||
| 2387 | debug_printf_eval("L_d:%f\n", L_d); | 2385 | debug_printf_eval("L_d:%f\n", L_d); |
| 2388 | } | 2386 | } |
| 2389 | 2387 | ||
| 2388 | debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); | ||
| 2390 | switch (XC(opinfo & OPCLSMASK)) { | 2389 | switch (XC(opinfo & OPCLSMASK)) { |
| 2391 | 2390 | ||
| 2392 | /* -- iterative node type -- */ | 2391 | /* -- iterative node type -- */ |
| @@ -2642,8 +2641,6 @@ static var *evaluate(node *op, var *res) | |||
| 2642 | 2641 | ||
| 2643 | /* simple builtins */ | 2642 | /* simple builtins */ |
| 2644 | case XC( OC_FBLTIN ): { | 2643 | case XC( OC_FBLTIN ): { |
| 2645 | int i; | ||
| 2646 | rstream *rsm; | ||
| 2647 | double R_d = R_d; /* for compiler */ | 2644 | double R_d = R_d; /* for compiler */ |
| 2648 | 2645 | ||
| 2649 | switch (opn) { | 2646 | switch (opn) { |
| @@ -2709,26 +2706,37 @@ static var *evaluate(node *op, var *res) | |||
| 2709 | if (!op1) { | 2706 | if (!op1) { |
| 2710 | fflush(stdout); | 2707 | fflush(stdout); |
| 2711 | } else if (L.s && *L.s) { | 2708 | } else if (L.s && *L.s) { |
| 2712 | rsm = newfile(L.s); | 2709 | rstream *rsm = newfile(L.s); |
| 2713 | fflush(rsm->F); | 2710 | fflush(rsm->F); |
| 2714 | } else { | 2711 | } else { |
| 2715 | fflush_all(); | 2712 | fflush_all(); |
| 2716 | } | 2713 | } |
| 2717 | break; | 2714 | break; |
| 2718 | 2715 | ||
| 2719 | case F_cl: | 2716 | case F_cl: { |
| 2720 | i = 0; | 2717 | rstream *rsm; |
| 2718 | int err = 0; | ||
| 2721 | rsm = (rstream *)hash_search(fdhash, L.s); | 2719 | rsm = (rstream *)hash_search(fdhash, L.s); |
| 2720 | debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm); | ||
| 2722 | if (rsm) { | 2721 | if (rsm) { |
| 2723 | i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); | 2722 | debug_printf_eval("OC_FBLTIN F_cl " |
| 2723 | "rsm->is_pipe:%d, ->F:%p\n", | ||
| 2724 | rsm->is_pipe, rsm->F); | ||
| 2725 | /* Can be NULL if open failed. Example: | ||
| 2726 | * getline line <"doesnt_exist"; | ||
| 2727 | * close("doesnt_exist"); <--- here rsm->F is NULL | ||
| 2728 | */ | ||
| 2729 | if (rsm->F) | ||
| 2730 | err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); | ||
| 2724 | free(rsm->buffer); | 2731 | free(rsm->buffer); |
| 2725 | hash_remove(fdhash, L.s); | 2732 | hash_remove(fdhash, L.s); |
| 2726 | } | 2733 | } |
| 2727 | if (i != 0) | 2734 | if (err) |
| 2728 | setvar_i(intvar[ERRNO], errno); | 2735 | setvar_i(intvar[ERRNO], errno); |
| 2729 | R_d = (double)i; | 2736 | R_d = (double)err; |
| 2730 | break; | 2737 | break; |
| 2731 | } | 2738 | } |
| 2739 | } /* switch */ | ||
| 2732 | setvar_i(res, R_d); | 2740 | setvar_i(res, R_d); |
| 2733 | break; | 2741 | break; |
| 2734 | } | 2742 | } |
| @@ -2877,6 +2885,7 @@ static var *evaluate(node *op, var *res) | |||
| 2877 | } /* while (op) */ | 2885 | } /* while (op) */ |
| 2878 | 2886 | ||
| 2879 | nvfree(v1); | 2887 | nvfree(v1); |
| 2888 | debug_printf_eval("returning from %s(): %p\n", __func__, res); | ||
| 2880 | return res; | 2889 | return res; |
| 2881 | #undef fnargs | 2890 | #undef fnargs |
| 2882 | #undef seed | 2891 | #undef seed |
| @@ -2919,18 +2928,19 @@ static int is_assignment(const char *expr) | |||
| 2919 | { | 2928 | { |
| 2920 | char *exprc, *s, *s0, *s1; | 2929 | char *exprc, *s, *s0, *s1; |
| 2921 | 2930 | ||
| 2922 | exprc = xstrdup(expr); | 2931 | if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) { |
| 2923 | if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { | ||
| 2924 | free(exprc); | ||
| 2925 | return FALSE; | 2932 | return FALSE; |
| 2926 | } | 2933 | } |
| 2927 | 2934 | ||
| 2935 | exprc = xstrdup(expr); | ||
| 2936 | s0 = exprc + (s0 - expr); | ||
| 2928 | *s++ = '\0'; | 2937 | *s++ = '\0'; |
| 2929 | s0 = s1 = s; | 2938 | |
| 2939 | s = s1 = s0; | ||
| 2930 | while (*s) | 2940 | while (*s) |
| 2931 | *s1++ = nextchar(&s); | 2941 | *s1++ = nextchar(&s); |
| 2932 | |||
| 2933 | *s1 = '\0'; | 2942 | *s1 = '\0'; |
| 2943 | |||
| 2934 | setvar_u(newvar(exprc), s0); | 2944 | setvar_u(newvar(exprc), s0); |
| 2935 | free(exprc); | 2945 | free(exprc); |
| 2936 | return TRUE; | 2946 | return TRUE; |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 56b11ca46..0afe9b9e7 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
| @@ -77,6 +77,12 @@ testing "awk string cast (bug 725)" \ | |||
| 77 | testing "awk handles whitespace before array subscript" \ | 77 | testing "awk handles whitespace before array subscript" \ |
| 78 | "awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" "" | 78 | "awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" "" |
| 79 | 79 | ||
| 80 | # GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2", | ||
| 81 | # do we need to emulate that as well? | ||
| 82 | testing "awk handles non-existing file correctly" \ | ||
| 83 | "awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \ | ||
| 84 | "2\n0\nOk\n" "" "" | ||
| 85 | |||
| 80 | prg=' | 86 | prg=' |
| 81 | BEGIN { | 87 | BEGIN { |
| 82 | u["a"]=1 | 88 | u["a"]=1 |
