且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

为什么的glibc的FCLOSE(NULL)引起分段错误,而不是返回错误?

更新时间:2022-10-16 19:35:06

FCLOSE 要求作为其参数的文件指针获得或者通过的fopen ,标准流之一标准输入标准输出标准错误,或者在其他一些实现定义的方式。空指针是不是其中之一,这样的行为是不确定的,就像 FCLOSE((FILE *)0xdeadbeef)会。 NULL不是特别用C;除了一个事实,即它保证比较不等于任何有效的指针,它只是像任何其他无效的指针,并用它调用除非你将它传递给文件作为合同的组成部分的接口 NULL 有一些特殊的意义吧。

此外,一个错误返回将是有效的(因为该行为是未定义反正)反而有害行为的实现,因为它的隐藏了不确定的行为的。调用未定义行为的preferable结果总是崩溃,因为它突出了错误,并且使您可以修复它​​。大多数用户 FCLOSE 不检查一个错误返回值,我敢打赌,大多数人傻到路过 NULL FCLOSE 不会足够聪明,检查 FCLOSE 的返回值>。一个有道理的,人们的的检查 FCLOSE 一般的返回值,因为最终刷新可能会失败,但是这是没有必要的那些只读取打开文件,或者 fflush 手动调用之前 FCLOSE (这是一个聪明的成语呢,因为它更容易处理错误,而你仍然有打开的文件)。

According to man page fclose(3):

RETURN VALUE

Upon successful completion 0 is returned. Otherwise, EOF is returned and the global variable errno is set to indicate the error. In either case any further access (including another call to fclose()) to the stream results in undefined behavior.

ERRORS

EBADF The file descriptor underlying fp is not valid.

The fclose() function may also fail and set errno for any of the errors specified for the routines close(2), write(2) or fflush(3).

Of course fclose(NULL) should fail but I expect that it to return with an errno normally instead of dying by segmentation fault directly. Is there any reason of this behavior?

Thanks in advance.

UPDATE: I shall put my code here (I'm trying strerror(), particularly).

FILE *not_exist = NULL;

not_exist = fopen("nonexist", "r");
if(not_exist == NULL){
    printError(errno);
}

if(fclose(not_exist) == EOF){
    printError(errno);
}

fclose requires as its argument a FILE pointer obtained either by fopen, one of the standard streams stdin, stdout, or stderr, or in some other implementation-defined way. A null pointer is not one of these, so the behavior is undefined, just like fclose((FILE *)0xdeadbeef) would be. NULL is not special in C; aside from the fact that it's guaranteed to compare not-equal to any valid pointer, it's just like any other invalid pointer, and using it invokes undefined behavior except when the interface you're passing it to documents as part of its contract that NULL has some special meaning to it.

Further, returning with an error would be valid (since the behavior is undefined anyway) but harmful behavior for an implementation, because it hides the undefined behavior. The preferable result of invoking undefined behavior is always a crash, because it highlights the error and enables you to fix it. Most users of fclose do not check for an error return value, and I'd wager that most people foolish enough to be passing NULL to fclose are not going to be smart enough to check the return value of fclose. An argument could be made that people should check the return value of fclose in general, since the final flush could fail, but this is not necessary for files that are opened only for reading, or if fflush was called manually before fclose (which is a smarter idiom anyway because it's easier to handle the error while you still have the file open).