环境变量值的最大大小是多少?


82

在Linux上的环境变量中可以存储的数据量是否有限制,如果可以,它是什么?

对于Windows,我发现以下知识库文章摘要如下:Windows XP或更高版本:8191个字符Windows 2000 / NT 4.0:2047个字符


Windows的实际限制为31,767。您了解了该set命令,该命令的命令行限制为8191个字符。 请参阅此msdn文章, 但是仍然是一个随机限制。
克里斯托弗·柯伦斯

5
8191并不是那么随机。是2 ^
13-1

AWS Lambda:[环境变量]集的总大小不超过4 KB(
Martin Thoma,

1
@BarnabyDawson克里斯托弗(Christopher)可能是故意的?
0xC0000022L

Answers:


74

我认为Linux上没有针对每个环境的变量限制。所有环境变量的总大小在一定execve()时间内受到限制。有关更多信息,请参见此处的“参数和环境大小的限制” 。

进程可能使用环境setenv()putenv()使环境超出exec分配的初始空间。

这是一个快速而肮脏的程序,它创建一个256 MB的环境变量。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
    size_t size = 1 << 28; /* 256 MB */
    char *var;

    var = malloc(size);
    if (var == NULL) {
        perror("malloc");
        return 1;
    }

    memset(var, 'X', size);
    var[size - 1] = '\0';
    var[0] = 'A';
    var[1] = '=';

    if (putenv(var) != 0) {
        perror("putenv");
        return 1;
    }

/*  Demonstrate E2BIG failure explained by paxdiablo */
    execl("/bin/true", "true", (char *)NULL);
    perror("execl");   


    printf("A=%s\n", getenv("A"));

    return 0;
}

5
+1获取execve()信息。您实际上可以添加(至少)8M的环境变量,但是exec()调用将无法工作。每当您尝试运行命令时,这都会在bash中显示为“参数列表太长”。
paxdiablo

1
还要注意的是POSIX要求ARG_MAX _POSIX_ARG_MAX,这应该是4096至至少
ninjalj

10
askUbuntu上的最高答案(由Chipaca讨论讨论了xargs --show-limits如何获取更多信息。
DocSalvager

我也看到每个arg字符串的限制-“此外,每个字符串的限制是32页(内核常量MAX_ARG_STRLEN)”
kiran01bm

23

好吧,我的盒子上至少有4M。那时,我感到无聊和徘徊。希望在我星期一恢复工作之前完成终端输出:-)

export b1=A
export b2=$b1$b1
export b4=$b2$b2
export b8=$b4$b4
export b16=$b8$b8
export b32=$b16$b16
export b64=$b32$b32
export b128=$b64$b64
export b256=$b128$b128
export b512=$b256$b256
export b1k=$b512$b512
export b2k=$b1k$b1k
export b4k=$b2k$b2k
export b8k=$b4k$b4k
export b16k=$b8k$b8k
export b32k=$b16k$b16k
export b64k=$b32k$b32k
export b128k=$b64k$b64k
export b256k=$b128k$b128k
export b512k=$b256k$b256k
export b1m=$b512k$b512k
export b2m=$b1m$b1m
export b4m=$b2m$b2m
echo $b4m
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
:    :    :    :    :    :    :    :    :    :    :    :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

如果您担心4M可能不足以容纳环境变量,那么您可能想重新考虑一下您的工作方式。

最好将信息放入文件中,然后使用环境变量来引用该文件。我见过这样的情况:如果变量具有形式@/path/to/any/fspec,则它将从文件中获取实际信息path/to/any/fspec。如果不是以开头@,它将使用环境变量本身的值。


有趣的是,设置了所有这些变量后,每个命令都会开始抱怨参数列表太长,因此即使可以设置参数列表,也可能无法在完成后启动程序(因为它必须将环境传递给这些程序)。


1
希望您使用了脚本,并且不要手工输入所有内容!
克里斯·黄·利弗

2
不,因此“无聊”。Vi-mode命令行编辑使操作变得简单一些,但我认为在达到4M标记之前它可能会失败。这就是生活。
paxdiablo,2009年


@LưuVĩnhPhúc:因为程序有限制。它们可以是任意限制,也可以基于可用资源,但是存在限制。DavidK很可能以为疯子应该不会误用他的
弹药

7

我使用以下代码段在Linux机器上进行了快速测试:

a="1"
while true
do
    a=$a$a
    echo "$(date) $(numfmt --to=iec-i --suffix=B --padding=7 ${#a})" 
done

在我的盒子(Gentoo 3.17.8-gentoo-r1)上,这导致(输出的最后几行):

Wed Jan  3 12:16:10 CET 2018   16MiB
Wed Jan  3 12:16:11 CET 2018   32MiB
Wed Jan  3 12:16:12 CET 2018   64MiB
Wed Jan  3 12:16:15 CET 2018  128MiB
Wed Jan  3 12:16:21 CET 2018  256MiB
Wed Jan  3 12:16:33 CET 2018  512MiB
xrealloc: cannot allocate 18446744071562068096 bytes

所以:极限很高!


1
18446744071562068096字节约为15艾字节。:)从512MiB看来似乎是一个巨大的飞跃。
马库斯

1
@Marcus:这是...我想某种程度上1Gb即1073741824字节即2 ^ 30字节在某处溢出。错误18446744071562068096中的字节数非常接近2 ^ 64,即18446744073709551616
cyberbird

1
我确实具有有限的C / gdb技能,但是我认为问题出在bash源文件subst.c中。函数sub_append_string(第726行)使用一个称为n的带符号int变量来计算新大小。新的大小(2 ^ 31)合适,但是有一个对齐计算:n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); 我怀疑零件: (n + DEFAULT_ARRAY_SIZE)溢出。一切都非常好,但我们是超越了任何理智的极限位置ofcourse方式..
cyberbird


1

不完全知道,但是快速实验显示没有错误发生,例如,值为64kB:

% perl -e 'print "#include <stdlib.h>\nint main() { return setenv(\"FOO\", \"", "x"x65536, "\", 1); }\n";'\
| gcc -x c -o envtest - && ./envtest && echo $?
0

1

我使用了这个非常快速和肮脏的php代码(如下),将其修改为不同的值,发现它适用于最大长度为128k的可变长度。在那之后,无论出于什么原因,它都不起作用。没有引发异常,没有错误报告,但是该值未显示在子外壳中。

也许这是特定于php的限制?也许有php.ini设置可能会影响它?也许子外壳继承的vars大小有限制?也许有相关的内核或外壳配置设置。

无论如何,默认情况下,在CentOS中,通过php中的putenv在环境中设置var的限制似乎约为128k。

<?php

  $s = 'abcdefghijklmnop';
  $s2 = "";
  for ($i = 0; $i < 8100; $i++) $s2 .= $s;
  $result = putenv('FOO='.$s2);
  print shell_exec('echo \'FOO: \'${FOO}');
  print "length of s2: ".strlen($s2)."\n";
  print "result = $result\n";
?>

版本信息 -

[root@localhost scratch]# php --version
PHP 5.2.6 (cli) (built: Dec  2 2008 16:32:08) 
<..snip..>

[root@localhost scratch]# uname -a
Linux localhost.localdomain 2.6.18-128.2.1.el5 #1 SMP Tue Jul 14 06:36:37 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost scratch]# cat /etc/redhat-release 
CentOS release 5.3 (Final)

0

命令行(带有所有参数)加上环境变量应小于128k。


11
需要引用
rr-
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.