While looking at `time' for other things, tb@ pointed out that the
following code is broken:

        $ time for i in 1 2; do echo $i; done
        ksh: : is read only

Note the missing variable name: time's pipeline fails since for's
identifier gets mangled to an empty string by get_command() at
sync.c:368 which in turn causes global() at var.c:177/194 to set it
RDONLY.

This regression was introduced by
https://marc.info/?l=openbsd-tech&m=121613951723808 and made it's way
into 4.4 as

        revision 1.28
        date: 2008/07/23 16:34:38;  author: jaredy;  state: Exp;  lines: +6 -1;
        fix stack abuse in the `time' commmand, using alloc()'d memory instead.

        reported by Thorsten Glaser, thanks.

        ok millert@, earlier version miod@

The following diff fixes `time for ...' by copying the identifier over
to the new stack if given.

regress/bin/ksh still passes on amd64, but I'll add a new one for this
once we have a final fix.

Feedback?

Index: syn.c
===================================================================
RCS file: /cvs/src/bin/ksh/syn.c,v
retrieving revision 1.38
diff -u -p -r1.38 syn.c
--- syn.c       30 Dec 2015 09:07:00 -0000      1.38
+++ syn.c       22 Apr 2018 02:17:33 -0000
@@ -365,9 +365,13 @@ get_command(int cf)
                syniocf &= ~(KEYWORD|ALIAS);
                t = pipeline(0);
                if (t) {
-                       t->str = alloc(2, ATEMP);
-                       t->str[0] = '\0'; /* TF_* flags */
-                       t->str[1] = '\0';
+                       if (t->str) {
+                               t->str = str_save(t->str, ATEMP);
+                       } else {
+                               t->str = alloc(2, ATEMP);
+                               t->str[0] = '\0'; /* TF_* flags */
+                               t->str[1] = '\0';
+                       }
                }
                t = block(TTIME, t, NULL, NULL);
                break;

Reply via email to