• 文章
  • 为什么 system() 是邪恶的
发布者:
2009年5月20日 (最后更新:2009年5月20日)

为什么 system() 是邪恶的

评分:4.5/5 (664票)
*****
所以,你来到这里是因为每个人都在告诉你像 system("PAUSE")system("CLS") 这样的东西很糟糕。但没有人真正解释为什么

原因如下。


----------------- 它资源消耗大 ----------------
首先,你必须考虑 system() 函数实际上做了什么:它执行的不仅仅是一个,而是可能两个独立的进程,并将退出状态返回给你的程序(希望是你想运行的那个程序的退出状态)。
http://linux.die.net/man/3/system 注意所有可能出错的地方……以及用于错误识别和处理的极少选择。

但等等,还有更多!说到 system("PAUSE"),这里是 WaltP 对 system() 为实现其目标所做工作的简化但完整的分解。
http://www.gidnetwork.com/b-61.html

----------------- 它破坏了安全性 -----------------
那么,如果它只是资源消耗大,又是什么让它如此邪恶呢?

因为你无法保证你正在执行的程序
1 是一个有效的命令
2 在所有系统上执行相同的操作
3 没有被恶意代码感染,或者
4 是你认为它是什么程序
最后两点需要稍作解释。

这里有一个小的控制台程序可以尝试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
#include <stdlib.h>

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__)
#define EDITOR "notepad"
#else
#define EDITOR "emacs"
#endif

int main()
  {
  printf( "Now I'm going to start your text editor!\n" );
  system( EDITOR );
  printf( "Good-bye!\n" );
  return 0;
  }

给 Unix/Linux 用户的一些说明
- 我没有安装 emacs(我受不了它)。我用“kate”和“vim”代替。如果你没有安装 Emacs,请编辑上面的源代码,将其替换为你喜欢的文本编辑器的名称。
- 如果你不知道如何退出 emacs,请按Ctrl-X,然后Ctrl-C.
- 在运行你的程序之前,你必须确保 PATH 包含了当前目录。对于 bash 用户,在运行程序之前,在命令提示符下键入
ECHO=.:"$PATH"
。别担心,这只是临时的。一旦你完成了这些练习,键入一个点然后按 ENTER 键即可重新启动 bash 并恢复到正确的默认设置。

好了,去编译并运行它看看效果吧。


现在你已经看到它正常工作了,在同一个目录下创建一个新的小程序
1
2
3
4
5
6
7
#include <stdio.h>

int main()
  {
  printf( "Bwah, hah, hah, hah, hah!\n" );
  return 0;
  }

编译它,并将可执行文件命名为“notepad.exe”(如果你在 Windows 上),或者“emacs”(或者上面你使用的任何名称),如果你在 *nix 上。(小心不要覆盖你第一个程序的*.exe)。

现在再次运行第一个程序。发生了什么?(Unix/Linux 用户,现在是重启 shell 的好时机。记住,这个例子是人为设计的——有很多其他方法可以将恶意软件引入执行路径。)


危险在于,当你直接执行一个程序时,它会获得与你的程序相同的权限——这意味着,例如,如果你以系统管理员的身份运行,那么你刚刚无意中执行的恶意程序也将以系统管理员的身份运行。如果这还不能让你吓得魂飞魄散,请检查一下你的脉搏。

即使你不是 sysadmin 也没关系。能做的都能做。


------------- 反病毒程序讨厌它 -------------
最后一件事仅仅是感知问题。如果你的用户运行任何类型的杀毒软件,如 ZoneAlarm、Norton、McAfee 等,那么他们就会收到一条非常令人不快的消息,说你的程序试图做一些被认为危险的事情。请记住,杀毒软件不会说明你试图做什么,只说明它试图做一些不当的事情。用户对这类程序持怀疑态度。


好了,就到这里吧。除非必要,否则不要使用 system()。

希望这有帮助。
作为补充,如果你确实需要使用 system(),通常最好检查一下你是否有一个 shell 可用。
1
2
if (system( NULL )) then_I_can_safely_use_system();
else fooey();


另外,直接来自手册页
不要在具有 set-user-ID 或 set-group-ID 权限的程序中使用 system(),因为某些环境变量的奇怪值可能会被用来破坏系统完整性。请使用 exec(3) 系列函数,但不要使用 execlp(3)execvp(3)。在某些系统上,如果 /bin/sh 是 bash 2 版本,并且 bash 2 在启动时会降权,那么 system() 在具有 set-user-ID 或 set-group-ID 权限的程序中实际上将无法正常工作。(Debian 使用了一个修改过的 bash,在被调用为 sh 时不会这样做。)

尽情享受吧!