• 文章
  • 為什麼 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 時不會這樣做。)

盡情享受吧!