2010-08-09 81 views
2

我正在尋找爲什麼在ruby中擴展基類不是個好主意的例子。我需要向一些人展示爲什麼它是一種被謹慎使用的武器。紅寶石猴子修補陷阱

任何恐怖故事,你可以分享?

+0

相關問題:http://stackoverflow.com/questions/699152/looking-for-a-concrete-example-of - 用猴子修補的錯誤 – 2011-04-18 01:17:59

回答

5

約2.5年前在魯比尼烏斯有一個很有名的例子monkey-patching going horribly wrong

有關這種情況的有趣之處在於,違規代碼和受害者都非常明顯而且非常不尋常。通常,罪犯是由一些PHP腳本kiddy編寫的一段代碼,他在1337元編程語言h4X0r技巧上喝醉了。而失敗模式是一個簡單的ArgumentError例外,因爲原始方法和monkeypatch具有不同的元素。

但是,在這種情況下,違規者是stdlib(mathn)中的一個庫,失敗模式是Rubinius VM完全炸燬。

那麼,發生了什麼?那麼,mathn monkeypatches Fixnum類和更改如何Fixnum算術運作。特別是,它改變了幾種核心方法的結果類型。例如:

r = 4/3 # => 1 
r.class # => Fixnum 

require 'mathn' 

r = 4/3 # => (4/3) 
r.class # => Rational 

的問題當然是在Rubinius的,整個的Ruby編譯器,整個Ruby的內核,Ruby的核心庫的大部分地區,在Rubinius的虛擬機和Rubinius的基礎設施的其它部分的某些部分,都是用Ruby編寫的。當然,所有這些都使用Fixnum算術。

Hash類是用Ruby編寫的,它使用Fixnum算法來計算哈希桶的大小,計算哈希函數等等。 Array是用Ruby編寫的,需要計算元素大小和數組長度。 FFI庫用Ruby編寫,需要計算內存地址(!)和結構大小。 Rubinius的許多部分都假設他們可以執行一些Fixnum算術運算,然後將結果作爲指針或int傳遞給某個C函數。

由於Ruby不支持任何類型的選擇器命名空間或類裝箱或類似的操作(儘管類似的計劃是針對Ruby 2.0),只要一些隨機的用戶代碼需要mathn庫,所有這些部分只是壯觀地爆炸,因爲突然,Fixnum操作的結果不再是Fixnum(它基本上與機器int相同並且可以如此傳遞),而是Rational(這是一個完整的Ruby對象)。

基本上,會發生什麼,是一些代碼將require 'mathn'(或者你將它鍵入IRb),並立即虛擬機死亡。

的解決方案,在這種情況下,是安全數學插件編譯器:當編譯器檢測到它是在編譯內核或Rubinius的其他核心部件,它會自動重寫調用Fixnum方法爲撥打私人這些方法的不可變副本。 [注:我認爲在當前版本的Rubinius中,問題以不同的方式解決。]

+0

是的,這絕對是可怕的。這聽起來像是一個完整的噩夢追蹤。 – zaius 2010-08-11 22:25:31

+0

這個bug今天就咬我了。包括我公司聊天機器人的「twss」插件包括分類器,其中包括mathn,它通過打破整數分割打破了linkbot。嘆。 – llimllib 2011-04-29 19:28:31

1

一個明顯的缺陷就是名稱衝突 - 如果兩個或多個軟件包爲不同行爲的方法選擇相同的名稱。