summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnold D. Robbins <arnold@skeeve.com>2023-12-25 22:33:13 +0200
committerArnold D. Robbins <arnold@skeeve.com>2023-12-25 22:33:13 +0200
commit54c74c3a879bbfe777def726598bba362fd2e0ef (patch)
tree64cb74be1709923933038a752b000a2b51f29bc2
parente5d9a0d273a1c082cd9df4bcb508c1e5dc07dc65 (diff)
parent93333bd8d23a7c87f1980310afd5274c33311c36 (diff)
downloadgawk-54c74c3a879bbfe777def726598bba362fd2e0ef.tar.gz
Merge branch 'gawk-5.3-stable'
-rw-r--r--ChangeLog48
-rw-r--r--awk.h5
-rw-r--r--builtin.c2
-rw-r--r--debug.c56
-rw-r--r--io.c25
-rw-r--r--pc/ChangeLog8
-rw-r--r--pc/Makefile.tst19
-rw-r--r--test/ChangeLog11
-rw-r--r--test/Makefile.am13
-rw-r--r--test/Makefile.in28
-rw-r--r--test/Maketests15
-rw-r--r--test/dbugarray2.awk4
-rw-r--r--test/dbugarray2.in3
-rw-r--r--test/dbugarray2.ok4
-rw-r--r--test/dbugarray3.awk18
-rw-r--r--test/dbugarray3.in3
-rw-r--r--test/dbugarray3.ok14
-rw-r--r--test/dbugarray4.awk4
-rw-r--r--test/dbugarray4.in7
-rw-r--r--test/dbugarray4.ok23
20 files changed, 286 insertions, 24 deletions
diff --git a/ChangeLog b/ChangeLog
index 4a3d20d..7753741 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,51 @@
+2023-12-25 Arnold D. Robbins <arnold@skeeve.com>
+
+ * debug.c (serialize_list): Fix a compiler warning about
+ an unused variable.
+
+2024-12-25 Andrew J. Schorr <aschorr@telemetry-investments.com>
+
+ * io.c (get_read_timeout): Make gawk match the doc and have
+ GAWK_READ_TIMEOUT work if no entry in PROCINFO. Thanks
+ to Ed Morton for the report.
+
+2023-12-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * debug.c (print_array): Use the subscript as the
+ subarray name instead of the `vname' field. This field
+ is not there for arrays created with NUMINT subscripts.
+ Thanks again to Hermann Peifer for the report.
+
+ Unrelated:
+
+ * debug.c (find_subscript): Fail early on Node_var_new
+ and Node_elem_new. Thanks yet again to Hermann Peifer
+ for the report.
+
+2023-12-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ Fix multidimensional array printing in the debugger, again.
+ Thanks again to Hermann Peifer for the report.
+
+ * debug.c (print_array): Maintain a stack of array names
+ and indexes, and print it when printing the value.
+ (print_array_names): New function.
+
+2023-12-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ Try to close a race condition window on SIGPIPE. See the thread at
+ https://lists.gnu.org/archive/html/bug-gawk/2023-12/msg00011.html.
+ Thanks to Andreas Schwab <schwab@suse.de>.
+
+ * awk.h (ignore_sigpipe, set_sigpipe_to_default): Remove decls,
+ they're not functions.
+ (do_nothing_on_signal): Add declaration.
+ (silent_catch_sigpipe): New macro.
+ * builtin.c (do_system): Replace call of set_sigpipe_to_default()
+ with call to silent_catch_sigpipe().
+ * io.c (redirect_string, gawk_popen): Ditto.
+ (do_nothing_on_signal): New function.
+
2023-12-12 Eli Zaretskii <eliz@gnu.org>
* io.c (redirect_string): Check registered parsers before failing
diff --git a/awk.h b/awk.h
index 8e38976..08ef36c 100644
--- a/awk.h
+++ b/awk.h
@@ -1668,8 +1668,7 @@ extern bool inrec(IOBUF *iop, int *errcode);
extern int nextfile(IOBUF **curfile, bool skipping);
extern bool is_non_fatal_std(FILE *fp);
extern bool is_non_fatal_redirect(const char *str, size_t len);
-extern void ignore_sigpipe(void);
-extern void set_sigpipe_to_default(void);
+extern void do_nothing_on_signal(int sig);
extern bool non_fatal_flush_std_file(FILE *fp);
extern size_t gawk_fwrite(const void *buf, size_t size, size_t count, FILE *fp, void *opaque);
@@ -2160,9 +2159,11 @@ str_terminate_f(NODE *n, char *savep)
#define ignore_sigpipe() signal(SIGPIPE, SIG_IGN)
#define set_sigpipe_to_default() signal(SIGPIPE, SIG_DFL)
#define die_via_sigpipe() (signal(SIGPIPE, SIG_DFL), kill(getpid(), SIGPIPE))
+#define silent_catch_sigpipe() signal(SIGPIPE, do_nothing_on_signal)
#else
#define ignore_sigpipe()
#define set_sigpipe_to_default()
+#define silent_catch_sigpipe()
#ifdef __MINGW32__
/* 0xC0000008 is EXCEPTION_INVALID_HANDLE, somewhat appropriate for EPIPE */
#define die_via_sigpipe() exit(0xC0000008)
diff --git a/builtin.c b/builtin.c
index 6fc76b7..84a0dff 100644
--- a/builtin.c
+++ b/builtin.c
@@ -2269,7 +2269,7 @@ do_system(int nargs)
cmd[tmp->stlen] = '\0';
os_restore_mode(fileno(stdin));
- set_sigpipe_to_default();
+ silent_catch_sigpipe();
status = system(cmd);
/*
diff --git a/debug.c b/debug.c
index 028e209..8c5bee6 100644
--- a/debug.c
+++ b/debug.c
@@ -1084,6 +1084,18 @@ print_field(long field_num)
}
}
+/* print_array_names --- print the stack of array names */
+
+static void
+print_array_names(const char **names, size_t num_names, FILE *out_fp)
+{
+ size_t i;
+
+ gprintf(out_fp, "%s", names[0]);
+ for (i = 1; i < num_names; i++)
+ gprintf(out_fp, "[\"%s\"]", names[i]);
+}
+
/* print_array --- print the contents of an array */
static int
@@ -1096,7 +1108,18 @@ print_array(volatile NODE *arr, char *arr_name)
volatile NODE *r;
volatile int ret = 0;
volatile jmp_buf pager_quit_tag_stack;
- static int level = 0;
+
+ // manage a stack of names for printing deeply nested arrays
+ static const char **names = NULL;
+ static size_t cur_name = 0;
+ static size_t num_names = 0;
+#define INITIAL_NAME_COUNT 10
+
+ if (names == NULL) {
+ emalloc(names, const char **, INITIAL_NAME_COUNT * sizeof(char *), "print_array");
+ memset(names, 0, INITIAL_NAME_COUNT * sizeof(char *));
+ num_names = INITIAL_NAME_COUNT;
+ }
if (assoc_empty((NODE *) arr)) {
gprintf(out_fp, _("array `%s' is empty\n"), arr_name);
@@ -1109,19 +1132,28 @@ print_array(volatile NODE *arr, char *arr_name)
list = assoc_list((NODE *) arr, "@ind_str_asc", SORTED_IN);
PUSH_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
- // level variable is so that we can print things like a[1][2][3] = 123 correctly.
if (setjmp(pager_quit_tag) == 0) {
- level++;
+ // push name onto stack
+ if (cur_name >= num_names) {
+ num_names *= 2;
+ erealloc(names, const char **, num_names * sizeof(char *), "print_array");
+ }
+ names[cur_name++] = arr_name;
+
+ // and print the array
for (i = 0; ret == 0 && i < num_elems; i++) {
subs = list[i];
r = *assoc_lookup((NODE *) arr, subs);
- if (level == 1)
- gprintf(out_fp, "%s", arr_name);
if (r->type == Node_var_array) {
- if (level >= 1)
- gprintf(out_fp, "[\"%.*s\"]", (int) subs->stlen, subs->stptr);
- ret = print_array(r, r->vname);
+ // 12/2023: Use sub->stptr here, not r->vname, since
+ // a subarray could have been created via
+ // split() or some other mechanism where flags has NUMINT in it.
+ // In this case, r->vname can be NULL, so pass in the
+ // subscript itself. This should be fixed in the code that
+ // builds such arrays.
+ ret = print_array(r, subs->stptr);
} else {
+ print_array_names(names, cur_name, out_fp);
gprintf(out_fp, "[\"%.*s\"] = ", (int) subs->stlen, subs->stptr);
valinfo((NODE *) r, gprintf, out_fp);
}
@@ -1130,11 +1162,11 @@ print_array(volatile NODE *arr, char *arr_name)
ret = 1;
POP_BINDING(pager_quit_tag_stack, pager_quit_tag, pager_quit_tag_valid);
+ cur_name--;
for (i = 0; i < num_elems; i++)
unref(list[i]);
efree(list);
- level--;
return ret;
}
@@ -1650,6 +1682,10 @@ find_subscript(struct list_item *item, NODE **ptr)
NODE *sub, *r;
int i = 0, count = item->num_subs;
+ // without this check, in_array() will SEGV...
+ if (symbol->type == Node_var_new || symbol->type == Node_elem_new)
+ return -1;
+
r = *ptr = NULL;
for (i = 0; i < count; i++) {
sub = item->subs[i];
@@ -4477,7 +4513,7 @@ serialize_list(int type)
int cnum = 0;
struct condition *cndn = NULL;
void *ptr, *end_ptr;
-#ifdef HAVE_LIBREADLINE
+#if defined(HAVE_LIBREADLINE) && defined(HAVE_HISTORY_LIST)
HIST_ENTRY *h = NULL;
#endif
diff --git a/io.c b/io.c
index 3ffac79..c423da6 100644
--- a/io.c
+++ b/io.c
@@ -947,7 +947,7 @@ redirect_string(const char *str, size_t explen, bool not_string,
(void) flush_io();
os_restore_mode(fileno(stdin));
- set_sigpipe_to_default();
+ silent_catch_sigpipe();
/*
* Don't check failure_fatal; see input pipe below.
* Note that the failure happens upon failure to fork,
@@ -2774,7 +2774,7 @@ gawk_popen(const char *cmd, struct redirect *rp)
FILE *current;
os_restore_mode(fileno(stdin));
- set_sigpipe_to_default();
+ silent_catch_sigpipe();
current = popen(cmd, binmode("r"));
@@ -4424,7 +4424,7 @@ in_PROCINFO(const char *pidx1, const char *pidx2, NODE **full_idx)
static long
get_read_timeout(IOBUF *iop)
{
- long tmout = 0;
+ long tmout = read_default_timeout; /* initialized from env. variable in init_io() */
if (PROCINFO_node != NULL) {
const char *name = iop->public.name;
@@ -4448,8 +4448,7 @@ get_read_timeout(IOBUF *iop)
(void) force_number(val);
tmout = get_number_si(val);
}
- } else
- tmout = read_default_timeout; /* initialized from env. variable in init_io() */
+ }
/* overwrite read routine only if an extension has not done so */
if ((iop->public.read_func == ( ssize_t(*)() ) read) && tmout > 0)
@@ -4593,3 +4592,19 @@ avoid_flush(const char *name)
return in_PROCINFO(bufferpipe, NULL, NULL) != NULL
|| in_PROCINFO(name, bufferpipe, NULL) != NULL;
}
+
+/* do_nothing_on_signal --- empty signal catcher for SIGPIPE */
+
+/*
+ * See the thread starting at
+ * https://lists.gnu.org/archive/html/bug-gawk/2023-12/msg00011.html.
+ *
+ * The hope is that by using this do-nothing function to catch
+ * SIGPIPE, instead of setting it to default, that when race conditions
+ * occur, gawk won't fatal out.
+ */
+
+void
+do_nothing_on_signal(int sig)
+{
+}
diff --git a/pc/ChangeLog b/pc/ChangeLog
index fd3c949..199b5ad 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -1,3 +1,11 @@
+2023-12-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.tst: Regenerated.
+
+2023-12-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.tst: Regenerated.
+
2023-12-12 Eli Zaretskii <eliz@gnu.org>
* gawkmisc.pc (optimal_bufsize): Return DEFBLKSIZE for directories
diff --git a/pc/Makefile.tst b/pc/Makefile.tst
index b318939..daf3c56 100644
--- a/pc/Makefile.tst
+++ b/pc/Makefile.tst
@@ -222,7 +222,7 @@ GAWK_EXT_TESTS = \
symtab11 symtab12 timeout typedregex1 typedregex2 typedregex3 \
typedregex4 typedregex5 typedregex6 typeof1 typeof2 typeof3 \
typeof4 typeof5 typeof6 unicode1 watchpoint1 \
- re_test typeof7 typeof8 dbugarray1
+ re_test typeof7 typeof8 dbugarray1 dbugarray2 dbugarray3 dbugarray4
ARRAYDEBUG_TESTS = arrdbg
EXTRA_TESTS = inftest regtest ignrcas3
@@ -244,7 +244,7 @@ SHLIB_TESTS = \
# List of the tests which should be run with --debug option:
NEED_DEBUG = dbugtypedre1 dbugtypedre2 dbugeval2 dbugeval3 dbugeval4 \
- dbugarray1
+ dbugarray1 dbugarray2 dbugarray3 dbugarray4
# List of the tests which should be run with --lint option:
@@ -3655,6 +3655,21 @@ dbugarray1:
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugarray2:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray3:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray4:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@ $(ZOS_FAIL)
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/ChangeLog b/test/ChangeLog
index 706c2a4..b955dcd 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,14 @@
+2023-12-24 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): New tests: dbugarray3, dbugarray4.
+ * dbugarray3.awk, dbugarray3.in, dbugarray3.ok,
+ dbugarray4.awk, dbugarray4.in, dbugarray4.ok: New files.
+
+2023-12-21 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): New test: dbugarray2.
+ * dbugarray2.awk, dbugarray2.in, dbugarray2.ok: New files.
+
2023-12-02 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (EXTRA_DIST): New test: dbugarray1.
diff --git a/test/Makefile.am b/test/Makefile.am
index 6742022..a876b3a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -247,6 +247,15 @@ EXTRA_DIST = \
dbugarray1.awk \
dbugarray1.in \
dbugarray1.ok \
+ dbugarray2.awk \
+ dbugarray2.in \
+ dbugarray2.ok \
+ dbugarray3.awk \
+ dbugarray3.in \
+ dbugarray3.ok \
+ dbugarray4.awk \
+ dbugarray4.in \
+ dbugarray4.ok \
dbugeval.in \
dbugeval.ok \
dbugeval2.awk \
@@ -1577,7 +1586,7 @@ GAWK_EXT_TESTS = \
symtab11 symtab12 timeout typedregex1 typedregex2 typedregex3 \
typedregex4 typedregex5 typedregex6 typeof1 typeof2 typeof3 \
typeof4 typeof5 typeof6 unicode1 watchpoint1 \
- re_test typeof7 typeof8 dbugarray1
+ re_test typeof7 typeof8 dbugarray1 dbugarray2 dbugarray3 dbugarray4
ARRAYDEBUG_TESTS = arrdbg
@@ -1602,7 +1611,7 @@ SHLIB_TESTS = \
# List of the tests which should be run with --debug option:
NEED_DEBUG = dbugtypedre1 dbugtypedre2 dbugeval2 dbugeval3 dbugeval4 \
- dbugarray1
+ dbugarray1 dbugarray2 dbugarray3 dbugarray4
# List of the tests which should be run with --lint option:
NEED_LINT = \
diff --git a/test/Makefile.in b/test/Makefile.in
index 5c14be7..1ef143f 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -511,6 +511,15 @@ EXTRA_DIST = \
dbugarray1.awk \
dbugarray1.in \
dbugarray1.ok \
+ dbugarray2.awk \
+ dbugarray2.in \
+ dbugarray2.ok \
+ dbugarray3.awk \
+ dbugarray3.in \
+ dbugarray3.ok \
+ dbugarray4.awk \
+ dbugarray4.in \
+ dbugarray4.ok \
dbugeval.in \
dbugeval.ok \
dbugeval2.awk \
@@ -1841,7 +1850,7 @@ GAWK_EXT_TESTS = \
symtab11 symtab12 timeout typedregex1 typedregex2 typedregex3 \
typedregex4 typedregex5 typedregex6 typeof1 typeof2 typeof3 \
typeof4 typeof5 typeof6 unicode1 watchpoint1 \
- re_test typeof7 typeof8 dbugarray1
+ re_test typeof7 typeof8 dbugarray1 dbugarray2 dbugarray3 dbugarray4
ARRAYDEBUG_TESTS = arrdbg
EXTRA_TESTS = inftest regtest ignrcas3
@@ -1863,7 +1872,7 @@ SHLIB_TESTS = \
# List of the tests which should be run with --debug option:
NEED_DEBUG = dbugtypedre1 dbugtypedre2 dbugeval2 dbugeval3 dbugeval4 \
- dbugarray1
+ dbugarray1 dbugarray2 dbugarray3 dbugarray4
# List of the tests which should be run with --lint option:
@@ -5451,6 +5460,21 @@ dbugarray1:
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugarray2:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray3:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray4:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@ $(ZOS_FAIL)
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/Maketests b/test/Maketests
index 9c2bf4f..bac220f 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -2334,6 +2334,21 @@ dbugarray1:
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+dbugarray2:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray3:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+dbugarray4:
+ @echo $@
+ @-AWKPATH="$(srcdir)" $(AWK) -f $@.awk --debug < "$(srcdir)"/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
double1:
@echo $@ $(ZOS_FAIL)
@-AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
diff --git a/test/dbugarray2.awk b/test/dbugarray2.awk
new file mode 100644
index 0000000..5af7922
--- /dev/null
+++ b/test/dbugarray2.awk
@@ -0,0 +1,4 @@
+BEGIN {
+ c[1][1] = 11
+ c[1][2] = 12
+}
diff --git a/test/dbugarray2.in b/test/dbugarray2.in
new file mode 100644
index 0000000..3050c91
--- /dev/null
+++ b/test/dbugarray2.in
@@ -0,0 +1,3 @@
+run
+print @c
+quit
diff --git a/test/dbugarray2.ok b/test/dbugarray2.ok
new file mode 100644
index 0000000..afa27fb
--- /dev/null
+++ b/test/dbugarray2.ok
@@ -0,0 +1,4 @@
+Starting program:
+Program exited normally with exit value: 0
+c["1"]["1"] = 11
+c["1"]["2"] = 12
diff --git a/test/dbugarray3.awk b/test/dbugarray3.awk
new file mode 100644
index 0000000..c179c1f
--- /dev/null
+++ b/test/dbugarray3.awk
@@ -0,0 +1,18 @@
+function walk_array(arr, name, i)
+{
+ for (i in arr) {
+ if (isarray(arr[i]))
+ walk_array(arr[i], (name "[" i "]"))
+ else
+ printf("%s[%s] = %s\n", name, i, arr[i])
+ }
+}
+
+BEGIN {
+ $0 = "1 2 3"
+ split($0, a[0])
+ a[1][1]
+ split($0, a[1])
+
+ walk_array(a, "a")
+}
diff --git a/test/dbugarray3.in b/test/dbugarray3.in
new file mode 100644
index 0000000..5abbb9a
--- /dev/null
+++ b/test/dbugarray3.in
@@ -0,0 +1,3 @@
+r
+p @a
+quit
diff --git a/test/dbugarray3.ok b/test/dbugarray3.ok
new file mode 100644
index 0000000..b5ee4a9
--- /dev/null
+++ b/test/dbugarray3.ok
@@ -0,0 +1,14 @@
+Starting program:
+a[0][1] = 1
+a[0][2] = 2
+a[0][3] = 3
+a[1][1] = 1
+a[1][2] = 2
+a[1][3] = 3
+Program exited normally with exit value: 0
+a["0"]["1"] = "1"
+a["0"]["2"] = "2"
+a["0"]["3"] = "3"
+a["1"]["1"] = "1"
+a["1"]["2"] = "2"
+a["1"]["3"] = "3"
diff --git a/test/dbugarray4.awk b/test/dbugarray4.awk
new file mode 100644
index 0000000..632ecb6
--- /dev/null
+++ b/test/dbugarray4.awk
@@ -0,0 +1,4 @@
+BEGIN {
+ a[1][1] = 1
+ a[1][2] = 2
+}
diff --git a/test/dbugarray4.in b/test/dbugarray4.in
new file mode 100644
index 0000000..8e85497
--- /dev/null
+++ b/test/dbugarray4.in
@@ -0,0 +1,7 @@
+r
+watch a[1]
+r
+cont
+cont
+cont
+q
diff --git a/test/dbugarray4.ok b/test/dbugarray4.ok
new file mode 100644
index 0000000..27217f4
--- /dev/null
+++ b/test/dbugarray4.ok
@@ -0,0 +1,23 @@
+Starting program:
+Program exited normally with exit value: 0
+Watchpoint 1: a["1"]
+error: attempt to use scalar value as array
+Restarting ...
+Starting program:
+Stopping in BEGIN ...
+Watchpoint 1: a["1"]
+ Old value: element not in array
+ New value: array, 0 elements
+main() at `dbugarray4.awk':2
+2 a[1][1] = 1
+Watchpoint 1: a["1"]
+ Old value: array, 0 elements
+ New value: array, 1 elements
+main() at `dbugarray4.awk':2
+2 a[1][1] = 1
+Watchpoint 1: a["1"]
+ Old value: array, 1 elements
+ New value: array, 2 elements
+main() at `dbugarray4.awk':3
+3 a[1][2] = 2
+Program exited normally with exit value: 0