aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2010-10-23 21:02:15 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2010-10-23 21:02:15 +0200
commit6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d (patch)
treeed74f2d281d2dae776f3105034717c049de77946
parent54779a47e9fa7f85b2a2ff744b9121f31a7758a9 (diff)
downloadbusybox-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.c182
-rwxr-xr-xtestsuite/awk.tests6
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
285static const char tokenlist[] ALIGN1 = 285static 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
330static const uint32_t tokeninfo[] = { 331static 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)" \
77testing "awk handles whitespace before array subscript" \ 77testing "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?
82testing "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
80prg=' 86prg='
81BEGIN { 87BEGIN {
82 u["a"]=1 88 u["a"]=1