当前位置: 首页 > 科技观察

运行一个HelloWorld也会产生bug?Python、Java、C++等16种语言出手

时间:2023-03-22 11:28:04 科技观察

本文经AI新媒体量子位(公众号ID:QbitAI)授权转载,转载请联系出处。最简单的helloworld,居然也有bug?不是这段代码还能写错,而是在运行时发现了操作系统异常处理的很多漏洞。当结果输出到/dev/full,即设备空间不足,任何写入都应该失败时,C语言仍然返回0,成功退出:$gcchello.c-ohello$./hello>/dev/full$echo$?0该错误的最初发现者说:这不是一个小错误,本质上是一个“打印到标准输出”的任务。发生错误但没有抛出异常,这意味着即使数据丢失,进程也会继续运行。于是他坚持做下去,测试了C++、Python、Java等流行语言,发了博客,很快就在论坛上盖了一座高楼,讨论度顿时炸了:while评论区网友议论纷纷Debug,综合梳理下来,踩过这个bug的语言多达16种!HelloWorld的Debug进程的最初发现者是一位技术博主,名叫sunfishcode。在他的博客中,他展示了C和Python的详细调试过程。它主要使用Linux系统下一个经典的设备文件,/dev/full。/dev/full在写入时总是返回设备上没有剩余空间(错误码为ENOSPC),常用于测试程序是否能正确处理I/O错误。如果程序正常,则返回错误报告:$echo"HelloWorld!">/dev/fullbash:echo:writeerror:Nospaceleftondevice$echo$?1而正如我们一开始展示的代码,使用C语言输出时,hello程序报告成功并返回0。使用strace命令跟踪这个进程产生的系统调用,可以发现程序确实失败了:$strace-etrace=write./hello>/dev/fullwrite(1,"HelloWorld!\n",13)=-1ENOSPC(Nospaceleftondevice)+++exitedwith0+++还有标语“Errorsshouldnotbepassedquietly”的Python,也提出了一个观点。程序向stderr打印了一条消息,丢失了信息,但最后也返回了0:$python2hello.py>/dev/fullclosefailedinfileobjectdestructor:sys.excepthookismissingsys.stderr$echo$?0这个bug严重吗?现实世界中没有一个程序会把HelloWorld当作一个关键的安全问题,但是“打印到标准输出”是一个现实中确实存在的程序任务。这就是最简单的程序HelloWorld的本质。博主sunfishcode是这样说的:标准输出可能是指某个特定的文件,那么如果文件空间刚好用完,程序因为bug没有检测到这个错误怎么办?父进程不会知道子进程失败了,它会继续运行。但是预期生成的输出实际上丢失了数据。当然,博主最后还给出了一个没有踩雷的语言列表:网友热议:这是bug吗?目前博主已经针对这个bug给出了一些解决方案。例如在C语言环境下,可以使用这种方法:#include#includeintmain(void){printf("Hello,World!\n");if(fflush(stdout)!=0||ferror(stdout)!=0){returnEXIT_FAILURE;}returnEXIT_SUCCESS;}并且评论区也贡献了Java环境下的解决方案,即增加获取底层未包装OutputStream的方法:System.out.println("你好,世界!");如果(System.out.checkError())抛出新的IOException();下面有人补充说,Java引入的RuntimeIOException可以用于意外的I/O异常:所以我们可以引入一个新的类,比如ErrorCheckingPrintStream,在PrintStream中添加“ErrorCheckingPrintStreamwithErrorChecks()”方法。另外,评论区的一个热门话题是:这位博主公布的问题是bug吗?反对者直言作者是头条党,以为自己发现了C语言标准库的一些bug,但实际上它只是处理了所有可能的系统调用失败:HelloWorld只是将API调用到文本界面,是的A简单的调用界面,我还没有发现任何错误。一些赞同的意见在下面作了进一步的补充。他认为C语言的编写方式已经说明了:程序不关心任何形式的错误条件。包括忽略printf的返回值,不刷新输出,不检查刷新返回,不关心errno值等等。因此,用户不应期望给定的系统调用会返回额外的errno值,而应使用特殊方法来处理特殊情况。甚至有人说:程序的失败不是程序控制结构定义的,而是需求定义的。HelloWorld程序的要求是否包括主机系统的所有错误边界?也有人比较认同作者的看法,认为HelloWorld不仅仅是接口调用,实际上需要操作系统在某处写入数据,而这正是简单程序与现实世界关联的地方:这是一个严重的问题,并且似乎大多数时候,这样一个看似简单的功能中存在的大量复杂性都被忽略了。还有一种方式,从教育的角度评论:毕竟C语言是很多程序员的入门语言,hello.c是里面的第一个程序。初学者有必要更好地理解控制结构、块和返回值、缓冲流、printf格式化语言等概念,所以我们把它当作一个bug。所以你怎么看?