5

I've read several posts here and still confused about how setenv() works:

My understanding is that environment variables are stored as a bunch of "foo=bar\0" strings continuously at the bottom of the user stack, and then there is an array envp[] of pointers which point to these strings, also close to the bottom of the user stack. The user stack grows on top of these bytes, meaning it is non-trivial to add more stuff to the string area or the pointer array. So how does setenv() work if a new variable is set(need to add an element to envp[]), or a variable is changed but the new value string is longer than the old one(making in-place modification impossible), without shifting (almost) the whole user stack to make room for newcomers?

A somewhat related question is, does bash keep an internal list of locally set variables, and when user export the locally set variable, bash simply removes it from this locally managed list, and add it into the above mentioned bottom of stack string area and insert its pointer to the pointer array envp[], so that its children processes automatically inherit the exported variables?

QnA
  • 901
  • 6
  • 19
  • 2
    It may start at that place in the stack but nothing prevents implementations from making a copy or moving it somewhere else. See for example this [setenv source code](https://code.woboq.org/userspace/glibc/stdlib/setenv.c.html#162) – kaylum Aug 20 '20 at 01:41
  • thanks, the example basically answered the first part of my question – QnA Aug 24 '20 at 18:01

1 Answers1

0

My understanding is that environment variables are stored as...

Your understanding is only partially correct. :smile:

...without shifting (almost) the whole user stack to make room for newcomers?

That would be impossible. Regardless of whether the language the program was written in was C or the operating-system was UNIX. For example, because pointers on the stack can refer to other locations on the stack.

The first thing to note is that where the env vars are stored in a new process is architecture dependent. Most UNIX implementations, on most CPU architectures, store it on the stack as you described. But there is literally nothing in the C specification that mandates that solution. Also, If you modify the environment the implementation is free to copy the block of existing environment vars to a new location in memory. The C implementation is free to move the block of env vars and update the magic __environ var.

A somewhat related question is, does bash keep an internal list of locally set variables....

Not in the manner you describe. It does keep an "internal list" of locally set variables. But it does not use it the manner you suggest.

I'm curious what prompted you to open this issue

Kurtis Rader
  • 5,764
  • 10
  • 16
  • thanks, can you elaborate a bit on the bash manage exported/non-exported env variables then? My guess is that one list for exported vars, and one list for everything else, including shell functions etc. – QnA Aug 24 '20 at 18:04