awk: fix segfault on closing non-opened file
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
54779a47e9
commit
6a0d7490ea
180
editors/awk.c
180
editors/awk.c
@ -283,88 +283,80 @@ enum {
|
|||||||
#define OC_B OC_BUILTIN
|
#define OC_B OC_BUILTIN
|
||||||
|
|
||||||
static const char tokenlist[] ALIGN1 =
|
static const char tokenlist[] ALIGN1 =
|
||||||
"\1(" NTC
|
"\1(" NTC
|
||||||
"\1)" NTC
|
"\1)" NTC
|
||||||
"\1/" NTC /* REGEXP */
|
"\1/" NTC /* REGEXP */
|
||||||
"\2>>" "\1>" "\1|" NTC /* OUTRDR */
|
"\2>>" "\1>" "\1|" NTC /* OUTRDR */
|
||||||
"\2++" "\2--" NTC /* UOPPOST */
|
"\2++" "\2--" NTC /* UOPPOST */
|
||||||
"\2++" "\2--" "\1$" NTC /* UOPPRE1 */
|
"\2++" "\2--" "\1$" NTC /* UOPPRE1 */
|
||||||
"\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
|
"\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
|
||||||
"\2*=" "\2/=" "\2%=" "\2^="
|
"\2*=" "\2/=" "\2%=" "\2^="
|
||||||
"\1+" "\1-" "\3**=" "\2**"
|
"\1+" "\1-" "\3**=" "\2**"
|
||||||
"\1/" "\1%" "\1^" "\1*"
|
"\1/" "\1%" "\1^" "\1*"
|
||||||
"\2!=" "\2>=" "\2<=" "\1>"
|
"\2!=" "\2>=" "\2<=" "\1>"
|
||||||
"\1<" "\2!~" "\1~" "\2&&"
|
"\1<" "\2!~" "\1~" "\2&&"
|
||||||
"\2||" "\1?" "\1:" NTC
|
"\2||" "\1?" "\1:" NTC
|
||||||
"\2in" NTC
|
"\2in" NTC
|
||||||
"\1," NTC
|
"\1," NTC
|
||||||
"\1|" NTC
|
"\1|" NTC
|
||||||
"\1+" "\1-" "\1!" NTC /* UOPPRE2 */
|
"\1+" "\1-" "\1!" NTC /* UOPPRE2 */
|
||||||
"\1]" NTC
|
"\1]" NTC
|
||||||
"\1{" NTC
|
"\1{" NTC
|
||||||
"\1}" NTC
|
"\1}" NTC
|
||||||
"\1;" NTC
|
"\1;" NTC
|
||||||
"\1\n" NTC
|
"\1\n" NTC
|
||||||
"\2if" "\2do" "\3for" "\5break" /* STATX */
|
"\2if" "\2do" "\3for" "\5break" /* STATX */
|
||||||
"\10continue" "\6delete" "\5print"
|
"\10continue" "\6delete" "\5print"
|
||||||
"\6printf" "\4next" "\10nextfile"
|
"\6printf" "\4next" "\10nextfile"
|
||||||
"\6return" "\4exit" NTC
|
"\6return" "\4exit" NTC
|
||||||
"\5while" NTC
|
"\5while" NTC
|
||||||
"\4else" NTC
|
"\4else" NTC
|
||||||
|
|
||||||
"\3and" "\5compl" "\6lshift" "\2or"
|
"\3and" "\5compl" "\6lshift" "\2or"
|
||||||
"\6rshift" "\3xor"
|
"\6rshift" "\3xor"
|
||||||
"\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
|
"\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
|
||||||
"\3cos" "\3exp" "\3int" "\3log"
|
"\3cos" "\3exp" "\3int" "\3log"
|
||||||
"\4rand" "\3sin" "\4sqrt" "\5srand"
|
"\4rand" "\3sin" "\4sqrt" "\5srand"
|
||||||
"\6gensub" "\4gsub" "\5index" "\6length"
|
"\6gensub" "\4gsub" "\5index" "\6length"
|
||||||
"\5match" "\5split" "\7sprintf" "\3sub"
|
"\5match" "\5split" "\7sprintf" "\3sub"
|
||||||
"\6substr" "\7systime" "\10strftime" "\6mktime"
|
"\6substr" "\7systime" "\10strftime" "\6mktime"
|
||||||
"\7tolower" "\7toupper" NTC
|
"\7tolower" "\7toupper" NTC
|
||||||
"\7getline" NTC
|
"\7getline" NTC
|
||||||
"\4func" "\10function" NTC
|
"\4func" "\10function" NTC
|
||||||
"\5BEGIN" NTC
|
"\5BEGIN" NTC
|
||||||
"\3END" "\0"
|
"\3END"
|
||||||
|
/* compiler adds trailing "\0" */
|
||||||
;
|
;
|
||||||
|
|
||||||
static const uint32_t tokeninfo[] = {
|
static const uint32_t tokeninfo[] = {
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
OC_REGEXP,
|
OC_REGEXP,
|
||||||
xS|'a', xS|'w', xS|'|',
|
xS|'a', xS|'w', xS|'|',
|
||||||
OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
|
OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
|
||||||
OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M',
|
OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
|
||||||
OC_FIELD|xV|P(5),
|
OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
|
||||||
OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74),
|
OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
|
||||||
OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
|
OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
|
||||||
OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/',
|
OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
|
||||||
OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
|
OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
|
||||||
OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-',
|
OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
|
||||||
OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
|
OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
|
||||||
OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%',
|
OC_IN|SV|P(49), /* in */
|
||||||
OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
|
|
||||||
OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
|
|
||||||
OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
|
|
||||||
OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
|
|
||||||
OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
|
|
||||||
OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
|
|
||||||
OC_COLON|xx|P(67)|':',
|
|
||||||
OC_IN|SV|P(49),
|
|
||||||
OC_COMMA|SS|P(80),
|
OC_COMMA|SS|P(80),
|
||||||
OC_PGETLINE|SV|P(37),
|
OC_PGETLINE|SV|P(37),
|
||||||
OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-',
|
OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
|
||||||
OC_UNARY|xV|P(19)|'!',
|
0, /* ] */
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0, /* \n */
|
||||||
0,
|
ST_IF, ST_DO, ST_FOR, OC_BREAK,
|
||||||
ST_IF, ST_DO, ST_FOR, OC_BREAK,
|
OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
|
||||||
OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
|
OC_PRINTF, OC_NEXT, OC_NEXTFILE,
|
||||||
OC_PRINTF, OC_NEXT, OC_NEXTFILE,
|
OC_RETURN|Vx, OC_EXIT|Nx,
|
||||||
OC_RETURN|Vx, OC_EXIT|Nx,
|
|
||||||
ST_WHILE,
|
ST_WHILE,
|
||||||
0,
|
0, /* else */
|
||||||
|
|
||||||
OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
|
OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
|
||||||
OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
|
OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
|
||||||
@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = {
|
|||||||
OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
|
OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
|
||||||
OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
|
OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
|
||||||
OC_GETLINE|SV|P(0),
|
OC_GETLINE|SV|P(0),
|
||||||
0, 0,
|
0, 0,
|
||||||
0,
|
0,
|
||||||
0
|
0 /* END */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* internal variable names and their initial values */
|
/* internal variable names and their initial values */
|
||||||
@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v)
|
|||||||
int fd, so, eo, r, rp;
|
int fd, so, eo, r, rp;
|
||||||
char c, *m, *s;
|
char c, *m, *s;
|
||||||
|
|
||||||
|
debug_printf_eval("entered %s()\n", __func__);
|
||||||
|
|
||||||
/* we're using our own buffer since we need access to accumulating
|
/* we're using our own buffer since we need access to accumulating
|
||||||
* characters
|
* characters
|
||||||
*/
|
*/
|
||||||
@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v)
|
|||||||
rsm->pos = p - eo;
|
rsm->pos = p - eo;
|
||||||
rsm->size = size;
|
rsm->size = size;
|
||||||
|
|
||||||
|
debug_printf_eval("returning from %s(): %d\n", __func__, r);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2347,6 +2343,8 @@ static var *evaluate(node *op, var *res)
|
|||||||
if (!op)
|
if (!op)
|
||||||
return setvar_s(res, NULL);
|
return setvar_s(res, NULL);
|
||||||
|
|
||||||
|
debug_printf_eval("entered %s()\n", __func__);
|
||||||
|
|
||||||
v1 = nvalloc(2);
|
v1 = nvalloc(2);
|
||||||
|
|
||||||
while (op) {
|
while (op) {
|
||||||
@ -2367,7 +2365,7 @@ static var *evaluate(node *op, var *res)
|
|||||||
opn = (opinfo & OPNMASK);
|
opn = (opinfo & OPNMASK);
|
||||||
g_lineno = op->lineno;
|
g_lineno = op->lineno;
|
||||||
op1 = op->l.n;
|
op1 = op->l.n;
|
||||||
debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK));
|
debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
|
||||||
|
|
||||||
/* execute inevitable things */
|
/* execute inevitable things */
|
||||||
if (opinfo & OF_RES1)
|
if (opinfo & OF_RES1)
|
||||||
@ -2387,6 +2385,7 @@ static var *evaluate(node *op, var *res)
|
|||||||
debug_printf_eval("L_d:%f\n", L_d);
|
debug_printf_eval("L_d:%f\n", L_d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
|
||||||
switch (XC(opinfo & OPCLSMASK)) {
|
switch (XC(opinfo & OPCLSMASK)) {
|
||||||
|
|
||||||
/* -- iterative node type -- */
|
/* -- iterative node type -- */
|
||||||
@ -2642,8 +2641,6 @@ static var *evaluate(node *op, var *res)
|
|||||||
|
|
||||||
/* simple builtins */
|
/* simple builtins */
|
||||||
case XC( OC_FBLTIN ): {
|
case XC( OC_FBLTIN ): {
|
||||||
int i;
|
|
||||||
rstream *rsm;
|
|
||||||
double R_d = R_d; /* for compiler */
|
double R_d = R_d; /* for compiler */
|
||||||
|
|
||||||
switch (opn) {
|
switch (opn) {
|
||||||
@ -2709,26 +2706,37 @@ static var *evaluate(node *op, var *res)
|
|||||||
if (!op1) {
|
if (!op1) {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
} else if (L.s && *L.s) {
|
} else if (L.s && *L.s) {
|
||||||
rsm = newfile(L.s);
|
rstream *rsm = newfile(L.s);
|
||||||
fflush(rsm->F);
|
fflush(rsm->F);
|
||||||
} else {
|
} else {
|
||||||
fflush_all();
|
fflush_all();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_cl:
|
case F_cl: {
|
||||||
i = 0;
|
rstream *rsm;
|
||||||
|
int err = 0;
|
||||||
rsm = (rstream *)hash_search(fdhash, L.s);
|
rsm = (rstream *)hash_search(fdhash, L.s);
|
||||||
|
debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
|
||||||
if (rsm) {
|
if (rsm) {
|
||||||
i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
|
debug_printf_eval("OC_FBLTIN F_cl "
|
||||||
|
"rsm->is_pipe:%d, ->F:%p\n",
|
||||||
|
rsm->is_pipe, rsm->F);
|
||||||
|
/* Can be NULL if open failed. Example:
|
||||||
|
* getline line <"doesnt_exist";
|
||||||
|
* close("doesnt_exist"); <--- here rsm->F is NULL
|
||||||
|
*/
|
||||||
|
if (rsm->F)
|
||||||
|
err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
|
||||||
free(rsm->buffer);
|
free(rsm->buffer);
|
||||||
hash_remove(fdhash, L.s);
|
hash_remove(fdhash, L.s);
|
||||||
}
|
}
|
||||||
if (i != 0)
|
if (err)
|
||||||
setvar_i(intvar[ERRNO], errno);
|
setvar_i(intvar[ERRNO], errno);
|
||||||
R_d = (double)i;
|
R_d = (double)err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} /* switch */
|
||||||
setvar_i(res, R_d);
|
setvar_i(res, R_d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -2877,6 +2885,7 @@ static var *evaluate(node *op, var *res)
|
|||||||
} /* while (op) */
|
} /* while (op) */
|
||||||
|
|
||||||
nvfree(v1);
|
nvfree(v1);
|
||||||
|
debug_printf_eval("returning from %s(): %p\n", __func__, res);
|
||||||
return res;
|
return res;
|
||||||
#undef fnargs
|
#undef fnargs
|
||||||
#undef seed
|
#undef seed
|
||||||
@ -2919,18 +2928,19 @@ static int is_assignment(const char *expr)
|
|||||||
{
|
{
|
||||||
char *exprc, *s, *s0, *s1;
|
char *exprc, *s, *s0, *s1;
|
||||||
|
|
||||||
exprc = xstrdup(expr);
|
if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) {
|
||||||
if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
|
|
||||||
free(exprc);
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exprc = xstrdup(expr);
|
||||||
|
s0 = exprc + (s0 - expr);
|
||||||
*s++ = '\0';
|
*s++ = '\0';
|
||||||
s0 = s1 = s;
|
|
||||||
|
s = s1 = s0;
|
||||||
while (*s)
|
while (*s)
|
||||||
*s1++ = nextchar(&s);
|
*s1++ = nextchar(&s);
|
||||||
|
|
||||||
*s1 = '\0';
|
*s1 = '\0';
|
||||||
|
|
||||||
setvar_u(newvar(exprc), s0);
|
setvar_u(newvar(exprc), s0);
|
||||||
free(exprc);
|
free(exprc);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -77,6 +77,12 @@ testing "awk string cast (bug 725)" \
|
|||||||
testing "awk handles whitespace before array subscript" \
|
testing "awk handles whitespace before array subscript" \
|
||||||
"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
|
"awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" ""
|
||||||
|
|
||||||
|
# GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2",
|
||||||
|
# do we need to emulate that as well?
|
||||||
|
testing "awk handles non-existing file correctly" \
|
||||||
|
"awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \
|
||||||
|
"2\n0\nOk\n" "" ""
|
||||||
|
|
||||||
prg='
|
prg='
|
||||||
BEGIN {
|
BEGIN {
|
||||||
u["a"]=1
|
u["a"]=1
|
||||||
|
Loading…
x
Reference in New Issue
Block a user