Hello World程序里居然有bug!

Hello World可能是码农们最常写的计算机程序了。很多人在刚开始学习一种新的编程语言时,编写的第一个程序就是Hello World。

所以这个看上去毫无特别之处的入门程序,真的一点儿bug也没有吗?

a3fbc0a53ac584e66a4dfb838705f9bb.png

毕竟Hello World程序只做一件事,怎么会有bug呢?

C语言中的Hello World

用C语言编写Hello World有很多不同的版本,比如维基百科里的版本、《C程序设计语言》一书里的版本,甚至还有1972年贝尔实验室成员Brian Kernighan撰写的版本。

0153b660e6930db78fe54e4f88dc6eb5.png

Brian Kernighan撰写的Hello World

下面这个是ANSI C(美国国家标准学会发布的C语言标准)中的版本:

/* Hello World in C, Ansi-style */

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
  puts("Hello World!");
  return EXIT_SUCCESS;
}

这可以说是最严谨的Hello World版本了吧?

它使用(void)来确保main是一种新的声明方式。它使用EXIT_SUCCESS宏指令来表示成功,而不是假设计算机平台使用0。另外,它还使用了适当的头文件声明puts。这个版本试图各方面都做到万无一失。

但它还是有个bug。

C语言里怎么会有bug?

Linux有一个叫“/dev/full”的设备文件,就像它那个有名的表亲“/dev/null”一样,但是当你把数据写入“/dev/full”时,数据并不会扔掉,而是会报错。它的作用就像文件系统中的一个刚刚用完空间的文件:

$ echo "Hello World!" > /dev/full
bash: echo: write error: No space left on device
$ echo $?
1

这是一个很棒的小工具,可以用来测试程序是否正确处理I/O错误。创建没有剩余空间的实际文件系统,或实际发生故障的磁盘是很不方便的,但要求一个程序将其输出写入“/dev/full”后看看会发生什么,是很容易的。

所以让我们测试一下上述的C语言范例:

$ gcc hello.c -o hello
$ ./hello > /dev/full
$ echo $?
0

跟上面的shell中使用echo时不同,这里没有得到任何输出,退出状态值为0。这意味着hello world程序成功执行。

但是,它实际上并没有成功。我们可以用strace确认:

$ strace -etrace=write ./hello > /dev/full
write(1, "Hello World!\n", 13)          = -1 ENOSPC (No space left on device)
+++ exited with 0 +++

操作系统报告了“No space”错误,但程序依然执行并返回了0,系统觉得代码成功了。这是个bug啊!

这个bug有多严重呢?

按理说,hello world在任何地方都不是绝对安全的。然而,它确实能打印到标准输出,标准输出可能会被重定向到另一个文件。而现实世界中的文件可能占用了全部空间。如果程序没有检测到这种错误,并通过返回代码报告错误,那么父进程就不会知道子进程失败了,即便系统期望产生的输出已经悄悄丢失了数据,但程序仍会继续运行,就像什么都没发生一样。

例如一个将yaml文件print到标准输出的程序,如果标准输出的空间用完了,输出可能会在某个任意的点被截断,尽管它可能仍然是有效的yaml。所以我们应该期望程序能够检测并报告这种情况。

某些主流语言也有bug

再来看看Python会告诉我们“bug不该悄悄传递”吗?这是Python2:

$ python2 hello.py > /dev/full
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
$ echo $?
0

它确实向stderr打印了一条信息,尽管这条信息令人困惑,但它也返回了0,这意味着它在告诉运行它的人,它成功退出了。

幸运的是,Python3正确地报告了这个错误,而且还print了一个更赞的错误信息。

$ python3 hello.py > /dev/full
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
OSError: [Errno 28] No space left on device
$ echo $?
120

使用普通教程网站上的hello world程序,又尝试了另外几种语言,测试结果如下:

语言

是否有bug

测试版本

C

(全部)

C++

(全部)

Python 2

Python 2.7.18

Ruby

ruby 2.7.2p137 (2020-10-01修订版5445e04352) [x86_64-linux-gnu]

Java

Openjdk 11.0.11 2021-04-20

Node.js

V12.21.0

Haskell

Glorious Glasgow Haskell编译系统,版本8.8.4

Rust

rustc 1.59.0 (9d1b2106e 2022-02-23)

Python 3

Python 3.9.5

Perl

Perl 5,版本32,subversion 1 (v5.32.1) built for x86_64-linux-gnu-thread-multi (with 46 registered patches...)

Perl 6

V2020.12

Bash

GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)

Awk

GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)

OCaml

4.08.1

Tcl

8.6.11

C#

Mono JIT 编译器版本 6.8.0.105

编译:lwy

原文链接:

https://blog.sunfishcode.online/bugs-in-hello-world/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值