Correctly un-export an env var when it is shadowed

Prior to this fix, if you exported a variable in one scope
and then unexported it in the next, it would remain exported.
Example:

    set -gx VAR 1
    function foo; set -l VAR; env; end
    foo

Here 'VAR' would be exported to 'env' because we failed to
notice that the env var is shadowed by an unexported variable.
This occurred at env var computation time, not in env_set!

Fixes #2132
This commit is contained in:
ridiculousfish 2015-06-12 16:05:59 -07:00
parent b6b6de3304
commit ea407476d0
3 changed files with 24 additions and 5 deletions

19
env.cpp
View file

@ -1264,7 +1264,7 @@ wcstring_list_t env_get_names(int flags)
Get list of all exported variables Get list of all exported variables
*/ */
static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> &h) static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> *h)
{ {
if (!n) if (!n)
return; return;
@ -1279,10 +1279,19 @@ static void get_exported(const env_node_t *n, std::map<wcstring, wcstring> &h)
{ {
const wcstring &key = iter->first; const wcstring &key = iter->first;
const var_entry_t &val_entry = iter->second; const var_entry_t &val_entry = iter->second;
if (val_entry.exportv && (val_entry.val != ENV_NULL))
if (val_entry.exportv && val_entry.val != ENV_NULL)
{ {
// Don't use std::map::insert here, since we need to overwrite existing values from previous scopes // Export the variable
h[key] = val_entry.val; // Don't use std::map::insert here, since we need to overwrite existing
// values from previous scopes
(*h)[key] = val_entry.val;
}
else
{
// We need to erase from the map if we are not exporting,
// since a lower scope may have exported. See #2132
h->erase(key);
} }
} }
} }
@ -1333,7 +1342,7 @@ static void update_export_array_if_necessary(bool recalc)
debug(4, L"env_export_arr() recalc"); debug(4, L"env_export_arr() recalc");
get_exported(top, vals); get_exported(top, &vals);
if (uvars()) if (uvars())
{ {

View file

@ -227,6 +227,14 @@ else
echo Test 16 fail echo Test 16 fail
end end
# Test that shadowing with a non-exported variable works
set -gx __fish_test_env17 UNSHADOWED
env | sgrep __fish_test_env17
function __fish_test_shadow
set -l __fish_test_env17
env | sgrep __fish_test_env17 ; or echo SHADOWED
end
__fish_test_shadow
# clear for other shells # clear for other shells
set -eU __fish_test_universal_variables_variable_foo set -eU __fish_test_universal_variables_variable_foo

View file

@ -16,6 +16,8 @@ Test 15 pass
Foo change detected Foo change detected
Foo change detected Foo change detected
Test 16 pass Test 16 pass
__fish_test_env17=UNSHADOWED
SHADOWED
Testing Universal Startup Testing Universal Startup
1 1
1 1