| From https://ftp.gnu.org/gnu/bash/bash-5.0-patches/bash50-010 |
| |
| Signed-off-by: Pascal de Bruijn <p.debruijn@unilogic.nl> |
| |
| BASH PATCH REPORT |
| ================= |
| |
| Bash-Release: 5.0 |
| Patch-ID: bash50-010 |
| |
| Bug-Reported-by: Thorsten Glaser <tg@mirbsd.de> |
| Bug-Reference-ID: <156622962831.19438.16374961114836556294.reportbug@tglase.lan.tarent.de> |
| Bug-Reference-URL: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=935115 |
| |
| Bug-Description: |
| |
| Bash-5.0 changed the way assignment statements preceding special builtins |
| and shell functions were handled in posix mode. They automatically created |
| or modified global variables instead of modifying existing local variables |
| as in bash-4.4. |
| |
| The bash-4.4 posix-mode semantics were buggy, and resulted in creating |
| local variables where they were not intended and modifying global variables |
| and local variables simultaneously. |
| |
| The bash-5.0 changes were intended to fix this issue, but did not preserve |
| enough backwards compatibility. The posix standard also changed what it |
| required in these cases, so bash-5.0 is not bound by the strict conformance |
| requirements that existed in previous issues of the standard. |
| |
| This patch modifies the bash-5.0 posix mode behavior in an effort to restore |
| some backwards compatibility and rationalize the behavior in the presence of |
| local variables. It |
| |
| 1. Changes the assignment semantics to be more similar to standalone assignment |
| statements: assignments preceding a function call or special builtin while |
| executing in a shell function will modify the value of a local variable |
| with the same name for the duration of the function's execution; |
| |
| 2. Changes assignments preceding shell function calls or special builtins |
| from within a shell function to no longer create or modify global variables |
| in the presence of a local variable with the same name; |
| |
| 3. Assignment statements preceding a shell function call or special builtin |
| at the global scope continue to modify the (global) calling environment, |
| but are unaffected by assignments preceding function calls or special |
| builtins within a function, as described in item 2. This is also similar |
| to the behavior of a standalone assignment statement. |
| |
| Patch (apply with `patch -p0'): |
| |
| *** ../bash-5.0-patched/variables.c 2018-12-18 11:07:21.000000000 -0500 |
| --- b/variables.c 2019-08-22 10:53:44.000000000 -0400 |
| *************** |
| *** 4461,4467 **** |
| |
| /* Take a variable from an assignment statement preceding a posix special |
| ! builtin (including `return') and create a global variable from it. This |
| ! is called from merge_temporary_env, which is only called when in posix |
| ! mode. */ |
| static void |
| push_posix_temp_var (data) |
| --- 4461,4467 ---- |
| |
| /* Take a variable from an assignment statement preceding a posix special |
| ! builtin (including `return') and create a variable from it as if a |
| ! standalone assignment statement had been performed. This is called from |
| ! merge_temporary_env, which is only called when in posix mode. */ |
| static void |
| push_posix_temp_var (data) |
| *************** |
| *** 4473,4486 **** |
| var = (SHELL_VAR *)data; |
| |
| ! binding_table = global_variables->table; |
| ! if (binding_table == 0) |
| ! binding_table = global_variables->table = hash_create (VARIABLES_HASH_BUCKETS); |
| ! |
| ! v = bind_variable_internal (var->name, value_cell (var), binding_table, 0, ASS_FORCE|ASS_NOLONGJMP); |
| |
| /* global variables are no longer temporary and don't need propagating. */ |
| ! var->attributes &= ~(att_tempvar|att_propagate); |
| if (v) |
| ! v->attributes |= var->attributes; |
| |
| if (find_special_var (var->name) >= 0) |
| --- 4473,4497 ---- |
| var = (SHELL_VAR *)data; |
| |
| ! /* Just like do_assignment_internal(). This makes assignments preceding |
| ! special builtins act like standalone assignment statements when in |
| ! posix mode, satisfying the posix requirement that this affect the |
| ! "current execution environment." */ |
| ! v = bind_variable (var->name, value_cell (var), ASS_FORCE|ASS_NOLONGJMP); |
| ! |
| ! /* If this modifies an existing local variable, v->context will be non-zero. |
| ! If it comes back with v->context == 0, we bound at the global context. |
| ! Set binding_table appropriately. It doesn't matter whether it's correct |
| ! if the variable is local, only that it's not global_variables->table */ |
| ! binding_table = v->context ? shell_variables->table : global_variables->table; |
| |
| /* global variables are no longer temporary and don't need propagating. */ |
| ! if (binding_table == global_variables->table) |
| ! var->attributes &= ~(att_tempvar|att_propagate); |
| ! |
| if (v) |
| ! { |
| ! v->attributes |= var->attributes; |
| ! v->attributes &= ~att_tempvar; /* not a temp var now */ |
| ! } |
| |
| if (find_special_var (var->name) >= 0) |
| *************** |
| *** 4576,4587 **** |
| { |
| int i; |
| |
| tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); |
| tempvar_list[tvlist_ind = 0] = 0; |
| ! |
| ! hash_flush (temporary_env, pushf); |
| ! hash_dispose (temporary_env); |
| temporary_env = (HASH_TABLE *)NULL; |
| |
| tempvar_list[tvlist_ind] = 0; |
| |
| --- 4587,4601 ---- |
| { |
| int i; |
| + HASH_TABLE *disposer; |
| |
| tempvar_list = strvec_create (HASH_ENTRIES (temporary_env) + 1); |
| tempvar_list[tvlist_ind = 0] = 0; |
| ! |
| ! disposer = temporary_env; |
| temporary_env = (HASH_TABLE *)NULL; |
| |
| + hash_flush (disposer, pushf); |
| + hash_dispose (disposer); |
| + |
| tempvar_list[tvlist_ind] = 0; |
| |
| *** ../bash-5.0-patched/tests/varenv.right 2018-12-17 15:39:48.000000000 -0500 |
| --- b/tests/varenv.right 2019-08-22 16:05:25.000000000 -0400 |
| *************** |
| *** 147,153 **** |
| outside: declare -- var="one" |
| inside: declare -x var="value" |
| ! outside: declare -x var="value" |
| ! inside: declare -- var="local" |
| ! outside: declare -x var="global" |
| foo=<unset> environment foo= |
| foo=foo environment foo=foo |
| --- 147,153 ---- |
| outside: declare -- var="one" |
| inside: declare -x var="value" |
| ! outside: declare -- var="outside" |
| ! inside: declare -x var="global" |
| ! outside: declare -- var="outside" |
| foo=<unset> environment foo= |
| foo=foo environment foo=foo |
| *** ../bash-5.0/patchlevel.h 2016-06-22 14:51:03.000000000 -0400 |
| --- b/patchlevel.h 2016-10-01 11:01:28.000000000 -0400 |
| *************** |
| *** 26,30 **** |
| looks for to find the patch level (for the sccs version string). */ |
| |
| ! #define PATCHLEVEL 9 |
| |
| #endif /* _PATCHLEVEL_H_ */ |
| --- 26,30 ---- |
| looks for to find the patch level (for the sccs version string). */ |
| |
| ! #define PATCHLEVEL 10 |
| |
| #endif /* _PATCHLEVEL_H_ */ |