回答
約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中,問題以不同的方式解決。]
一個明顯的缺陷就是名稱衝突 - 如果兩個或多個軟件包爲不同行爲的方法選擇相同的名稱。
The Trifecta of FAIL; or, how to patch Rails 2.0 for Ruby 1.8.7有一個Rails的例子(這是一個大的,詳細檢查的項目)導致的問題,因爲他們monkypatched String
添加方法chars
。
相關問題:http://stackoverflow.com/questions/699152/looking-for-a-concrete-example-of - 用猴子修補的錯誤 – 2011-04-18 01:17:59