C++ 当传递无效指针时,`ferror(FILE*)`和`std::ferror(FILE*)`的行为是什么?

C++ 当传递无效指针时,`ferror(FILE*)`和`std::ferror(FILE*)`的行为是什么?,c++,c,language-lawyer,std,libc,C++,C,Language Lawyer,Std,Libc,传递无效指针时,:ferror(文件*)和std::ferror(文件*)的行为是什么? < C++标准只指C(参见)。但是在C标准中,ferror函数描述中没有提到传递无效指针或NULL时会发生什么 我理解,根据C第7.21.3.4条草案: 关联文件(包括标准文本流)关闭后,指向文件对象的指针的值是不确定的 但这不应妨碍检查任何给定的文件*指针(不确定或不确定)是否引用有效的文件对象的实现 无论哪种方式,标准甚至似乎对这是未定义的行为、实现定义的行为还是其他行为都保持沉默 例如,fopen(

传递无效指针时,
:ferror(文件*)
std::ferror(文件*)
的行为是什么?

< C++标准只指C(参见)。但是在C标准中,
ferror
函数描述中没有提到传递无效指针或
NULL
时会发生什么

我理解,根据C第7.21.3.4条草案:

关联文件(包括标准文本流)关闭后,指向
文件
对象的指针的值是不确定的

但这不应妨碍检查任何给定的
文件*
指针(不确定或不确定)是否引用有效的
文件
对象的实现

无论哪种方式,标准甚至似乎对这是未定义的行为、实现定义的行为还是其他行为都保持沉默


例如,
fopen()
可以将返回的指针存储在某个全局集合(例如
std::set
)中,
ferror()
和类似的函数可以检查它们的参数是否包含在该集合中,另外,
fclose()
将其从该集合中删除。

根据C草案§4.2,遗漏被视为未定义的行为(强调添加):

如果违反了出现在约束或运行时约束之外的“应”或“不应”要求,则行为未定义。未定义的行为在本国际标准中以“未定义的行为”或省略任何明确的行为定义来表示。这三者在重点上没有区别;它们都描述了“未定义的行为”


感谢您在对问题的评论中对此进行了描述。

这是未定义的行为。根据C标准(J.2未定义的行为)

-指向
文件
对象的指针的值在关联的 文件已关闭(7.21.3)

当传递无效指针时,{any standard library function}的行为是什么

有些函数会检查
NULL
。未指定用于检查其他无效指针的指针。这是未定义的行为,因为C规范在这些情况下缺乏任何定义

但这不应妨碍检查任何给定文件*指针(不确定或不确定)是否引用有效文件对象的实现

这是正确的-不阻止检查
ferror()
可以执行这样的检查,但不需要这样做。未定义具有此类指针的行为

关闭关联文件(包括标准文本流)后,指向文件对象的指针的值是不确定的

但这不应妨碍检查任何给定文件*指针(不确定或不确定)是否引用有效文件对象的实现

不幸的是,没有。想象一个实现,其中
fopen
fclose
的框架如下所示

FILE *
fopen(const char *path, const char *mode)
{
    FILE *fp = malloc(sizeof(FILE));
    if (!fp) return 0;
    // ... initialize fp ...
    return fp;
}

int
fclose(FILE *fp)
{
    // ... tear down fp ...
    free(fp);
    return 0;
}
为了确定
ferror
的参数是否引用有效的文件对象,此实现必须能够检测用于引用
malloc
分配的存储的指针值,但由于该堆块已被释放,因此现在不确定。你可能已经知道,没有办法做到这一点。因此,这个实现不能做你想做的,C委员会也不想排除这个实现


(C标准一贯使用“不确定”来指代那些你除了可能复制它们之外不能做任何事情的值;任何对不确定值的控制或算术依赖都会引发未定义的行为。[脚注:仔细阅读本标准的规范性文本在技术上并不支持这一点,但所有C语言的字面意义上的实现都处理了这样一句话:“如果……在不确定的情况下使用具有自动存储持续时间的对象的值,则行为是未定义的。”在C11的非规范性附录J.2中,就好像它是规范性的一样,也就好像“自动存储持续时间”限定符不存在一样。])

相关文本是7.1.4库函数的使用,^1:

除非在随后的详细说明中另有明确说明,否则以下语句均适用:如果函数的参数具有无效值(如函数域外的值,或程序地址空间外的指针,或空指针,或对应参数不符合常量条件时指向不可修改存储器的指针)或类型(升级后)参数个数可变的函数不需要该行为,该行为未定义


对于所有标准库函数,传递空指针或无效指针是未定义的行为,除非该函数的规范为其提供定义。然而,一般来说,在资源句柄释放后使用资源句柄的规范基本上不可能在mea中指定ningful way
除非禁止再次使用资源句柄。因此,虽然可以为空情况指定行为,也有一些函数可以指定,但不可能为任何形式的UAF指定行为(释放后使用),其中在
fclose
之后使用
FILE*
是一种情况。

如果标准对传递无效指针或
NULL
指针时发生的情况保持沉默,则行为未定义。“未定义”的定义在标准中,还明确包括标准没有描述对所发生的事情的约束的情况。行为是未定义的,这当然不是真的