putenv()/setenv() 如何在不移动整个用户堆栈的情况下工作?

QnA*_*QnA 5 c linux process environment-variables linux-kernel

我在这里阅读了几篇文章,但仍然对如何setenv()工作感到困惑:

我的理解是,环境变量作为一堆“foo=bar\0”字符串连续存储在用户堆栈的底部,然后有一个envp[]指向这些字符串的指针数组,也靠近堆栈的底部用户堆栈。用户堆栈在这些字节之上增长,这意味着向字符串区域或指针数组添加更多内容并不简单。setenv()那么,如果设置了新变量(需要添加一个元素envp[]),或者更改了变量但新值字符串比旧值字符串长(使得就地修改不可能),而不需要(几乎)移动变量,那么如何工作?整个用户堆栈为新人腾出空间?

一个有点相关的问题是,是否bash保留本地设置变量的内部列表,并且当用户使用export本地设置变量时,bash只需将其从本地管理列表中删除,并将其添加到上述堆栈字符串区域的底部并将其指针插入到指针数组envp[],以便其子进程自动继承导出的变量?

Kur*_*der 0

我的理解是环境变量存储为...

您的理解仅部分正确。:微笑:

...无需转移(几乎)整个用户堆栈来为新用户腾出空间?

那是不可能的。无论程序编写的语言是 C 还是操作系统是 UNIX。例如,因为堆栈上的指针可以引用堆栈上的其他位置。

首先要注意的是,环境变量存储在新进程中的位置取决于体系结构。大多数 UNIX 实现(在大多数 CPU 架构上)都将其存储在堆栈中,如您所描述的。但 C 规范中实际上并没有强制要求该解决方案。此外,如果修改环境,实现可以自由地将现有环境变量块复制到内存中的新位置。C 实现可以自由移动环境变量块并更新魔法__environ变量。

一个有点相关的问题是,bash 是否保留本地设置变量的内部列表......

不是按照你描述的方式。它确实保留了本地设置变量的“内部列表”。但它不会按照您建议的方式使用它。

我很好奇是什么促使你打开这个问题