[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Changing $0 after gsub() breaks output
From: |
arnold |
Subject: |
Re: Changing $0 after gsub() breaks output |
Date: |
Sun, 29 Jan 2023 00:53:03 -0700 |
User-agent: |
Heirloom mailx 12.5 7/5/10 |
Hi.
Thank you for the bug report and easy reproducer. The patch
below fixes the problem. It will be in Git in the next
day or two.
Arnold
Yasuhiro Yamada <yamada@gr3.ie> wrote:
> Hi.
> Executing gsub() without an action and making changes to $0 will
> corrupt the output.
> This behavior seems like a bug.
>
> $ ./gawk --version
> GNU Awk 5.2.1, API 3.2, PMA Avon 8-g1
> ...
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1'
> q <===== broken output
>
> Interestingly, the result is different for each run.
>
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 b0 61 99 0a
> 260 a 231 \n
> 0000004
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 c0 e7 f7 0a
> 300 347 367 \n
> 0000004
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 c0 07 14 0a
> 300 \a 024 \n
> 0000004
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 c0 57 76 0a
> 300 W v \n
> 0000004
>
> Older versions do NOT reproduce this issue.
> Also, the outputs are as expected and intuitive.
>
> $ ./gawk --version
> GNU Awk 4.1.4, API: 1.1
> ...
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1'
> @@@
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 40 40 40 0a
> @ @ @ \n
> 0000004
>
> This issue seems to occur in v4.2.0 and later.
>
> $ ./gawk --version
> GNU Awk 4.2.0, API: 2.0
> ...
> $ echo abc | ./gawk 'gsub(".","@") && $0=$1' | od -tx1c
> 0000000 e0 4f fc 0a
> 340 O 374 \n
> 0000004
>
> My environment is
>
> $ uname -a
> Linux ip-172-31-9-222 5.4.0-1093-aws #102~18.04.2-Ubuntu SMP Wed
> Dec 7 00:31:59 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
> $ gcc --version
> gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
---------------------------------------------
diff --git a/interpret.h b/interpret.h
index 4540d302..5adb229b 100644
--- a/interpret.h
+++ b/interpret.h
@@ -872,16 +874,30 @@ mod:
break;
case Op_assign:
+ {
+ NODE *save_lhs;
+
lhs = POP_ADDRESS();
r = TOP_SCALAR();
- unref(*lhs);
+ /*
+ * 1/2023:
+ * The old NODE pointed to by *lhs has to be freed.
+ * But we can't free it too early, in case it's both $0
and $1
+ * (Test case was gawk 'gusb(/./, "@") && $0=$1'). So
we save
+ * the old one, and after the assignment, we free it,
since
+ * $0 and $1 have the same stptr value but only $0 has
MALLOC
+ * in the flags. Whew!
+ */
+ save_lhs = *lhs;
if (r->type == Node_elem_new) {
DEREF(r);
r = dupnode(Nnull_string);
}
UPREF(r);
UNFIELD(*lhs, r);
+ unref(save_lhs);
REPLACE(r);
+ }
break;
case Op_subscript_assign: