From cbc90272abfeb864f50a0f27be73de85d09ace90 Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Mon, 12 Feb 2024 05:00:16 +0000 Subject: [PATCH] Fix unset non-namespace funct. from within namespace (re: dbccda10) The referenced commit more or less accidentally worked because it set 'name' to the namespace-prefixed function name, which then triggered the code at the bottom of unall() to set a dummy node in the virtual subshell. However, this also bypassed the lookup for the non-namespaced name, which made it impossible to unset a function defined outside a namespace from within the namespace. src/cmd/ksh93/bltins/typeset.c: unall(): - When prefixing the namespace name, use a local 'nsname' for the prefixed name and do not change 'name'. This fixes the bug, but on its own this fix would also reintroduce the subshell bug. - To avoid that, add code to set a dummy node in a virtual subshell for a namespace function. If that is done, simply return, because nothing else needs doing now. --- NEWS | 3 +++ src/cmd/ksh93/bltins/typeset.c | 21 +++++++++++++++------ src/cmd/ksh93/tests/namespace.sh | 12 ++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) diff --git a/NEWS b/NEWS index a3e605c02176..d7e3364ea64b 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,9 @@ Uppercase BUG_* IDs are shell bug IDs as used by the Modernish shell library. behaviour of the system's external printf(1) determines whether this is compiled in or out by default. Normal ksh printf options keep working. +- Fixed a bug, introduced on 2023-06-02, that made it impossible within a + namespace to unset a function defined outside the namespace. + 2024-02-09: - Fixed multiple inaccurate or missing values in the /opt/ast/bin/getconf diff --git a/src/cmd/ksh93/bltins/typeset.c b/src/cmd/ksh93/bltins/typeset.c index 2c8bfed8e99f..22932cf3bcf2 100644 --- a/src/cmd/ksh93/bltins/typeset.c +++ b/src/cmd/ksh93/bltins/typeset.c @@ -1352,13 +1352,22 @@ static int unall(int argc, char **argv, Dt_t *troot) if(jmpval==0) { #if SHOPT_NAMESPACE - if(sh.namespace && troot==sh.fun_tree && *name!='.') + if(sh.namespace && troot==sh.fun_tree && !sh.prefix && *name!='.') { + char *nsname; + Namval_t *np2; /* prefix the namespace name */ - sfputr(sh.stk,nv_name(sh.namespace),'.'); - sfputr(sh.stk,name,'\0'); - name = stkfreeze(sh.stk,0); + sfputr(sh.strbuf,nv_name(sh.namespace),'.'); + sfputr(sh.strbuf,name,'\0'); + nsname = sfstruse(sh.strbuf); + np = nv_search(nsname,troot,NV_NOSCOPE); + if(troot!=sh.fun_base && !np && (np2=nv_search(nsname,troot,0)) && is_afunction(np2)) + { /* create dummy virtual subshell node without NV_FUNCTION attribute */ + nv_open(nsname,troot,NV_NOSCOPE); + return r; + } } + if(!np) #endif /* SHOPT_NAMESPACE */ np=nv_open(name,troot,NV_NOADD|nflag); } @@ -1421,8 +1430,8 @@ static int unall(int argc, char **argv, Dt_t *troot) } else if(troot==sh.alias_tree) r = 1; - else if(troot==sh.fun_tree && troot!=sh.fun_base && (np=nv_search(name,sh.fun_tree,0)) && is_afunction(np)) - nv_open(name,troot,NV_NOSCOPE); /* create dummy virtual subshell node without NV_FUNCTION attribute */ + else if(troot==sh.fun_tree && troot!=sh.fun_base && !np && (np=nv_search(name,troot,0)) && is_afunction(np)) + nv_open(name,troot,NV_NOSCOPE); /* create dummy virtual subshell node without NV_FUNCTION attribute */ } return r; } diff --git a/src/cmd/ksh93/tests/namespace.sh b/src/cmd/ksh93/tests/namespace.sh index 9e9c292449bd..17d6e22dd1bb 100755 --- a/src/cmd/ksh93/tests/namespace.sh +++ b/src/cmd/ksh93/tests/namespace.sh @@ -210,6 +210,18 @@ do [[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (1b)" \ "(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))" + # bug introduced on 2023-06-02 + got=$( + eval "$b() { echo BAD; }" + namespace ns + { + (unset -f "$b"; PATH=/dev/null; "$b" --version 2>&1) + exit # avoid optimizing out the subshell + } + ) + [[ e=$? -eq 2 && $got =~ $exp ]] || err_exit "'unset -f $b' fails in subshell (1c)" \ + "(expected status 2 and ERE match of $(printf %q "$exp"), got status $e and $(printf %q "$got"))" + got=$( namespace ns {