mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
class.c: check redefinition
* class.c (rb_prepend_module): check redefinition of built-in opimized methods. [ruby-dev:47124] [Bug #7983] * vm.c (rb_vm_check_redefinition_by_prepend): ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39601 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
00a8203b0b
commit
f113ab552c
4 changed files with 62 additions and 11 deletions
|
@ -1,3 +1,10 @@
|
|||
Tue Mar 5 21:36:43 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* class.c (rb_prepend_module): check redefinition of built-in opimized
|
||||
methods. [ruby-dev:47124] [Bug #7983]
|
||||
|
||||
* vm.c (rb_vm_check_redefinition_by_prepend): ditto.
|
||||
|
||||
Tue Mar 5 20:29:25 2013 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||
|
||||
* proc.c (mnew): revert r39224. [ruby-core:53038] [Bug #7988]
|
||||
|
|
6
class.c
6
class.c
|
@ -790,6 +790,7 @@ move_refined_method(st_data_t key, st_data_t value, st_data_t data)
|
|||
void
|
||||
rb_prepend_module(VALUE klass, VALUE module)
|
||||
{
|
||||
void rb_vm_check_redefinition_by_prepend(VALUE klass);
|
||||
VALUE origin;
|
||||
int changed = 0;
|
||||
|
||||
|
@ -816,7 +817,10 @@ rb_prepend_module(VALUE klass, VALUE module)
|
|||
changed = include_modules_at(klass, klass, module);
|
||||
if (changed < 0)
|
||||
rb_raise(rb_eArgError, "cyclic prepend detected");
|
||||
if (changed) rb_clear_cache();
|
||||
if (changed) {
|
||||
rb_clear_cache();
|
||||
rb_vm_check_redefinition_by_prepend(klass);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1475,6 +1475,20 @@ class TestModule < Test::Unit::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
def test_prepend_optmethod
|
||||
bug7983 = '[ruby-dev:47124] [Bug #7983]'
|
||||
assert_separately [], %{
|
||||
module M
|
||||
def /(other)
|
||||
to_f / other
|
||||
end
|
||||
end
|
||||
Fixnum.send(:prepend, M)
|
||||
assert_equal(0.5, 1 / 2, "#{bug7983}")
|
||||
}
|
||||
assert_equal(0, 1 / 2)
|
||||
end
|
||||
|
||||
def test_class_variables
|
||||
m = Module.new
|
||||
m.class_variable_set(:@@foo, 1)
|
||||
|
|
46
vm.c
46
vm.c
|
@ -972,28 +972,54 @@ rb_iter_break_value(VALUE val)
|
|||
|
||||
static st_table *vm_opt_method_table = 0;
|
||||
|
||||
static int
|
||||
vm_redefinition_check_flag(VALUE klass)
|
||||
{
|
||||
if (klass == rb_cFixnum) return FIXNUM_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cFloat) return FLOAT_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cString) return STRING_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cArray) return ARRAY_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cHash) return HASH_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cBignum) return BIGNUM_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cSymbol) return SYMBOL_REDEFINED_OP_FLAG;
|
||||
if (klass == rb_cTime) return TIME_REDEFINED_OP_FLAG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
rb_vm_check_redefinition_opt_method(const rb_method_entry_t *me, VALUE klass)
|
||||
{
|
||||
st_data_t bop;
|
||||
if (!me->def || me->def->type == VM_METHOD_TYPE_CFUNC) {
|
||||
if (st_lookup(vm_opt_method_table, (st_data_t)me, &bop)) {
|
||||
int flag = 0;
|
||||
|
||||
if (klass == rb_cFixnum) flag = FIXNUM_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cFloat) flag = FLOAT_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cString) flag = STRING_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cArray) flag = ARRAY_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cHash) flag = HASH_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cBignum) flag = BIGNUM_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cSymbol) flag = SYMBOL_REDEFINED_OP_FLAG;
|
||||
else if (klass == rb_cTime) flag = TIME_REDEFINED_OP_FLAG;
|
||||
int flag = vm_redefinition_check_flag(klass);
|
||||
|
||||
ruby_vm_redefined_flag[bop] |= flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
check_redefined_method(st_data_t key, st_data_t value, st_data_t data)
|
||||
{
|
||||
ID mid = (ID)key;
|
||||
rb_method_entry_t *me = (rb_method_entry_t *)value;
|
||||
VALUE klass = (VALUE)data;
|
||||
rb_method_entry_t *newme = rb_method_entry(klass, mid, NULL);
|
||||
|
||||
if (newme != me)
|
||||
rb_vm_check_redefinition_opt_method(me, me->klass);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
void
|
||||
rb_vm_check_redefinition_by_prepend(VALUE klass)
|
||||
{
|
||||
if (!vm_redefinition_check_flag(klass)) return;
|
||||
st_foreach(RCLASS_M_TBL(RCLASS_ORIGIN(klass)), check_redefined_method,
|
||||
(st_data_t)klass);
|
||||
}
|
||||
|
||||
static void
|
||||
add_opt_method(VALUE klass, ID mid, VALUE bop)
|
||||
{
|
||||
|
|
Loading…
Add table
Reference in a new issue