ash : fix double-quoted "\z" handling
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 13 Feb 2018 13:43:29 +0000 (14:43 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 13 Feb 2018 13:44:11 +0000 (14:44 +0100)
function                                             old     new   delta
readtoken1                                          2602    2608      +6

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
shell/ash.c
shell/ash_test/ash-quoting/bkslash_case1.right [new file with mode: 0644]
shell/ash_test/ash-quoting/bkslash_case1.tests [new file with mode: 0755]
shell/hush_test/hush-quoting/bkslash_case1.right [new file with mode: 0644]
shell/hush_test/hush-quoting/bkslash_case1.tests [new file with mode: 0755]

index 4c1b5e409e5416b05a2591cebe4ed0a338ce8676..5e281b5ceee8d72fed8757e20830890c43a3bc66 100644 (file)
@@ -6146,12 +6146,12 @@ rmescapes(char *str, int flag, int *slash_position)
                                if (*p == '*'
                                 || *p == '?'
                                 || *p == '['
-                                || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */
-                                || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
-                                || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
-                                || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */
+                                || *p == '\\' /* case '\' in \\    ) echo ok;; *) echo WRONG;; esac */
+                                || *p == ']'  /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */
+                                || *p == '-'  /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */
+                                || *p == '!'  /* case '!' in [\!]  ) echo ok;; *) echo WRONG;; esac */
                                /* Some libc support [^negate], that's why "^" also needs love */
-                                || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */
+                                || *p == '^'  /* case '^' in [\^]  ) echo ok;; *) echo WRONG;; esac */
                                ) {
                                        *q++ = '\\';
                                }
@@ -11992,13 +11992,24 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
                                        USTPUTC(CTLESC, out);
                                        USTPUTC('\\', out);
                                }
-                               /* Backslash is retained if we are in "str" and next char isn't special */
+                               /* Backslash is retained if we are in "str"
+                                * and next char isn't dquote-special.
+                                */
                                if (dblquote
                                 && c != '\\'
                                 && c != '`'
                                 && c != '$'
                                 && (c != '"' || eofmark != NULL)
                                ) {
+//dash survives not doing USTPUTC(CTLESC), but merely by chance:
+//Example: "\z" gets encoded as "\<CTLESC>z".
+//rmescapes() then emits "\", "\z", protecting z from globbing.
+//But it's wrong, should protect _both_ from globbing:
+//everything in double quotes is not globbed.
+//Unlike dash, we have a fix in rmescapes() which emits bare "z"
+//for "<CTLESC>z" since "z" is not glob-special (else unicode may break),
+//and glob would see "\z" and eat "\". Thus:
+                                       USTPUTC(CTLESC, out); /* protect '\' from glob */
                                        USTPUTC('\\', out);
                                }
                                USTPUTC(CTLESC, out);
diff --git a/shell/ash_test/ash-quoting/bkslash_case1.right b/shell/ash_test/ash-quoting/bkslash_case1.right
new file mode 100644 (file)
index 0000000..1b52491
--- /dev/null
@@ -0,0 +1,10 @@
+ok1
+ok2
+ok3
+ok4
+ok5
+Ok:0
+ok6
+ok7
+ok8
+Ok:0
diff --git a/shell/ash_test/ash-quoting/bkslash_case1.tests b/shell/ash_test/ash-quoting/bkslash_case1.tests
new file mode 100755 (executable)
index 0000000..d0c3599
--- /dev/null
@@ -0,0 +1,38 @@
+# Case argument is globbed, match patterns are not.
+# This caught some bugs in the past.
+
+case z in
+\z  ) echo ok1 ;;
+*   ) echo BUG ;;
+esac
+case \z in
+z   ) echo ok2 ;;
+*   ) echo BUG ;;
+esac
+case \z in
+\z  ) echo ok3 ;;
+*   ) echo BUG ;;
+esac
+case z in
+\z  ) echo ok4 ;;
+*   ) echo BUG ;;
+esac
+case \\z in
+\\z ) echo ok5 ;;
+*   ) echo BUG ;;
+esac
+echo Ok:$?
+
+case "\z" in
+"\z"  ) echo ok6 ;;
+*     ) echo BUG ;;
+esac
+case "\\z" in
+"\\z" ) echo ok7 ;;
+*     ) echo BUG ;;
+esac
+case "\\\z" in
+"\\\z") echo ok8 ;;
+*     ) echo BUG ;;
+esac
+echo Ok:$?
diff --git a/shell/hush_test/hush-quoting/bkslash_case1.right b/shell/hush_test/hush-quoting/bkslash_case1.right
new file mode 100644 (file)
index 0000000..1b52491
--- /dev/null
@@ -0,0 +1,10 @@
+ok1
+ok2
+ok3
+ok4
+ok5
+Ok:0
+ok6
+ok7
+ok8
+Ok:0
diff --git a/shell/hush_test/hush-quoting/bkslash_case1.tests b/shell/hush_test/hush-quoting/bkslash_case1.tests
new file mode 100755 (executable)
index 0000000..d0c3599
--- /dev/null
@@ -0,0 +1,38 @@
+# Case argument is globbed, match patterns are not.
+# This caught some bugs in the past.
+
+case z in
+\z  ) echo ok1 ;;
+*   ) echo BUG ;;
+esac
+case \z in
+z   ) echo ok2 ;;
+*   ) echo BUG ;;
+esac
+case \z in
+\z  ) echo ok3 ;;
+*   ) echo BUG ;;
+esac
+case z in
+\z  ) echo ok4 ;;
+*   ) echo BUG ;;
+esac
+case \\z in
+\\z ) echo ok5 ;;
+*   ) echo BUG ;;
+esac
+echo Ok:$?
+
+case "\z" in
+"\z"  ) echo ok6 ;;
+*     ) echo BUG ;;
+esac
+case "\\z" in
+"\\z" ) echo ok7 ;;
+*     ) echo BUG ;;
+esac
+case "\\\z" in
+"\\\z") echo ok8 ;;
+*     ) echo BUG ;;
+esac
+echo Ok:$?