我一直在思考一些环境变量,并提出了一些问题/观察结果.

  • putenv(char *string);

    这个电话似乎有致命的缺陷.因为它不复制传递的字符串,所以不能用本地调用它,也不能保证堆分配的字符串不会被覆盖或意外删除.此外(尽管我还没有测试过),因为环境变量的一个用途是将值传递给子元素的环境,如果子元素调用exec*()个函数中的一个,这似乎是无用的.我说错了吗?

  • Linux手册页表明glibc 2.0-2.1.1放弃了上述行为,开始复制字符串,但这导致了内存泄漏,glibc 2.1.2修复了该漏洞.我不清楚这个内存泄漏是什么,也不清楚它是如何修复的.

  • setenv()个复制了字符串,但我不知道它是如何工作的.当进程加载时,会为环境分配空间,但空间是固定的.有没有(武断的?)大会在这里工作?例如,在env字符串指针数组中分配比当前使用的更多的插槽,并根据需要向下移动空终止指针?新(复制)字符串的内存是否分配在环境本身的地址空间中,如果太大而无法容纳,则只需获取ENOMEM?

  • 考虑到上述问题,有没有理由 Select putenv()而不是setenv()

推荐答案

  • [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().

Linux相关问答推荐

使用sed或awk映射自定义和任意函数

X86_64程序集中的分段故障:系统调用问题

在 Rust 中重命名主线程

使用正则表达式捕获特定字符串

Google Cloud Ops Agent Mongo 集成错误 - AuthenticationFailed:SCRAM 身份验证失败,storedKey 不匹配

如何在linux中将2个不同大小的图像(边框,实际图像)合并为1个

如何在 Linux 上捕获原始 HID 输入?

Linux time 命令输出中 real、user 和 sys 的含义

为什么 perf 不报告缓存未命中?

如何在 linux 上为 JNI 应用程序编译动态库?

为什么 Linux (x86) 的页面大小是 4 KB,这是如何计算的?

在 Bash 中识别接收到的信号名称

yum 可以告诉我哪些存储库提供了特定的包吗?

Linux:在目录下的文件列表中搜索特定单词

从Linux中的行尾删除空格

如何删除 Mercurial 存储库

使远程目录保持最新

何时使用管道与何时使用共享内存

从线程内Forking 是否安全?

如何使用cp从不同目录复制多个文件?