C程序的参数是否保证以'\0'结尾?

4
关于main()参数,2011年C标准(5.1.2.2.1:2)规定:

如果argc的值大于0,则数组成员argv[0]到argv[argc-1](含)将包含指向字符串的指针,在程序启动之前由主机环境给出实现定义的值。

在这种情况下,“字符串”一词是否应解释为“0结尾的字符串”,即以非0字符序列结尾,后跟最终的'\0',或者一些实现是否以不同的方式传递程序参数?

在POSIX平台上,exec*函数族之一的参数是否由exec*函数验证为指向格式正确的字符串(如何验证?),或者一个setuid程序应该避免假设已经传递了格式正确的0结尾字符串作为参数?


3
反问:如果没有\0结尾,有什么合理的方法能够读取这些字符串呢? - Robert Harvey
1
实际上,要不是这样,你怎么知道它们的长度呢? - Shafik Yaghmour
@RobertHarvey 好吧,如果不是Oli Charlesworth挖掘出的定义,某些平台上程序的参数可能始终最多只有16个字符。 - Pascal Cuoq
1
问题本质上在询问一个恶意(甚至只是有缺陷的)程序是否可以通过exec()传递畸形参数数组 - 即使这不具有实际可解释性,因为问题涉及风险而非功能,所以这并不重要。 - Chris Stratton
在C语言中,“string”总是指“以空字符结尾的字符串”。 - M.M
1个回答

8

在这种情况下,“string”这个词是否应该被解释为“0结尾的字符串”,即一系列非0字符后跟最后一个'\0',或者某些实现可能以不同的方式向程序传递参数?

7.1.1定义了一个字符串:

字符串是由第一个空字符终止并包括在内的连续字符序列。


exec*函数族的参数是否由exec*函数本身验证为指向格式正确的字符串的指针(如何验证)。

POSIX规范指出,exec系列函数的args是以空字符结尾的字符串,并且没有指定如果不是这种情况会发生什么。可能是未定义的行为。这似乎是合理的,因为exec函数没有合理的方式来验证每个参数是否正确地以空字符结尾。(但请记住,exec*必须复制其参数,因为地址空间即将被交换出去。)


没有这个保证,它就不是真正的C语言,因为它没有遵循C标准。 - Robert Harvey
@OliCharlesworth 好的,我再考虑一下,如果是针对我的操作系统,我会定义一个最大参数长度(4KiB或任何合理的长度),并从调用execv*的进程中读取该长度的数据。如果在这个限制范围内没有找到'\0',那就是一个错误(和/或者我会添加终止符0到复制品)。 - Pascal Cuoq
@OliCharlesworth 哦,确实有这样的限制,它被称为 ARG_MAX。感谢您提供相关标准的链接。 - Pascal Cuoq
1
@OliCharlesworth 我对恶意进程在良性的操作系统上调用exec函数并使用良性的setuid二进制文件很感兴趣,这不仅是理论上的。 - Pascal Cuoq
1
@OliCharlesworth和@PascalCuoq,无论规范是否明确说明,实际上exec调用确实会检查空终止符。exec必须复制参数到新进程中。在启动时,子进程的参数不指向父进程分配的内存。对于任何想要在父进程死亡后引用其argv参数的程序来说,这是行不通的。在复制这些参数的过程中,exec必须检查格式良好的字符串,否则,如果没有检测到空终止符,它将因E2BIG而失败。 - Duck
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接