From 555af37616893160ad1afb208a957d6a01a7a315 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Wed, 5 May 2021 16:23:06 -0700 Subject: [PATCH] Disallow escaped characters in variable expansion Prior to this fix, an escaped character like \x41 (hex for ascii A) was interpreted the same was as A, so that $\x41 would be the same as $A. Fix this by inserting an INTERNAL_SEPARATOR before these escapes, so that we no longer treat it as part of the variable name. This also affects brackets; don't treat echo $foo\1331\135 the same as echo $foo[1]. Fixes #7969 --- CHANGELOG.rst | 1 + src/common.cpp | 5 ++++- tests/checks/slices.fish | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2076c68b4..4c90fbd3a 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,7 @@ Notable improvements and fixes Syntax changes and new commands ------------------------------- +- Escaped characters like ``\x41`` are no longer valid in a variable name (:issue:`7969`). Deprecations and removed features --------------------------------- diff --git a/src/common.cpp b/src/common.cpp index 964224bfe..44271ee0b 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -1155,7 +1155,7 @@ static maybe_t string_last_char(const wcstring &str) { } /// Given a null terminated string starting with a backslash, read the escape as if it is unquoted, -/// appending to result. Return the number of characters consumed, or 0 on error. +/// appending to result. Return the number of characters consumed, or none on error. maybe_t read_unquoted_escape(const wchar_t *input, wcstring *result, bool allow_incomplete, bool unescape_special) { assert(input[0] == L'\\' && "Not an escape"); @@ -1244,6 +1244,9 @@ maybe_t read_unquoted_escape(const wchar_t *input, wcstring *result, boo } if (res <= max_val) { + // Prepend internal sep so this does not get treated as part of a variable. + // See #7969. + if (unescape_special) result->push_back(INTERNAL_SEPARATOR); result_char_or_none = static_cast((byte_literal ? ENCODE_DIRECT_BASE : 0) + res); } else { diff --git a/tests/checks/slices.fish b/tests/checks/slices.fish index 44b25870b..5f1a29c47 100644 --- a/tests/checks/slices.fish +++ b/tests/checks/slices.fish @@ -78,3 +78,17 @@ echo $list # CHECK: 2 1 3 set -l list 1 2 3 set list[2..] $list[-1..2] echo $list # CHECK: 1 3 2 + +# Regression test for #7969. +set fo shorty +set foo A B C +echo $foo[1] +# CHECK: A +echo $foo\1331\135 +# CHECK: A[1] B[1] C[1] +echo $foo\x5b1\x5d +# CHECK: A[1] B[1] C[1] +echo $foo\1331\135 +# CHECK: A[1] B[1] C[1] +echo $fo\157 +# CHECK: shortyo