awk: fix printf buffer overflow
function old new delta awk_printf 468 546 +78 fmt_num 239 247 +8 getvar_s 125 111 -14 evaluate 3343 3329 -14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/2 up/down: 86/-28) Total: 58 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
08ca313d7e
commit
e2e3802987
@ -904,25 +904,23 @@ static double my_strtod(char **pp)
|
|||||||
|
|
||||||
/* -------- working with variables (set/get/copy/etc) -------- */
|
/* -------- working with variables (set/get/copy/etc) -------- */
|
||||||
|
|
||||||
static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
|
static void fmt_num(const char *format, double n)
|
||||||
{
|
{
|
||||||
int r = 0;
|
if (n == (long long)n) {
|
||||||
char c;
|
snprintf(g_buf, MAXVARFMT, "%lld", (long long)n);
|
||||||
const char *s = format;
|
|
||||||
|
|
||||||
if (int_as_int && n == (long long)n) {
|
|
||||||
r = snprintf(b, size, "%lld", (long long)n);
|
|
||||||
} else {
|
} else {
|
||||||
|
const char *s = format;
|
||||||
|
char c;
|
||||||
|
|
||||||
do { c = *s; } while (c && *++s);
|
do { c = *s; } while (c && *++s);
|
||||||
if (strchr("diouxX", c)) {
|
if (strchr("diouxX", c)) {
|
||||||
r = snprintf(b, size, format, (int)n);
|
snprintf(g_buf, MAXVARFMT, format, (int)n);
|
||||||
} else if (strchr("eEfFgGaA", c)) {
|
} else if (strchr("eEfFgGaA", c)) {
|
||||||
r = snprintf(b, size, format, n);
|
snprintf(g_buf, MAXVARFMT, format, n);
|
||||||
} else {
|
} else {
|
||||||
syntax_error(EMSG_INV_FMT);
|
syntax_error(EMSG_INV_FMT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static xhash *iamarray(var *a)
|
static xhash *iamarray(var *a)
|
||||||
@ -999,7 +997,7 @@ static const char *getvar_s(var *v)
|
|||||||
{
|
{
|
||||||
/* if v is numeric and has no cached string, convert it to string */
|
/* if v is numeric and has no cached string, convert it to string */
|
||||||
if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
|
if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
|
||||||
fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
|
fmt_num(getvar_s(intvar[CONVFMT]), v->number);
|
||||||
v->string = xstrdup(g_buf);
|
v->string = xstrdup(g_buf);
|
||||||
v->type |= VF_CACHED;
|
v->type |= VF_CACHED;
|
||||||
}
|
}
|
||||||
@ -2315,12 +2313,9 @@ static int awk_getline(rstream *rsm, var *v)
|
|||||||
#endif
|
#endif
|
||||||
static char *awk_printf(node *n, int *len)
|
static char *awk_printf(node *n, int *len)
|
||||||
{
|
{
|
||||||
char *b = NULL;
|
char *b;
|
||||||
char *fmt, *s, *f;
|
char *fmt, *f;
|
||||||
const char *s1;
|
int i;
|
||||||
int i, j, incr, bsize;
|
|
||||||
char c, c1;
|
|
||||||
var *arg;
|
|
||||||
|
|
||||||
//tmpvar = nvalloc(1);
|
//tmpvar = nvalloc(1);
|
||||||
#define TMPVAR (&G.awk_printf__tmpvar)
|
#define TMPVAR (&G.awk_printf__tmpvar)
|
||||||
@ -2333,8 +2328,14 @@ static char *awk_printf(node *n, int *len)
|
|||||||
// to evaluate() potentially recursing into another awk_printf() can't
|
// to evaluate() potentially recursing into another awk_printf() can't
|
||||||
// mangle the value.
|
// mangle the value.
|
||||||
|
|
||||||
|
b = NULL;
|
||||||
i = 0;
|
i = 0;
|
||||||
while (*f) {
|
while (*f) { /* "print one format spec" loop */
|
||||||
|
char *s;
|
||||||
|
char c;
|
||||||
|
char sv;
|
||||||
|
var *arg;
|
||||||
|
|
||||||
s = f;
|
s = f;
|
||||||
while (*f && (*f != '%' || *++f == '%'))
|
while (*f && (*f != '%' || *++f == '%'))
|
||||||
f++;
|
f++;
|
||||||
@ -2343,40 +2344,55 @@ static char *awk_printf(node *n, int *len)
|
|||||||
syntax_error("%*x formats are not supported");
|
syntax_error("%*x formats are not supported");
|
||||||
f++;
|
f++;
|
||||||
}
|
}
|
||||||
|
|
||||||
incr = (f - s) + MAXVARFMT;
|
|
||||||
b = qrealloc(b, incr + i, &bsize);
|
|
||||||
c = *f;
|
c = *f;
|
||||||
if (c != '\0')
|
if (!c) {
|
||||||
f++;
|
/* Tail of fmt with no percent chars,
|
||||||
c1 = *f;
|
* or "....%" (percent seen, but no format specifier char found)
|
||||||
|
*/
|
||||||
|
goto tail;
|
||||||
|
}
|
||||||
|
sv = *++f;
|
||||||
*f = '\0';
|
*f = '\0';
|
||||||
arg = evaluate(nextarg(&n), TMPVAR);
|
arg = evaluate(nextarg(&n), TMPVAR);
|
||||||
|
|
||||||
j = i;
|
/* Result can be arbitrarily long. Example:
|
||||||
if (c == 'c' || !c) {
|
* printf "%99999s", "BOOM"
|
||||||
i += sprintf(b+i, s, is_numeric(arg) ?
|
*/
|
||||||
|
if (c == 'c') {
|
||||||
|
s = xasprintf(s, is_numeric(arg) ?
|
||||||
(char)getvar_i(arg) : *getvar_s(arg));
|
(char)getvar_i(arg) : *getvar_s(arg));
|
||||||
} else if (c == 's') {
|
} else if (c == 's') {
|
||||||
s1 = getvar_s(arg);
|
s = xasprintf(s, getvar_s(arg));
|
||||||
b = qrealloc(b, incr+i+strlen(s1), &bsize);
|
|
||||||
i += sprintf(b+i, s, s1);
|
|
||||||
} else {
|
} else {
|
||||||
i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
|
double d = getvar_i(arg);
|
||||||
|
if (strchr("diouxX", c)) {
|
||||||
|
//TODO: make it wider here (%x -> %llx etc)?
|
||||||
|
s = xasprintf(s, (int)d);
|
||||||
|
} else if (strchr("eEfFgGaA", c)) {
|
||||||
|
s = xasprintf(s, d);
|
||||||
|
} else {
|
||||||
|
syntax_error(EMSG_INV_FMT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*f = c1;
|
*f = sv;
|
||||||
|
|
||||||
/* if there was an error while sprintf, return value is negative */
|
if (i == 0) {
|
||||||
if (i < j)
|
b = s;
|
||||||
i = j;
|
i = strlen(b);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tail:
|
||||||
|
b = xrealloc(b, i + strlen(s) + 1);
|
||||||
|
i = stpcpy(b + i, s) - b;
|
||||||
|
if (!c) /* tail? */
|
||||||
|
break;
|
||||||
|
free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(fmt);
|
free(fmt);
|
||||||
//nvfree(tmpvar, 1);
|
//nvfree(tmpvar, 1);
|
||||||
#undef TMPVAR
|
#undef TMPVAR
|
||||||
|
|
||||||
b = xrealloc(b, i + 1);
|
|
||||||
b[i] = '\0';
|
|
||||||
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
|
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
|
||||||
if (len)
|
if (len)
|
||||||
*len = i;
|
*len = i;
|
||||||
@ -2936,8 +2952,8 @@ static var *evaluate(node *op, var *res)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
var *v = evaluate(nextarg(&op1), TMPVAR0);
|
var *v = evaluate(nextarg(&op1), TMPVAR0);
|
||||||
if (v->type & VF_NUMBER) {
|
if (v->type & VF_NUMBER) {
|
||||||
fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
|
fmt_num(getvar_s(intvar[OFMT]),
|
||||||
getvar_i(v), TRUE);
|
getvar_i(v));
|
||||||
fputs(g_buf, F);
|
fputs(g_buf, F);
|
||||||
} else {
|
} else {
|
||||||
fputs(getvar_s(v), F);
|
fputs(getvar_s(v), F);
|
||||||
|
Loading…
Reference in New Issue
Block a user