From 6a4972069fd9c338e53c6cae48be9d732e37dab4 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Thu, 11 Jun 2020 17:14:31 +0200 Subject: [PATCH] Fix BUG_CASELIT: pattern matching as literal string in 'case' This fixes an undocumented 'case' pattern matching misbehaviour (labelled BUG_CASELIT in modernish) that goes back to the original Bourne shell, but wasn't discovered until 2018. If a pattern doesn't match as a pattern, it's tried again as a literal string. This breaks common validation use cases, such as: n='[0-9]' case $n in ( [0-9] ) echo "$n is a number" ;; esac would output "[0-9] is a number" as the literal string fallback matches the pattern. As this misbehaviour was never documented anywhere (not for Bourne, ksh88, or ksh93), and it was never replicated in other shells (not even in ksh88 clones pdksh and mksh), it is unlikely any scripts rely on it. Of course, a literal string fallback, should it be needed, is trivial to implement correctly without this breakage: case $n in ( [0-9] | "[0-9]") echo "$n is a number or the number pattern" ;; esac src/cmd/ksh93/sh/xec.c: - Remove trim_eq() function responsible for implementing the misbehaviour described above. NEWS: - Added. Document this bugfix. Ref.: - The problem: thread starting at https://www.mail-archive.com/austin-group-l@opengroup.org/msg02127.html - The solution, thanks to George Koehler: comments/commits in https://github.com/att/ast/issues/476 - Modernish BUG_CASELIT bug test & documentation: https://github.com/modernish/modernish/commit/b2024ae3 (cherry picked from commit 8d6c8ce69884767a160c1e20049e77bdd849c248 with some extra edits to NEWS to upate the info for this reboot) --- NEWS | 25 +++++++++++++++++++++++++ src/cmd/ksh93/sh/xec.c | 22 +--------------------- 2 files changed, 26 insertions(+), 21 deletions(-) create mode 100644 NEWS diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..1280b3977 --- /dev/null +++ b/NEWS @@ -0,0 +1,25 @@ +This documents significant changes in the 93u+m branch of AT&T ksh93. +For full details, see the git log at: + https://github.com/modernish/ksh + +Any uppercase BUG_* names are modernish shell bug IDs. + +2020-05-13: + +- Fix BUG_CASELIT: an undocumented 'case' pattern matching misbehaviour that + goes back to the original Bourne shell, but wasn't discovered until 2018. + If a pattern doesn't match as a pattern, it was tried again as a literal + string. This broke common validation use cases, e.g.: + n='[0-9]' + case $n in + ( [0-9] ) echo "$n is a number" ;; + esac + would output "[0-9] is a number" as the literal string fallback matches the + pattern. As this misbehaviour was never documented anywhere (not for Bourne, + ksh88, or ksh93), and it was never replicated in other shells (not even in + ksh88 clones pdksh and mksh), it is unlikely any scripts rely on it. + Of course, a literal string fallback, should it be needed, is trivial to + implement correctly without this breakage: + case $n in + ( [0-9] | "[0-9]") echo "$n is a number or the number pattern" ;; + esac diff --git a/src/cmd/ksh93/sh/xec.c b/src/cmd/ksh93/sh/xec.c index c370477ad..9718266c0 100644 --- a/src/cmd/ksh93/sh/xec.c +++ b/src/cmd/ksh93/sh/xec.c @@ -65,7 +65,6 @@ #endif /* SHOPT_SPAWN */ static void sh_funct(Shell_t *,Namval_t*, int, char*[], struct argnod*,int); -static int trim_eq(const char*, const char*); static void coproc_init(Shell_t*, int pipes[]); static void *timeout; @@ -2556,8 +2555,7 @@ int sh_exec(register const Shnode_t *t, int flags) s = rex->argval; type = (rex->argflag&ARG_RAW); if((type && strcmp(r,s)==0) || - (!type && (strmatch(r,s) - || trim_eq(r,s)))) + (!type && strmatch(r,s))) { do sh_exec(t->reg.regcom,(t->reg.regflag?(flags&sh_state(SH_ERREXIT)):flags)); while(t->reg.regflag && @@ -2983,24 +2981,6 @@ int sh_run(int argn, char *argv[]) return(argn); } -/* - * test for equality with second argument trimmed - * returns 1 if r == trim(s) otherwise 0 - */ - -static int trim_eq(register const char *r,register const char *s) -{ - register char c; - while(c = *s++) - { - if(c=='\\') - c = *s++; - if(c && c != *r++) - return(0); - } - return(*r==0); -} - /* * print out the command line if set -x is on */