zai*_*ius 2 ruby monkeypatching
我正在寻找为什么在ruby中扩展基类不是一个好主意的例子.我需要向一些人展示为什么它是一种谨慎使用的武器.
你可以分享任何恐怖故事吗?
大约2.5年前在鲁宾尼斯有一个非常着名的猴子修补例子.
关于这个案例的有趣之处在于,违规代码和受害者都非常明显且极不寻常.通常,罪犯是由一些PHP脚本小伙子写的一段代码,他们在他的1337元编程h4X0r技能上喝醉了.并且失败模式是一个简单的ArgumentError例外,因为原始方法和monkeypatch具有不同的arity.
但是,在这种情况下,罪犯是stdlib(mathn)中的一个库,失败模式是Rubinius VM完全爆炸.
所以发生了什么事?好吧,mathnmonkeypatches Fixnum类并改变Fixnum算术的工作方式.特别是,它改变了几种核心方法的结果和类型.例如:
r = 4/3 # => 1
r.class # => Fixnum
require 'mathn'
r = 4/3 # => (4/3)
r.class # => Rational
Run Code Online (Sandbox Code Playgroud)
问题当然是在Rubinius中,整个Ruby编译器,整个Ruby内核,Ruby核心库的大部分内容,Rubinius VM的某些部分以及Rubinius基础架构的其他部分都是用Ruby编写的.当然,所有这些Fixnum都在整个地方使用算术.
该Hash班是用Ruby编写的,它使用Fixnum算法来计算散列桶的大小,计算哈希函数等.Array是用Ruby编写的,需要计算元素大小和数组长度.FFI库是用Ruby编写的,需要计算内存地址(!)和结构大小.Rubinius的许多部分假设他们可以做一些Fixnum算术然后将结果传递给某个C函数作为指针或int.
而且由于Ruby不支持任何类型的选择器命名空间或类拳击或类似(虽然类似于Ruby 2.0的计划),只要一些随机用户代码需要mathn库,所有这些部分都会引人注目地爆炸,因为所有突然之间,一个Fixnum操作的结果不再是一个Fixnum(它基本上与一台机器相同int,可以这样传递),而是一个Rational(它是一个完整的Ruby对象).
基本上,会发生什么,是某些代码会require 'mathn'(或者你会将其输入到IRb中),并且VM会立即死亡.
在这种情况下,解决方案是编译器的安全数学插件:当编译器检测到它正在编译内核或Rubinius的其他核心部分时,它会自动将对Fixnum方法的调用重写为对这些方法的私有不可变副本的调用.[注意:我认为在当前版本的Rubinius中,问题以不同的方式解决.]
| 归档时间: |
|
| 查看次数: |
828 次 |
| 最近记录: |