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 |