什麼是"Core Dumps",為什麼"Haskell"可以沒有?

"Haskell"介紹說"No core dumps":

"strong typing means no core dumps!"

http://www.haskell.org/haskellwiki/Introduction#Other_frequently-asked_questions

我記得以前終端有出過,然後什麼"yum"就用不了了

再以前有翻譯"吐核"的文章提到過

http://imtx.me/archives/1612.html

遇到問題直接"Google",找到以下說法

"In computing, a core dump, more properly a memory dump or storage dump, consists of the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed)."

http://en.wikipedia.org/wiki/Core_dump

"A core dump is a snapshot of the execution of a program at the moment it is aborted by the operating system (e.g. for attempting to violate the memory protection)."

http://oopweb.com/CPP/Documents/DebugCPP/Volume/coredump.html

"A coredump is a special file which represents the memory image of a process. Many operating systems have the capability of saving a core dump when the application crashes."

http://publib.boulder.ibm.com/httpserv/ihsdiag/coredumps.html

..英文看得我更糊塗,至少中文是"核心轉儲"

究竟是什麼情形,為什麼別的語言會有?


理想是美好的,現實是殘酷的。

聽說效率很重要,於是標準庫里就有各種unsafe*。

想要數組越界,來點unsafe{At,Read,Write}就好了嘛。

何況有了FFI,想怎麼作死都可以,區區coredump算什麼……


Core Dump通常是操作系統提供的調試輔助操作。用於當程序崩潰——通常是不得不調用abort()——時將程序當時的內存快照保留在一個文件里。程序員可以用調試器分析其中的內容從而推斷究竟是什麼原因引起了崩潰。Windows和傳統UNIX都提供了這樣的選項,允許程序崩潰時內核自動介入並創建dump。通常內核和用戶態程序都可以保存dump。

傳統上C/C++程序很多錯誤都能造成程序崩潰,一個常見的例子是內存訪問違例,不只是空指針,也包括很多其他的情形。對Windows而言,它也允許通過AppVerifier和Gflags強制在更多的情況讓程序崩潰,比如內存泄漏或不當訪問(野指針)時。Linux下我一般只用log,用工具調試的經驗不多,如有專家不妨賜教。

Dump這東西往往很討人厭,因為它只是程序崩潰瞬間的快照,而很多程序錯誤並不是出錯即停的,從這個快照里推導出程序的bug,就像福爾摩斯要從兇殺現場還原出沼地蝰蛇如何爬到隔壁咬死受害人的過程,充滿了謎題、猜測和推理,而且破案的成功率也難以保證。我幸運地有過兩次成功地從dump分析bug的經歷,每次分析幾乎都歷時一月以上。整體上在過去五年里,我遇到的情況都是以分析失敗居多。相對地,我所合作過的程序員往往也不願意調試這樣的bug。

最近十年來由於託管程序興起(Java/.NET/Python/...),我們的實際程序生活中已經很少出現程序崩潰的情形了,取而代之的是以程序拋出異常的形式退出。這種情況下由於其運行時並無調用abort()之虞,程序往往不會有dump產生,因為操作系統並不負責管理那些異常,在它的角度上看它只能看到運行時系統(比如Python解釋器或Java虛擬機)給出了某個非0的退出碼然後退出執行。

這其中比較特別一點的是.NET。我曾經聽說過Windows下可以通過Visual Studio在.NET程序拋出異常時強制介入並斷下程序執行,然後程序員可以選擇是否保存dump。因為.NET和Windows系統的緊密關係,微軟可以做到這一點。而如果某個解釋執行的程序能讓解釋器崩潰,那麼問題可大了:這說明這個解釋器可能被黑客作為攻擊的目標。

至於寫下那篇FAQ的那位「聖哲」所言的Strong Typing means no core dumps,又是一條夢囈一般的宣傳。這根本是風馬牛不相及的兩個東西。沒有core dump的充分條件是我們的程序運行在某個運行時之上,而當程序出錯時運行時能正確處理錯誤而沒有abort(),通常也就沒有core dump。我接觸Haskell的時間雖然很短,但至少也知道GHC和Hugs98都有解釋執行的能力,GHC雖然可以編譯代碼,但它的程序也有一個厚厚的運行時。這才是Haskell沒有core dump的真正原因。

=====

最後個人吐槽。話比較難聽。如有喜愛Haskell的知友不適,請見諒。

對於能在Haskell社區的公開場合看到這樣毫無常識的發言,我一點都不意外。就我開始接觸Haskell以來,這也不是第一次遇到了。它完全符合我對Haskell社區一部分吹鼓手的印象:對形式邏輯毫無理性的迷戀和對計算機工程和歷史非一般的無知,並且以一知半解為榮。最要命的是,恰恰是這幫迷戀邏輯和推理的人,說起話來毫無邏輯。

我想,恐怕這位FAQ作者所見過的最牛的所謂程序bug大概也就是編譯錯誤。這樣很好,就像我之前無數次說的,就讓他們繼續做他們的千秋大夢吧。


Core dump 的解釋建議看看 core 的 man 手冊。它是為輔助故障溯源的記錄程序運行狀態(主要是內存)的一個文件,是處理一些信號時的默認行為,即寫 coredump+ 終止進程。POSIX明確指定了一些信號的處理是需要生成 coredump 的。至於各系統對 POSIX 的兼容程度各有不一,另當別論(比如可以用 man 7 signal 去查 Linux 的情況)。像 @陳甫鵃 指出的 abort(3) ,實際上是最終產生一個 SIGABT 或 SIGIOT 信號。

本質上說,coredump 是信號處理的產物,是內核的行為。明確了這個,也就好繼續討論了。

首先其實只需要打開 ghci,然後

kill -11 `pidof ghc`

就可以為 ghc 進程發送一個斷錯誤信號,併產生一個 core dump. 如果系統設置 coredump 文件大小不是0,就可以看到一個 core 文件生成。

ghc 是 Haskell 的一個編譯器,Haskell是一個語言(規範)。一個語言本身能否產生 core dump 是偽命題。

"strong typing means no core dumps!" 應該是在強調不會出現內存訪問錯誤引起的 core dump. 其實這類錯誤是最常見的問題,本質原因是把一個非指針類型的數據當作指針來用,所以讀寫這個所謂的「地址」,就有可能出現內存錯誤。弱類型的語言,比如C,編譯器不能保證這一點,我們可以簡單的用一個數字,cast 成指針來讀寫。

近年大家看到更多的可能是類似 Java 的 NullPointerException 這樣的錯誤。所以新近的語言,比如 Mozilla 正在開發中的 Rust 語言,PR 中描述說是一個沒有 Null 指針的語言。考慮到 Haskell 也是一個相對古老的語言了,這個 「no core dump" 只是當時的一個宣傳語。

另外說託管的運行時環境沒有 dump 也是不太準確的斷言。舉個 Erlang 的例子。Erlang 的標準實現 BEAM 是一個由虛擬機運行 BEAM bytecode 的運行環境。Erlang/OTP 提供一個功能,BEAM 虛擬機會在自身出現錯誤(或收到其他一些信號處理)時,產生一個 crashdump 文件,裡面記錄了很多可能對分析故障有幫助的虛擬機狀態信息。很像操作系統內核提供的 core dump。從這個角度,core dump 這一類的功能又是一個有效的輔助分析工具。沒有它倒不見得是好事。


我不是很了解Haskell,但是根據字面上理解,FAQ裡面說的"No core dumps"是指它可以完全防止空指針的訪問。一般來說,在C/C++中,對空指針的任何調用或者說訪問非法內存地址的時候會導致程序崩潰,從而生成core dump。


所謂"沒有coredump"如果不是因為無知導致的胡說的話,那就是有意的宣傳用語。Coredump是一種操作系統的行為,Haskell是一種編程語言,你不可能把一本Haskell的書放在操作系統光碟,然後讓lambda calculus, lazy evaluation, strong type等等滲透到操作系統中,所以只要在編程語言的實現中除非了操作系統產生coredump的機制就會產生coredump,比如說kill它。

總之Haskell的類型系統雖然有獨到之處和高大上的特性,但是和coredump是兩個不同位面的東西。


dump本身就是一個內存快照,和程序使用的編程語言沒有關係。以Windows為例,如果系統開啟了自動抓dump,當一個程序造成系統崩潰,也就是Windows藍屏時,Windows核心會將崩潰時的內存快照寫到一個dump文件中,這和造成系統崩潰的程序是用何種語言寫的,沒有關係。或者我也可以用調試器調試一個進程,中斷該進程,並將當前內存dump下來,我根本不用關心這個進程的程序是用什麼語言寫的。

看引用的那句話:

Most functional languages, and Haskell in particular, are strongly typed, eliminating a huge class of easy-to-make errors at compile time. In particular, strong typing means no core dumps! There is simply no possibility of treating an integer as a pointer, or following a null pointer.

並非特指Haskell,而是指所有strong typing的編程語言,比如C#也可以算是一種強類型語言。這句話中的 no core dump 更像是一個宣傳口號,因為不能將整型當作指針,或者訪問一個空指針,所以沒那麼容易造成系統崩潰而已。


我不太明白什麼叫「Haskell 沒有 core dumps」。至於別的語言,Python/Ruby/Perl/Shell/PHP/Erlang/Lua/Javascript/Java/C#/etc 和 Haskell 都一樣的,包了層虛擬機或者解釋器,錯誤都被它們處理了。

至於什麼叫「core dump」,請自行查閱維基百科。


問題描述的鏈接錨點錯了, 詳見問題評論, 這裡補上(知乎改了字數限制, 不便修改描述)

http://www.haskell.org/haskellwiki/Introduction#No_core_dumps

"""

3.5 No core dumps

Most functional languages, and Haskell in particular, are strongly typed, eliminating a huge class of easy-to-make errors at compile time. In particular, strong typing means no core dumps! There is simply no possibility of treating an integer as a pointer, or following a null pointer.

"""


我當時剛剛開始學Haskell的時候,就看到了這句話,Haskell的類型系統可以讓你避免Core Dump,我心裡想,原來這麼碉

當我寫完Hello World等基本的程序之後,嘗試了下人生第一個稍微長一點的Haskell程序的時候,噗,直接掛了


推薦閱讀:

虎書ML版裡面關於garbage collector的問題?
如何評價 RAII 特性在 C++ 中的大範圍運用?
明明很多編程語言從對象數組中取數據比用SQL從表中取數據方便,為什麼資料庫還是使用SQL?
為什麼Python程序不怎麼佔用CPU資源?
假如DNA是一種編程語言,那麼誰能保證人類對DNA的修改沒有bug?

TAG:編程語言 | Haskell |