From 113ed667a8a7f9f04a94998b28d52e6eb01cc1f5 Mon Sep 17 00:00:00 2001 From: Dave Trudgian Date: Wed, 2 Feb 2022 11:57:43 -0600 Subject: [PATCH] interp: allow unsetting global vars from inside a function again In dc2e11e6cf "unset" of a global var inside a function was broken, as the special handling of "export" or "readonly" in function scope introduced in that commit also incorrectly captured "unset", calling "parent.Set" with the previous value. Tweak the logic so that "unset" is handled like it did before, which fixes the regression. Fixes #806 --- interp/interp_test.go | 4 ++++ interp/vars.go | 12 ++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/interp/interp_test.go b/interp/interp_test.go index 3f23fbdf1..e6fb35e90 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -2381,6 +2381,10 @@ set +o pipefail "x=after\nbefore\n", }, + // unset global from inside function + {"f() { unset foo; echo $foo; }; foo=bar; f", "\n"}, + {"f() { unset foo; }; foo=bar; f; echo $foo", "\n"}, + // name references {"declare -n foo=bar; bar=etc; [[ -R foo ]]", ""}, {"declare -n foo=bar; bar=etc; [ -R foo ]", ""}, diff --git a/interp/vars.go b/interp/vars.go index cce6eb79f..feda4285b 100644 --- a/interp/vars.go +++ b/interp/vars.go @@ -31,17 +31,21 @@ func (o *overlayEnviron) Get(name string) expand.Variable { } func (o *overlayEnviron) Set(name string, vr expand.Variable) error { - // "foo=bar" in a function updates the global scope, unless the variable - // has been declared as local. + // Manipulation of a global var inside a function if o.funcScope && !vr.Local && !o.values[name].Local { + // "foo=bar" on a global var in a function updates the global scope + if vr.IsSet() { + return o.parent.(expand.WriteEnviron).Set(name, vr) + } // "foo=bar" followed by "export foo" or "readonly foo" - if !vr.IsSet() { + if vr.Exported || vr.ReadOnly { prev := o.Get(name) prev.Exported = prev.Exported || vr.Exported prev.ReadOnly = prev.ReadOnly || vr.ReadOnly vr = prev + return o.parent.(expand.WriteEnviron).Set(name, vr) } - return o.parent.(expand.WriteEnviron).Set(name, vr) + // "unset" is handled below } prev := o.Get(name)