有关putenv()函数和SETENV问题() [英] Questions about putenv() and setenv()

查看:315
本文介绍了有关putenv()函数和SETENV问题()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在思考一些关于环境变量有几个问题/意见。


  • 传给putenv(字符*字符串);

    这似乎调用致命的缺点。因为它不会复制传递的字符串,你不能用本地调用它并不能保证堆中分配的字符串不会被覆盖或意外删除。此外(虽然我没有测试过),因为一个使用环境变量是值传递给孩子的环境中,这似乎是无用的,如果孩子调用的exec *()的一个功能。我错在那?


  • Linux手册页指出的glibc 2.0-2.1.1放弃了上述行为,并开始复制字符串,但这个导致了固定在2.1.2 glibc的内存泄漏。目前还不清楚到我这是什么内存泄漏是和它是如何固定的。


  • SETENV()复制字符串,但我不知道究竟是如何工作的。对环境空间被分配的处理负荷时,但它是固定的。有没有在这里工作的一些(任意?)约定?例如,比目前使用的包膜字符串的指针阵列中分配更多时隙,并根据需要移动该空终止指针下来?在环境本身的地址空间分配给新(复制)字符串的内存,如果它太大,不适合你只能ENOMEM?


  • 考虑到上述问题,是没有任何理由preFER putenv()函数 SETENV()



解决方案

  

      
  • [中] 传给putenv(字符*字符串); [...]调用似乎有致命缺陷

  •   

是的,这是致命的缺陷。 这是在POSIX(1988)preserved因为这是现有技术。在 SETENV()机制后到达更正:的POSIX的1990标准说,在§B.4.6.1附加功能 putenv()函数的和的了clearenv()的被认为但他拒绝。该单一Unix规格(SUS)版本2在1997年列出了 putenv()函数而不是 SETENV() unsetenv()。下一个版本(2004)做了定义这两个 SETENV() unsetenv( ) 为好。


  

由于它不会复制传递的字符串,你不能用本地调用它并不能保证堆中分配的字符串不会被覆盖或意外删除。


你是正确的,一个局部变量几乎总是一个坏的选择传递给 putenv()函数 - 例外是晦涩的,几乎不存在的地步。如果字符串在堆上分配(以的malloc()等),你必须确保你的code不修改它。如果这样做,则在同一时间修改环境


  

另外(虽然我没有测试过),因为一个使用环境变量是值传递给孩子的环境中,这似乎是无用的,如果孩子调用的exec *()功能。我错在那?


EXEC *()功能使环境的副本,并传递到执行的过程。有没有的问题在那里。


  

Linux手册页指出的glibc 2.0-2.1.1放弃了上述行为,并开始复制字符串,但这个导致了固定在2.1.2 glibc的内存泄漏。目前还不清楚到我这是什么内存泄漏是和它是如何固定的。


内存泄漏的产生是因为一旦你叫 putenv()函数用字符串,则不能再次使用该字符串用于任何目的,因为你无法判断它是仍在使用,尽管你可以通过覆盖(与不确定的结果,如果你将名称更改为,在环境中的其他位置找到了一个环境变量)的修改值。所以,如果你已经分配的空间,经典的 putenv()函数如果再次改变变量泄漏了。当 putenv()函数开始复制数据时,分配的变量成为未被引用,因为 putenv()函数不再保持在一个参考的说法,但用户预期的环境会引用它,所以内存被泄露。我不知道什么定盘 - 我希望3/4是恢复到原来的行为


  

SETENV()复制字符串,但我不知道究竟是如何工作的。对环境的空间分配过程中加载时,但它是固定的。


原始环境空间是固定的;当你开始修改它,规则的改变。甚至与 putenv()函数,原来的环境被修改和可能增长如添加新的变量,或者作为改变现有的变量有较长的值的结果的结果。


  

有没有在这里工作的一些(任意?)约定?例如,比目前使用的包膜字符串的指针阵列中分配更多时隙,并根据需要移动该空终止指针向下


这是什么 SETENV()机制是有可能的事情。 (全局)变量 ENVIRON 指向指针数组环境变量的开始。如果指向在同一时间内存一个街区,在不同的时间不同的块,那么环境切换,就这样。


  

是在环境本身的地址空间分配的新(复制)字符串的内存,如果它太大,不适合你只能ENOMEM?


嗯,是的,你可以得到ENOMEM,但是你必须试图pretty努力。如果你成长环境的过大,则可能无法正确​​exec的其它程序 - 无论是环境将被截断或EXEC操作将失败


  

考虑到上述问题,是没有任何理由preFER putenv()函数在SETENV()?



  • 使用 SETENV()在新的code。

  • 更新旧code使用 SETENV(),但不要使之成为重中之重。

  • 请不要使用 putenv()函数在新的code。

I have been thinking a little about environment variables and have a few questions/observations.

  • putenv(char *string);

    This call seems fatally flawed. Because it doesn't copy the passed string you can't call it with a local and there is no guarantee a heap allocated string won't be overwritten or accidentally deleted. Furthermore (though I haven't tested it), since one use of environment variables is to pass values to child's environment this seems useless if the child calls one of the exec*() functions. Am I wrong in that?

  • The Linux man page indicates that glibc 2.0-2.1.1 abandoned the above behavior and began copying the string but this led to a memory leak that was fixed in glibc 2.1.2. It's not clear to me what this memory leak was or how it was fixed.

  • setenv() copies the string but I don't know exactly how that works. Space for the environment is allocated when the process loads but it is fixed. Is there some (arbitrary?) convention at work here? For example, allocating more slots in the env string pointer array than currently used and moving the null terminating pointer down as needed? Is the memory for the new (copied) string allocated in the address space of the environment itself and if it is too big to fit you just get ENOMEM?

  • Considering the above issues, is there any reason to prefer putenv() over setenv()?

解决方案

  • [The] putenv(char *string); [...] call seems fatally flawed.

Yes, it is fatally flawed. It was preserved in POSIX (1988) because that was the prior art. The setenv() mechanism arrived later. Correction: The POSIX 1990 standard says in §B.4.6.1 "Additional functions putenv() and clearenv() were considered but rejected". The Single Unix Specification (SUS) version 2 from 1997 lists putenv() but not setenv() or unsetenv(). The next revision (2004) did define both setenv() and unsetenv() as well.

Because it doesn't copy the passed string you can't call it with a local and there is no guarantee a heap allocated string won't be overwritten or accidentally deleted.

You're correct that a local variable is almost invariably a bad choice to pass to putenv() — the exceptions are obscure to the point of almost not existing. If the string is allocated on the heap (with malloc() et al), you must ensure that your code does not modify it. If it does, it is modifying the environment at the same time.

Furthermore (though I haven't tested it), since one use of environment variables is to pass values to child's environment this seems useless if the child calls one of the exec*() functions. Am I wrong in that?

The exec*() functions make a copy of the environment and pass that to the executed process. There's no problem there.

The Linux man page indicates that glibc 2.0-2.1.1 abandoned the above behavior and began copying the string but this led to a memory leak that was fixed in glibc 2.1.2. It's not clear to me what this memory leak was or how it was fixed.

The memory leak arises because once you have called putenv() with a string, you cannot use that string again for any purpose because you can't tell whether it is still in used, though you could modify the value by overwriting it (with indeterminate results if you change the name to that of an environment variable found at another position in the environment). So, if you have allocated space, the classic putenv() leaks it if you change the variable again. When putenv() began to copy data, allocated variables became unreferenced because putenv() no longer kept a reference to the argument, but the user expected that the environment would be referencing it, so the memory was leaked. I'm not sure what the fix was - I would 3/4 expect it was to revert to the old behaviour.

setenv() copies the string but I don't know exactly how that works. Space for the environment is allocated when the process loads but it is fixed.

The original environment space is fixed; when you start modifying it, the rules change. Even with putenv(), the original environment is modified and could grow as a result of adding new variables, or as a result of changing existing variables to have longer values.

Is there some (arbitrary?) convention at work here? For example, allocating more slots in the env string pointer array than currently used and moving the null terminating pointer down as needed?

That is what the setenv() mechanism is likely to do. The (global) variable environ points to the start of the array of pointers to environment variables. If it points to one block of memory at one time and a different block at a different time, then the environment is switched, just like that.

Is the memory for the new (copied) string allocated in the address space of the environment itself and if it is too big to fit you just get ENOMEM?

Well, yes, you could get ENOMEM, but you'd have to be trying pretty hard. And if you grow the environment too large, you may be unable to exec other programs properly - either the environment will be truncated or the exec operation will fail.

Considering the above issues, is there any reason to prefer putenv() over setenv()?

  • Use setenv() in new code.
  • Update old code to use setenv(), but don't make it a top priority.
  • Do not use putenv() in new code.

这篇关于有关putenv()函数和SETENV问题()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆