- [The]
putenv(char *string);
[…]这个电话似乎有致命的缺陷.
是的,它有致命的缺陷 它被保存在POSIX(1988)中,因为这是现有技术.setenv()
机制随后抵达 Correction: POSIX 1990标准在§B.4.6.1中规定"考虑了附加功能putenv()和clearenv(),但被拒绝".1997年的Single Unix Specification(SUS)版本2列出了putenv()
个,但没有列出setenv()
或unsetenv()
个.下一次修订(2004年)也对setenv()
和unsetenv()
进行了定义.
因为它不复制传递的字符串,所以不能用本地调用它,也不能保证堆分配的字符串不会被覆盖或意外删除.
你是对的,一个局部变量几乎总是一个错误的 Select ,传递到putenv()
-例外是模糊的,几乎不存在.如果字符串是在堆上分配的(malloc()
等),则必须确保代码不会修改它.如果是这样的话,它就是在同时修改环境.
此外(尽管我还没有测试过),因为环境变量的一个用途是将值传递给子元素的环境,如果子元素调用exec*()
个函数中的一个,这似乎是无用的.我说错了吗?
exec*()
个函数制作环境的副本,并将其传递给已执行的进程.没问题.
Linux手册页表明glibc 2.0-2.1.1放弃了上述行为,开始复制字符串,但这导致了内存泄漏,glibc 2.1.2修复了该漏洞.我不清楚这个内存泄漏是什么,也不清楚它是如何修复的.
内存泄漏是因为一旦你用一个字符串调用了putenv()
,你就不能再将该字符串用于任何目的,因为你无法判断它是否仍在使用中,尽管可以通过覆盖来修改该值(如果将名称更改为环境中另一个位置的环境变量的名称,则结果不确定).所以,如果你已经分配了空间,如果你再次改变变量,classic 的putenv()
就会泄露它.当putenv()
开始复制数据时,分配的变量变得不被引用,因为putenv()
不再保留对参数的引用,但用户预期环境会引用它,因此内存泄漏.我不确定修复是什么——我有三分之四的人认为它会恢复到以前的行为.
setenv()
个复制了字符串,但我不知道它是如何工作的.当进程加载时,会为环境分配空间,但空间是固定的.
原有的环境空间是固定的;当你开始修改它时,规则就会改变.即使使用putenv()
,原始环境也会被修改,并且可能会因为添加新变量或更改现有变量以获得更长的值而增长.
有没有(武断的?)大会在这里工作?例如,在env字符串指针数组中分配比当前使用的更多的插槽,并根据需要向下移动空终止指针?
这就是setenv()
机制可能会做的事情.(全局)变量environ
指向指向环境变量的指针数组的开头.如果它一次指向一个内存块,另一次指向另一个内存块,那么环境就会切换,就像那样.
新(复制)字符串的内存是否分配在环境本身的地址空间中,如果太大而无法容纳,则只需获取ENOMEM?
嗯,是的,你可以得到ENOMEM,但你必须非常努力.如果环境增长过大,可能无法正确执行其他程序——要么环境被截断,要么执行操作失败.
考虑到上述问题,有没有理由 Select putenv()而不是setenv()?
- 在新代码中使用
setenv()
.
- 将旧代码更新为
setenv()
,但不要将其作为首要任务.
- 不要在新代码中使用
putenv()
.