Skip to content

Commit

Permalink
interp: fix variables scope in functions
Browse files Browse the repository at this point in the history
Variables declared as exported or readonly in functions
without assignment are not correctly propagated to the
global scope, this snippet should return a `bar: readonly variable`
error:

```
_foo() {
    bar=foo
    readonly bar
}

_foo
bar=bar
```

This snippet should also export `bar` variable correctly:

```
_foo() {
    export bar
}

_foo
bar=foo
env | grep ^bar=
```
  • Loading branch information
cclerget authored and mvdan committed Nov 21, 2021
1 parent 308418e commit 1eb295c
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 1 deletion.
16 changes: 16 additions & 0 deletions interp/interp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2303,6 +2303,10 @@ set +o pipefail
{"export foo=(1 2); $ENV_PROG | grep '^foo='", "exit status 1"},
{"declare -A foo=([a]=b); export foo; $ENV_PROG | grep '^foo='", "exit status 1"},
{"export foo=(b c); foo=x; $ENV_PROG | grep '^foo='", "exit status 1"},
{"foo() { bar=foo; export bar; }; foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
{"foo() { export bar; }; bar=foo; foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
{"foo() { export bar; }; foo; bar=foo; $ENV_PROG | grep ^bar=", "bar=foo\n"},
{"foo() { export bar=foo; }; foo; readonly bar; $ENV_PROG | grep ^bar=", "bar=foo\n"},

// local
{
Expand Down Expand Up @@ -2430,6 +2434,18 @@ set +o pipefail
"readonly foo=bar; foo=etc",
"foo: readonly variable\nexit status 1 #JUSTERR",
},
{
"foo() { bar=foo; readonly bar; }; foo; bar=bar",
"bar: readonly variable\nexit status 1 #JUSTERR",
},
{
"foo() { readonly bar; }; foo; bar=foo",
"bar: readonly variable\nexit status 1 #JUSTERR",
},
{
"foo() { readonly bar=foo; }; foo; export bar; $ENV_PROG | grep '^bar='",
"bar=foo\n",
},

// multiple var modes at once
{
Expand Down
12 changes: 11 additions & 1 deletion interp/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,14 @@ 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.
if o.funcScope && vr.IsSet() && !vr.Local && !o.values[name].Local {
if o.funcScope && !vr.Local && !o.values[name].Local {
// "foo=bar" followed by "export foo" or "readonly foo"
if !vr.IsSet() {
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)
}

Expand Down Expand Up @@ -64,6 +71,9 @@ func (o *overlayEnviron) Set(name string, vr expand.Variable) error {
writeEnv.Set(name, vr)
return nil
}
} else if prev.Exported {
// variable is set and was marked as exported
vr.Exported = true
}
// modifying the entire variable
vr.Local = prev.Local || vr.Local
Expand Down

0 comments on commit 1eb295c

Please sign in to comment.