14

I get a suprising behaviour when I have a function local read-only variable and global read-only variable with the same name.

When read-only option is removed from global declaration. I.e.

declare -r var="main" 

is changed to:

declare var="main" 

I get the expected behaviour. I've been reading bash man page but I can't find an explanation to this behaviour. Could you please point me to the section(s) of the manual explaining the issue ?

I think this is a similar kind of issue than How does lexical scoping supported in different shell languages? but more specific.

Details:

$ cat readonly_variable.sh #!/bin/bash # expected output: # # BASH_VERSION = 3.2.25(1)-release # function # main # # but instead getting: # # BASH_VERSION = 3.2.25(1)-release # ./readonly_variable.sh: line 6: local: var: readonly variable # main # main # # when read-only option (-r) is removed from global declaration (*), the output # is expected set -o nounset function func { local -r var="function" echo "$var" } declare -r var="main" # (*) echo BASH_VERSION = $BASH_VERSION echo $(func) echo $var exit 0 

I'm stucked to this particular Bash version.

$ ./readonly_variable.sh BASH_VERSION = 3.2.25(1)-release ./readonly_variable.sh: line 24: local: var: readonly variable main main $ 
1
  • 4
    There's a recent discussion of this issue on the gnu.bash.bug mailing list. Commented Feb 18, 2011 at 16:39

1 Answer 1

12

Actually, making local copies of readonly global variables is explicitely forbidden for security reasons, as documented in bash source code (in variables.c:make_local_variable):

The test against old_var's context level is to disallow local copies of readonly global variables (since "I" believe that this could be a security hole).

(where "I" is not me, I'm merely quoting)

/* Since this is called only from the local/declare/typeset code, we can call builtin_error here without worry (of course, it will also work for anything that sets this_command_name). Variables with the `noassign' attribute may not be made local. The test against old_var's context level is to disallow local copies of readonly global variables (since I believe that this could be a security hole). Readonly copies of calling function local variables are OK. */ if (old_var && (noassign_p (old_var) || (readonly_p (old_var) && old_var->context == 0))) { if (readonly_p (old_var)) sh_readonly (name); return ((SHELL_VAR *)NULL); } 
Sign up to request clarification or add additional context in comments.

1 Comment

Not the first place where I would take a look for documentation.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.