aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew J. Schorr <aschorr@telemetry-investments.com>2017-11-14 14:28:48 -0500
committerAndrew J. Schorr <aschorr@telemetry-investments.com>2017-11-14 14:28:48 -0500
commit064d78b562c9670751c48673c6d1d171aff51a42 (patch)
tree8c50b4d4a4ba82be1a482ab3927dab6ded648fc7
parentfe60f215f0dc446e39d69d4663cbb8c5ef406535 (diff)
downloadegawk-064d78b562c9670751c48673c6d1d171aff51a42.tar.gz
egawk-064d78b562c9670751c48673c6d1d171aff51a42.tar.bz2
egawk-064d78b562c9670751c48673c6d1d171aff51a42.zip
Fix field corruption when $0 is reassigned with open $n references.
-rw-r--r--ChangeLog12
-rw-r--r--field.c16
-rw-r--r--interpret.h9
-rw-r--r--test/ChangeLog7
-rw-r--r--test/Makefile.am8
-rw-r--r--test/Makefile.in18
-rw-r--r--test/Maketests10
-rw-r--r--test/setrec0.awk8
-rw-r--r--test/setrec0.in1
-rw-r--r--test/setrec0.ok1
-rw-r--r--test/setrec1.awk9
-rw-r--r--test/setrec1.ok1
12 files changed, 91 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index a3e53e92..27adc355 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2017-11-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ Fix corruption when $0 is reassigned while other NODEs have open
+ references to $n. Thanks to Eric Pruitt <eric.pruitt@gmail.com> for
+ the bug report.
+ * field.c (purge_record): For each $n field variable, if valref > 1
+ and it has not already been malloced, make a copy of the string, since
+ $0 is about to be reset.
+ * interpret.h (Op_store_field): We must call the assign function
+ before unref, since we must copy any non-malloced $n string values
+ before freeing $0.
+
2017-11-09 Arnold D. Robbins <arnold@skeeve.com>
* main.c (usage): Add a note to not post bugs in comp.lang.awk.
diff --git a/field.c b/field.c
index 5ab718d4..5263cc61 100644
--- a/field.c
+++ b/field.c
@@ -341,14 +341,20 @@ static void
purge_record()
{
int i;
- NODE *n;
NF = -1;
for (i = 1; i <= parse_high_water; i++) {
- assert((fields_arr[i]->flags & MALLOC) == 0
- ? fields_arr[i]->valref == 1
- : true);
- unref(fields_arr[i]);
+ NODE *n;
+ NODE *r = fields_arr[i];
+ if ((r->flags & MALLOC) == 0 && r->valref > 1) {
+ /* This can and does happen. We must copy the string! */
+ const char *save = r->stptr;
+ emalloc(r->stptr, char *, r->stlen + 1, "purge_record");
+ memcpy(r->stptr, save, r->stlen);
+ r->stptr[r->stlen] = '\0';
+ r->flags |= MALLOC;
+ }
+ unref(r);
getnode(n);
*n = *Null_field;
fields_arr[i] = n;
diff --git a/interpret.h b/interpret.h
index 166a11e1..4b140c28 100644
--- a/interpret.h
+++ b/interpret.h
@@ -699,11 +699,16 @@ mod:
lhs = r_get_field(t1, & assign, false);
decr_sp();
DEREF(t1);
+ /*
+ * N.B. We must call assign() before unref, since
+ * we may need to copy $n values before freeing the
+ * $0 buffer.
+ */
+ assert(assign != NULL);
+ assign();
unref(*lhs);
r = POP_SCALAR();
UNFIELD(*lhs, r);
- assert(assign != NULL);
- assign();
}
break;
diff --git a/test/ChangeLog b/test/ChangeLog
index 4586d02e..1e1cf7ea 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,10 @@
+2017-11-14 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * Makefile.am (EXTRA_DIST): Add new tests setrec0 and setrec1.
+ (BASIC_TESTS): Add setrec0 and setrec1.
+ * setrec0.awk, setrec0.in, setrec0.ok: New files.
+ * setrec1.awk, setrec1.ok: New files.
+
2017-11-10 Arnold D. Robbins <arnold@skeeve.com>
* badargs.ok: Updated after code change.
diff --git a/test/Makefile.am b/test/Makefile.am
index cb17f9d6..1438e083 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -1003,6 +1003,11 @@ EXTRA_DIST = \
sclforin.ok \
sclifin.awk \
sclifin.ok \
+ setrec0.awk \
+ setrec0.in \
+ setrec0.ok \
+ setrec1.awk \
+ setrec1.ok \
shadow.awk \
shadow.ok \
shadowbuiltin.awk \
@@ -1229,7 +1234,8 @@ BASIC_TESTS = \
regexpbrack regexpbrack2 regexprange regrange reindops reparse resplit \
rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 rstest3 \
rstest4 rstest5 rswhite \
- scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr \
+ scalar sclforin sclifin setrec0 setrec1 \
+ sigpipe1 sortempty sortglos splitargv splitarr \
splitdef splitvar splitwht status-close strcat1 strnum1 strnum2 strtod \
subamp subback subi18n subsepnm subslash substr swaplns synerr1 synerr2 \
tradanch tweakfld \
diff --git a/test/Makefile.in b/test/Makefile.in
index 091927c5..5a190d7a 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1261,6 +1261,11 @@ EXTRA_DIST = \
sclforin.ok \
sclifin.awk \
sclifin.ok \
+ setrec0.awk \
+ setrec0.in \
+ setrec0.ok \
+ setrec1.awk \
+ setrec1.ok \
shadow.awk \
shadow.ok \
shadowbuiltin.awk \
@@ -1486,7 +1491,8 @@ BASIC_TESTS = \
regexpbrack regexpbrack2 regexprange regrange reindops reparse resplit \
rri1 rs rscompat rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 rstest3 \
rstest4 rstest5 rswhite \
- scalar sclforin sclifin sigpipe1 sortempty sortglos splitargv splitarr \
+ scalar sclforin sclifin setrec0 setrec1 \
+ sigpipe1 sortempty sortglos splitargv splitarr \
splitdef splitvar splitwht status-close strcat1 strnum1 strnum2 strtod \
subamp subback subi18n subsepnm subslash substr swaplns synerr1 synerr2 \
tradanch tweakfld \
@@ -3755,6 +3761,16 @@ sclifin:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+setrec0:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+setrec1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
sigpipe1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/Maketests b/test/Maketests
index 8ae3f973..f64b8640 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -887,6 +887,16 @@ sclifin:
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+setrec0:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+setrec1:
+ @echo $@
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
sigpipe1:
@echo $@
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/setrec0.awk b/test/setrec0.awk
new file mode 100644
index 00000000..8d978aa7
--- /dev/null
+++ b/test/setrec0.awk
@@ -0,0 +1,8 @@
+function reassign(x, y) {
+ $0 = x
+ print y
+}
+
+{
+ reassign("larry", $1)
+}
diff --git a/test/setrec0.in b/test/setrec0.in
new file mode 100644
index 00000000..ce013625
--- /dev/null
+++ b/test/setrec0.in
@@ -0,0 +1 @@
+hello
diff --git a/test/setrec0.ok b/test/setrec0.ok
new file mode 100644
index 00000000..ce013625
--- /dev/null
+++ b/test/setrec0.ok
@@ -0,0 +1 @@
+hello
diff --git a/test/setrec1.awk b/test/setrec1.awk
new file mode 100644
index 00000000..3da1aa10
--- /dev/null
+++ b/test/setrec1.awk
@@ -0,0 +1,9 @@
+function reassign(x, y) {
+ $0 = x
+ print y
+}
+
+BEGIN {
+ $0 = substr("geronimo", 5, 3)
+ reassign(" 52", $1)
+}
diff --git a/test/setrec1.ok b/test/setrec1.ok
new file mode 100644
index 00000000..6bb3f869
--- /dev/null
+++ b/test/setrec1.ok
@@ -0,0 +1 @@
+nim