原文地址:https://blog.sunfishcode.online/bugs-in-hello-world/
Hello World
或许是最常被编写的计算机程序了。几十年来,它都是许多人开始学习一门新的程序语言时编写的第一个程序。
理所当然的,这个毫不起眼的开始应当是没有 Bug 的,对吧?
毕竟,Hello World 就只是输出个 Hello World
,又能有什么坏心思 Bug 呢?
看看 C 语言?
在 C 语言中写 Hello World 的方法有许多种。有维基百科版本,K&R书中的hello world,甚至还有1974年已知最古老的C hello world程序。
这里采用另一个 “ANSI C” 中的版本:
/* Hello World in C, Ansi-style */
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
puts("Hello World!");
return EXIT_SUCCESS;
}
这是最小心谨慎的一个版本。它使用了 (void)
来确保 main
时新式声明,使用了 EXIT_SUCCESS
而不是 0
来表示成功,这可以规避掉一部分的风险(真没必要),同时它也使用了正确的 headers 来防止隐式声明 puts
。这看起来可以完美地输出“ Hello World!
”。
但是,它存在一个 Bug。
之前提到的其他版本中也存在着这个 Bug。
真有 Bug?
Linux 有个有趣的驱动器文件叫做 “/dev/full”,它跟著名的 “/dev/null” 很像。但不同的是,后者会丢弃所有被写入其中地数据,而前者永远是满的。
$ echo "Hello World!" > /dev/full
bash: echo: write error: No space left on device
$ echo $?
1
这是一个测试程序是否正确处理 I/O 错误的很棒的小工具。你可以把它轻易作为一个满的或坏的磁盘来使用,而不是历经万难去创设一个这样的文件系统。
让我们来试试上面的代码吧!
$ gcc hello.c -o hello
$ ./hello > /dev/full
$ echo $?
0
不像我们之前使用 echo 时那样,我们没有得到输出,并且退出状态是 0,这意味着这个程序回报说它正常运行了!但事实上我们都知道,他失败了。通过使用 strace,我们可以确信它确确实实遇到了异常:
$ strace -etrace=write ./hello > /dev/full
write(1, "Hello World!\n", 13) = -1 ENOSPC (No space left on device)
+++ exited with 0 +++
看!操作系统说没空间了!但这又和程序有什么关系呢?程序把这个错误瞒了下来,让系统误以为没有发生异常,这是不对的!
这严重吗?当然,在 Hello World 中这算不上什么。但是,在其他需要标准输出的地方,这可能会导致一些问题。特别是当输出到一个文件时,明明失败了系统却不知道,于是乎系统继续向前运行,这或将导致数据的丢失,亦或是系统的错误!一片寂静之中,你的数据少了一半!
比方说你要输出一个 yaml 或其他什么,明明没有空间了却未处理这一异常,你将获得一个无效的 yaml!
必要之时,我们需要把这一 Bug 纳入考虑范围。
那么,其他语言呢?
看看原文吧!
这里贴一张引子原文的表格
语言 | 有这个 Bug? | 测试版本 |
---|---|---|
C | Yes | (all) |
C++ | Yes | (all) |
Python 2 | Yes | Python 2.7.18 |
Ruby | Yes | ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-linux-gnu] |
Java | Yes | openjdk 11.0.11 2021-04-20 |
Node.js | Yes | v12.21.0 |
Haskell | Yes | The Glorious Glasgow Haskell Compilation System, version 8.8.4 |
Rust | No | rustc 1.59.0 (9d1b2106e 2022-02-23) |
Python 3 | No | Python 3.9.5 |
Perl | No | perl 5, version 32, subversion 1 (v5.32.1) built for x86_64-linux-gnu-thread-multi (with 46 registered patches...) |
Perl 6 | No | v2020.12 |
Bash | No | GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu) |
Awk | No | GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1) |
OCaml | No | 4.08.1 |
Tcl | No | 8.6.11 |
C# | No | Mono JIT compiler version 6.8.0.105 |
评论