From cb042b05828c4c89320bc9c7454c04c2761bbb9a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 Jul 2021 13:29:32 +0200 Subject: awk: restore strdup elision optimization in assignment function old new delta evaluate 3339 3387 +48 Signed-off-by: Denys Vlasenko --- editors/awk.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'editors/awk.c') diff --git a/editors/awk.c b/editors/awk.c index 649198d..20672db 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -102,7 +102,7 @@ enum { #define VF_USER 0x0200 /* 1 = user input (may be numeric string) */ #define VF_SPECIAL 0x0400 /* 1 = requires extra handling when changed */ #define VF_WALK 0x0800 /* 1 = variable has alloc'd x.walker list */ -#define VF_FSTR 0x1000 /* 1 = var::string points to fstring buffer */ +#define VF_FSTR 0x1000 /* 1 = don't free() var::string (not malloced, or is owned by something else) */ #define VF_CHILD 0x2000 /* 1 = function arg; x.parent points to source */ #define VF_DIRTY 0x4000 /* 1 = variable was set explicitly */ @@ -1371,6 +1371,12 @@ static node *parse_expr(uint32_t term_tc) cn->a.n = vn->a.n; if (tc & TS_BINOP) { cn->l.n = vn; +//FIXME: this is the place to detect and reject assignments to non-lvalues. +//Currently we allow "assignments" to consts and temporaries, nonsense like this: +// awk 'BEGIN { "qwe" = 1 }' +// awk 'BEGIN { 7 *= 7 }' +// awk 'BEGIN { length("qwe") = 1 }' +// awk 'BEGIN { (1+1) += 3 }' expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; if ((t_info & OPCLSMASK) == OC_PGETLINE) { /* it's a pipe */ @@ -3043,14 +3049,17 @@ static var *evaluate(node *op, var *res) case XC( OC_MOVE ): debug_printf_eval("MOVE\n"); /* if source is a temporary string, jusk relink it to dest */ -//Disabled: if R.v is numeric but happens to have cached R.v->string, -//then L.v ends up being a string, which is wrong -// if (R.v == TMPVAR1 && R.v->string) { -// res = setvar_p(L.v, R.v->string); -// R.v->string = NULL; -// } else { + if (R.v == TMPVAR1 + && !(R.v->type & VF_NUMBER) + /* Why check !NUMBER? if R.v is a number but has cached R.v->string, + * L.v ends up a string, which is wrong */ + /*&& R.v->string - always not NULL (right?) */ + ) { + res = setvar_p(L.v, R.v->string); /* avoids strdup */ + R.v->string = NULL; + } else { res = copyvar(L.v, R.v); -// } + } break; case XC( OC_TERNARY ): -- cgit v1.1