【问题标题】:Can argc overflow?argc 会溢出吗?
【发布时间】:2015-03-20 10:49:15
【问题描述】:

我在 SO 中闲逛,看到了 this question。然后我开始怀疑我是否可以溢出argc。

标准规定argv[argc] 必须是一个空指针,但如果 argc 溢出,这将是错误的。

(我wrote一个小C程序和一个python脚本来测试它,但得到了一个MemoryError。)

谢谢!


Rationale for International Standard — Programming Languages — C §5.1.2.2.1 程序启动

argcargv 作为main 的参数的规范认可了广泛的先前实践。 argv[argc] 需要为空指针,以提供对列表末尾的冗余检查,也是根据惯例。

【问题讨论】:

  • Standard says that argv[argc] must be a null pointer but this will be false if argc overflow -- 我把它读作“不要让 argc 溢出”。 (“医生,我这样做会很痛”)
  • 在 POSIX 和大多数 Linux 系统上,main 的初始堆栈 - 由 execve- 安装,包括它的参数(即 argv),受到更多限制(通常,几兆字节)。所以argc 不到几百万,我从来没有听说过argc 可能接近INT_MAX 的操作系统
  • 可以说,在这种情况下,实现将具有系统特定的限制,无法将 2^15 个参数传递给程序
  • 好吧,我当然不会输入它们:)
  • 等一下,“我不会感到惊讶”是什么意思。任何 LP64 或 LLP64 架构都符合要求,因此 Windows 或 Linux。不过,您需要大量 RAM。我想如果从头开始,argc 应该有类型size_t

标签: c integer-overflow


【解决方案1】:

按标准

所以,从你的报价来看:

argv[argc] 必须是空指针

因此,argc 不能溢出,因为那样上面的说法就不成立了。

在实践中

实际上,传递给程序的参数的总大小是有限的。

在我的 Linux/x64 系统上:

$ getconf ARG_MAX 2097152

因此,总参数大小约为 2 兆字节,argc 不会溢出。我相信这个限制衡量了argv 中的总数据和环境的组合。如果您在尝试运行命令时超出此限制,exec() 将失败并显示E2BIG。来自man 2 execve

E2BIG 环境中的总字节数 (envp) 和参数 列表 (argv) 太大。

我相信与其他系统相比,我的系统的 ~2 兆字节限制相对宽松。我的 OS X 系统报告的限制为 ~260KB。

但是如果ARG_MAX 真的很大呢?

好的,假设您使用的是旧的/奇怪的系统,所以int 是 16 位,而 ARG_MAX 远远超过 215,否则这是相当合理的。现在,假设您使用超过 215 个参数调用 execve()。该实现有两个选项。

  1. 它可以允许argc 溢出...基本上,丢弃您的数据,确保您正在运行的程序以某种意外且可能错误的方式执行,并违反 C 标准。最糟糕的是,错误是无声的,所以你可能永远不会知道。

  2. 或者,它可以简单地从execve() 返回EOVERFLOW,通知您它根本无法运行具有这么多参数的图像。现在,POSIX / SUS 标准没有提及这个错误结果......但是,我怀疑这仅仅是因为标准作者从未期望ARG_MAX 大于INT_MAX

选项#2 是唯一合理的选项。如果您的系统以某种方式选择了选项 #1,那么它已损坏,您应该提交错误报告。

或者,您可以尝试运行为 16 位系统编译的旧程序,但您是通过某种仿真器或兼容层运行它。如果您尝试向程序传递超过 215 个参数,我希望模拟器或兼容层会给出错误消息。

【讨论】:

  • 但是想象一下你在一个 ARG_MAX 非常大的系统上(出于什么原因)并且它可能会发生。会是怎样的失败?由于它仍然遵守标准,它可以被称为 C 兼容,但它也可能发生未定义的行为,程序员无法阻止。这是什么错误?
  • 我认为标准有未定义的行为,因为没有定义签名溢出。
  • @zaibis 要求argv[argc] 为空指针意味着要求将ARG_MAX 设置得足够小以使argc 不能 溢出。
【解决方案2】:

实际上,不,你不能。大多数系统对argvenvp 的总组合大小设置了相对较低的限制。几十到几百 KB 的限制并不少见。请参阅 http://www.in-ulm.de/~mascheck/various/argmax/ 以获取对各种操作系统的限制的相当全面的列表。

【讨论】:

  • 该列表没有适用于 Windows 的数据,但有 question on SO 和一些数字。
【解决方案3】:

我试过这个:

test.c:

 ⚡⚡⚡  more test.c 
#include <stdio.h>
int main(int argc, char **argv)
{
    printf("argc = %d\n", argc);
    printf("Size of argc = %d\n", sizeof(argc));
    return 0;
}

然后使用了一个很大的 zipfile

 ⚡⚡⚡  ls -h bigfile 
-rw-r--r-- 1 ehwas ehwas 355M Jan 22 16:54 bigfile

然后将该文件作为参数读取到测试程序中:

⚡⚡⚡  ./test $(more bigfile)

结果:

5 minutes nothing happend, then everything froze

然后我尝试了一个较小的文件:

 ⚡⚡⚡  ls -h notsobigfile 
-rw-r--r-- 1 ehwas ehwas 6.7M Jan 22 17:04 notsobigfile

还有:

 ⚡⚡⚡  ./test $(more notsobigfile)
bash: ./test: Argument list too long

【讨论】:

  • 既然可以只使用 $(seq 1 100000),为什么还要使用 zip 文件来生成参数?
  • 没想到。谢谢!
【解决方案4】:

按照标准规定,argv[argc] 必须是有效值。

因此,如果运行时环境处于无法保证的情况,则不应启动程序。

【讨论】:

    猜你喜欢
    • 2023-03-10
    • 1970-01-01
    • 2015-11-05
    • 2012-12-01
    • 2010-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多