Comments
Description
Transcript
Feature #6936
Ruby trunk - Feature #6936 Forbid singleton class and instance variabls for float 08/27/2012 08:12 AM - naruse (Yui NARUSE) Status: Closed Priority: Normal Assignee: ko1 (Koichi Sasada) Target version: 2.0.0 Description [Feature #6763] などで議論されていた flonum が r36798 でが入ったわけですが、 1. Float のオブジェクトID の仕様が変更 2. flonum な float に特異メソッドが追加不可 3. flonum な float に特異クラスが作成不可 4. flonum な float は同じ値同士でインスタンス変数が共有される といった非互換が存在します。 もっとも、1. は通常意識するはずのないところですし、2. は元から禁止されています。 気になるのは 3. と 4. で、これは 1.9.3 と挙動が異なるだけでなく、 32bit 環境での 2.0 や、64bit環境の flonum でない float オブジェクトとも挙動が異なります。 実際問題として実害はないような気もしますが、このような違いが極めて実装上の問題で、 Ruby 上から見えないところに存在するのは気持ち悪く感じます。 よって、以下のようにするとよいのではないでしょうか。 * flonum でない float でも特異クラスの作成を禁止 * float へのインスタンス変数作成を禁止 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 話を発散させると、この話は true, false, nil, Fixnum, Symbol のような即値から、 Bignum や Time のような immutable っぽいオブジェクトにも当てはまる気がしています。 Related issues: Related to Ruby trunk - Feature #6763: Introduce Flonum technique to speedup ... Closed 07/21/2012 Related to Ruby trunk - Feature #3222: Can bignums have singleton class & met... Closed 04/30/2010 Associated revisions Revision 37341 - 10/27/2012 02:10 AM - ko1 (Koichi Sasada) numeric.c (rb_float_new_in_heap), include/ruby/ruby.h: make all Float objects frozen. [ruby-dev:46081] [ruby-trunk - Feature #6936] Most part of patch by NARUSE, Yui [email protected]. class.c (singleton_class_of): raise TypeError when trying to define a singleton method on Float objects. vm.c (vm_define_method): ditto. test/ruby/marshaltestlib.rb: catch up above changes. test/ruby/test_class.rb: ditto. test/test_pp.rb: ditto. Revision 37341 - 10/27/2012 02:10 AM - ko1 (Koichi Sasada) numeric.c (rb_float_new_in_heap), include/ruby/ruby.h: make all Float objects frozen. [ruby-dev:46081] [ruby-trunk - Feature #6936] Most part of patch by NARUSE, Yui [email protected]. class.c (singleton_class_of): raise TypeError when trying to define a singleton method on Float objects. vm.c (vm_define_method): ditto. test/ruby/marshaltestlib.rb: catch up above changes. 03/28/2017 1/14 test/ruby/test_class.rb: ditto. test/test_pp.rb: ditto. Revision 37341 - 10/27/2012 02:10 AM - ko1 (Koichi Sasada) numeric.c (rb_float_new_in_heap), include/ruby/ruby.h: make all Float objects frozen. [ruby-dev:46081] [ruby-trunk - Feature #6936] Most part of patch by NARUSE, Yui [email protected]. class.c (singleton_class_of): raise TypeError when trying to define a singleton method on Float objects. vm.c (vm_define_method): ditto. test/ruby/marshaltestlib.rb: catch up above changes. test/ruby/test_class.rb: ditto. test/test_pp.rb: ditto. Revision 37341 - 10/27/2012 02:10 AM - ko1 (Koichi Sasada) numeric.c (rb_float_new_in_heap), include/ruby/ruby.h: make all Float objects frozen. [ruby-dev:46081] [ruby-trunk - Feature #6936] Most part of patch by NARUSE, Yui [email protected]. class.c (singleton_class_of): raise TypeError when trying to define a singleton method on Float objects. vm.c (vm_define_method): ditto. test/ruby/marshaltestlib.rb: catch up above changes. test/ruby/test_class.rb: ditto. test/test_pp.rb: ditto. History #1 - 08/27/2012 03:23 PM - ko1 (Koichi Sasada) (2012/08/27 8:12), naruse (Yui NARUSE) wrote: 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. -// SASADA Koichi at atdot dot net #2 - 08/27/2012 05:53 PM - kosaki (Motohiro KOSAKI) 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 03/28/2017 2/14 Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. ぼくはありだとおもう。数という概念は世界がはじまるより前からあったのだ、ムハハハハハという世界ですな #3 - 08/27/2012 10:53 PM - naruse (Yui NARUSE) (2012/08/27 17:46), KOSAKI Motohiro wrote: 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. ぼくはありだとおもう。数という概念は世界がはじまるより前からあったのだ、ムハハハハハという世界ですな そうですね、そうすると統一感が出るんじゃないかなぁと思っています。 -NARUSE, Yui [email protected] #4 - 08/28/2012 09:59 AM - usa (Usaku NAKAMURA) こんにちは、なかむら(う)です。 In message " Re: [ruby-trunk - Feature #6936][Assigned] Forbid singleton class and instance variabls for float" on Aug.27,2012 15:22:07, [email protected] wrote: Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. +1 それでは。 -U.Nakamura [email protected] 03/28/2017 3/14 #5 - 08/28/2012 10:23 PM - mrkn (Kenta Murata) むらたです。 2012/8/28 U.Nakamura [email protected]: こんにちは、なかむら(う)です。 In message " Re: [ruby-trunk - Feature #6936][Assigned] Forbid singleton class and instance variabls for float" on Aug.27,2012 15:22:07, [email protected] wrote: Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. +1 わたしも +1。 -Kenta Murata OpenPGP FP = 1D69 ADDE 081C 9CC2 2E54 98C1 CEFE 8AFB 6081 B062 本を書きました!! 『Ruby 逆引きレシピ』 http://www.amazon.co.jp/dp/4798119881/mrkn-22 E-mail: [email protected] twitter: http://twitter.com/mrkn/ blog: http://d.hatena.ne.jp/mrkn/ #6 - 08/30/2012 01:59 AM - Anonymous 稲葉と申します。 部外者(Perl屋)からの茶々です。すみません。 (2012/08/28 22:04), Kenta Murata wrote: むらたです。 2012/8/28 U.Nakamura [email protected]: 03/28/2017 4/14 こんにちは、なかむら(う)です。 In message " Re: [ruby-trunk - Feature #6936][Assigned] Forbid singleton class and instance variabls for float" on Aug.27,2012 15:22:07, [email protected] wrote: Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. +1 わたしも +1。 こーゆうのが++でないのがRubyistか、って思いました。 (ひょっとしてRuby界では常識? +=1じゃないんですね。) すみません。 - 稲葉 浩人 [email protected] #7 - 08/30/2012 07:53 AM - kosaki (Motohiro KOSAKI) +1 わたしも +1。 こーゆうのが++でないのがRubyistか、って思いました。 (ひょっとしてRuby界では常識? +=1じゃないんですね。) たぶんそういう言語美意識的な深い意味はなくてたんにruby-coreで +1 を使う人が 多いのでそれに影響されてるだけだと思いますよ 03/28/2017 5/14 #8 - 09/04/2012 10:23 PM - ko1 (Koichi Sasada) (2012/08/27 22:35), NARUSE, Yui wrote: (2012/08/27 17:46), KOSAKI Motohiro wrote: 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. ぼくはありだとおもう。数という概念は世界がはじまるより前からあったのだ、ムハハハハハという世界ですな そうですね、そうすると統一感が出るんじゃないかなぁと思っています。 とりあえず影響が少なそうな,Float だけ frozen にしちゃうのはどうでしょ うか. -// SASADA Koichi at atdot dot net #9 - 09/05/2012 11:09 AM - naruse (Yui NARUSE) ko1 (Koichi Sasada) wrote: (2012/08/27 22:35), NARUSE, Yui wrote: (2012/08/27 17:46), KOSAKI Motohiro wrote: 後者の具体的手法はいくつかあると思いますが、即値は最初から frozen にしておくとかもありかなと思っています。 Numeric は freeze しちゃう,というのだとやり過ぎでしょうか. 03/28/2017 6/14 ぼくはありだとおもう。数という概念は世界がはじまるより前からあったのだ、ムハハハハハという世界ですな そうですね、そうすると統一感が出るんじゃないかなぁと思っています。 とりあえず影響が少なそうな,Float だけ frozen にしちゃうのはどうでしょ うか. 以下のような感じですかね diff --git a/class.c b/class.c index 1d871fb..1df38e4 100644 --- a/class.c +++ b/class.c @@ -1324,6 +1324,10 @@ singleton_class_of(VALUE obj) rb_bug("unknown immediate %p", (void *)obj); return klass; } + else { + if (BUILTIN_TYPE(obj) == T_FLOAT) + rb_raise(rb_eTypeError, "can't define singleton"); + } if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && rb_ivar_get(RBASIC(obj)->klass, id_attached) == obj) { diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index a674de8..53de6a8 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -1129,7 +1129,7 @@ struct RBignum { (FL_TAINT | FL_UNTRUSTED); \ } while (0) -#define OBJ_FROZEN(x) (!!FL_TEST((x), FL_FREEZE)) +#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):FLONUM_P(x))) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) #if SIZEOF_INT < SIZEOF_LONG diff --git a/numeric.c b/numeric.c index 58ac7ad..6a72fba 100644 --- a/numeric.c +++ b/numeric.c @@ -621,6 +621,7 @@ rb_float_new_in_heap(double d) OBJSETUP(flt, rb_cFloat, T_FLOAT); flt->float_value = d; OBJ_FREEZE(flt); return (VALUE)flt; } 03/28/2017 7/14 #10 - 10/27/2012 08:38 AM - matz (Yukihiro Matsumoto) - Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada) OK, I'd like to see if everything goes well. Merge it. Matz. #11 - 10/27/2012 09:23 AM - ko1 (Koichi Sasada) (2012/10/27 8:38), matz (Yukihiro Matsumoto) wrote: Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada) OK, I'd like to see if everything goes well. Merge it. Roger, boss. -// SASADA Koichi at atdot dot net #12 - 10/27/2012 10:23 AM - ko1 (Koichi Sasada) (2012/10/27 9:05), SASADA Koichi wrote: (2012/10/27 8:38), matz (Yukihiro Matsumoto) wrote: Assignee changed from matz (Yukihiro Matsumoto) to ko1 (Koichi Sasada) OK, I'd like to see if everything goes well. Merge it. とりあえずの速報ですが, test-all では下記のエラー: Running tests: [ 846/11367] PPTestModule::PPInspectTest#test_to_s_with_iv = 0.00 s 1) Error: test_to_s_with_iv(PPTestModule::PPInspectTest): RuntimeError: can't modify frozen Float /mnt/sdb1/ruby/trunk/test/test_pp.rb:111:in block in test_to_s_with_iv' /mnt/sdb1/ruby/trunk/test/test_pp.rb:111:ininstance_eval' /mnt/sdb1/ruby/trunk/test/test_pp.rb:111:in `test_to_s_with_iv' [ 2709/11367] TestClass#test_singleton_class = 0.00 s 2) Failure: test_singleton_class(TestClass) [/mnt/sdb1/ruby/trunk/test/ruby/test_class.rb:195]: Exception raised: <#>. [ 4022/11367] TestFloat#test_singleton_method = 0.00 s 3) Failure: 03/28/2017 8/14 test_singleton_method(TestFloat) [/mnt/sdb1/ruby/trunk/test/ruby/test_float.rb:608]: [TypeError] exception expected, not Class: Message: <"can't modify frozen Float"> ---Backtrace--- /mnt/sdb1/ruby/trunk/test/ruby/test_float.rb:608:in `block in test_singleton_method' [ 6113/11367] TestMarshal#test_float_extend = 0.00 s 4) Error: test_float_extend(TestMarshal): TypeError: can't define singleton /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:224:in extend_object' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:224:inextend' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:224:in `test_float_extend' [ 6115/11367] TestMarshal#test_float_ivar = 0.00 s 5) Error: test_float_ivar(TestMarshal): RuntimeError: can't modify frozen Float /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:212:in block in test_float_ivar' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:212:ininstance_eval' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:212:in `test_float_ivar' [ 6116/11367] TestMarshal#test_float_ivar_self = 0.00 s 6) Error: test_float_ivar_self(TestMarshal): RuntimeError: can't modify frozen Float /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:218:in block in test_float_ivar_self' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:218:ininstance_eval' /mnt/sdb1/ruby/trunk/test/ruby/marshaltestlib.rb:218:in `test_float_ivar_self' Finished tests in 563.933874s, 20.1566 tests/s, 6086.8360 assertions/s. 11367 tests, 3432573 assertions, 2 failures, 4 errors, 29 skips test-ruby spec のほうでは 1) String#% taints result for %s when argument is tainted ERROR RuntimeError: can't modify frozen Float /mnt/sdb1/ruby/trunk/spec/ruby spec/core/string/modulo_spec.rb:654:in taint' /mnt/sdb1/ruby/trunk/spec/ruby spec/core/string/modulo_spec.rb:654:in block (2 levels) in ' /mnt/sdb1/ruby/trunk/spec/ruby spec/core/string/modulo_spec.rb:4:in `' というエラーが出ました. とりあえず,テストを直せば良さそうだなぁと思っています. -// SASADA Koichi at atdot dot net 03/28/2017 9/14 #13 - 10/27/2012 10:54 AM - ko1 (Koichi Sasada) (2012/10/27 10:02), SASADA Koichi wrote: とりあえず,テストを直せば良さそうだなぁと思っています. 直しながら考えてたんですが,現在 1 や :sym などは "can't define singleton method (TypeError)" frozen object は "can't modify frozen Float (RuntimeError)" のよう に,RuntimeError になります. なるせさんのパッチでは,「Float の場合は TypeError」としようとしているん ですが,これを frozen だったら TypeError にするべきか,どうか迷っており ます. frozen は type じゃないから,従来通り RuntimeError で良いですかね? Fixnum など,および frozen object なら TypeError というのもアリかとふと 思ったのでした. (Float で分岐を分けると,Bignum も frozen にしようって議論が出てきたと き,じゃあここをどうする,とまた悩みそうだと思った次第です) とりあえず,なるせさんのパッチにちょっと足して,テスト修正して通ること を確認しました. Index: include/ruby/ruby.h --- include/ruby/ruby.h (revision 37336) +++ include/ruby/ruby.h (working copy) @@ -1133,7 +1133,7 @@ struct RBignum { (FL_TAINT | FL_UNTRUSTED); \ } while (0) -#define OBJ_FROZEN(x) (!!FL_TEST((x), FL_FREEZE)) +#define OBJ_FROZEN(x) (!!(FL_ABLE(x)?(RBASIC(x)->flags&(FL_FREEZE)):FLONUM_P(x))) #define OBJ_FREEZE(x) FL_SET((x), FL_FREEZE) #if SIZEOF_INT < SIZEOF_LONG Index: class.c --- class.c (revision 37336) +++ class.c (working copy) @@ -1322,6 +1322,10 @@ singleton_class_of(VALUE obj) rb_bug("unknown immediate %p", (void *)obj); return klass; } + else { + if (BUILTIN_TYPE(obj) == T_FLOAT) + rb_raise(rb_eTypeError, "can't define singleton"); + } if (FL_TEST(RBASIC(obj)->klass, FL_SINGLETON) && rb_ivar_get(RBASIC(obj)->klass, id_attached) == obj) { Index: numeric.c --- numeric.c (revision 37336) +++ numeric.c (working copy) @@ -620,6 +620,7 @@ rb_float_new_in_heap(double d) NEWOBJ_OF(flt, struct RFloat, rb_cFloat, T_FLOAT); flt->float_value = d; 03/28/2017 10/14 OBJ_FREEZE(flt); return (VALUE)flt; } Index: vm.c --- vm.c (revision 37336) +++ vm.c (working copy) @@ -1872,7 +1872,7 @@ vm_define_method(rb_thread_t *th, VALUE } if (is_singleton) { if (FIXNUM_P(obj) || FLONUM_P(obj) || SYMBOL_P(obj)) { if (FIXNUM_P(obj) || SYMBOL_P(obj) || CLASS_OF(obj) == rb_cFloat) { rb_raise(rb_eTypeError, "can't define singleton method \"%s\" for %s", rb_id2name(id), rb_obj_classname(obj)); Index: test/ruby/marshaltestlib.rb --- test/ruby/marshaltestlib.rb (revision 37336) +++ test/ruby/marshaltestlib.rb (working copy) @@ -207,30 +207,6 @@ module MarshalTestLib marshal_equal(NegativeZero) {|o| 1.0/o} end def test_float_ivar o1 = 1.23 o1.instance_eval { @iv = 1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} - end def test_float_ivar_self o1 = 5.5 o1.instance_eval { @iv = o1 } marshal_equal(o1) {|o| o.instance_eval { @iv }} - end def test_float_extend o1 = 0.0/0.0 o1.extend(Mod1) marshal_equal(o1) { |o| (class << self; self; end).ancestors } o1.extend(Mod2) marshal_equal(o1) { |o| (class << self; self; end).ancestors } - end class MyRange < Range; def initialize(v, *args) super(*args); @v = v; end end def test_range marshal_equal(1..2) Index: test/ruby/test_class.rb --- test/ruby/test_class.rb (revision 37336) +++ test/ruby/test_class.rb (working copy) @@ -187,12 +187,8 @@ class TestClass < Test::Unit::TestCase def test_singleton_class assert_raise(TypeError) { 1.extend(Module.new) } 03/28/2017 11/14 - if 1.0.equal? 1.0 # flonum? assert_raise(TypeError) { 1.0.extend(Module.new) } - else assert_nothing_raised { 1.0.extend(Module.new) } - end - assert_nothing_raised { (2.0*1000).extend(Module.new) } + assert_raise(TypeError) { (2.0*1000).extend(Module.new) } assert_raise(TypeError) { :foo.extend(Module.new) } assert_in_out_err([], <<-INPUT, %w(:foo :foo true true), []) Index: test/test_pp.rb --- test/test_pp.rb (revision 37336) +++ test/test_pp.rb (working copy) @@ -107,10 +107,6 @@ class PPInspectTest < Test::Unit::TestCa a.instance_eval { @a = nil } result = PP.pp(a, '') assert_equal("#{a.inspect}\n", result) - a = 1.0 - a.instance_eval { @a = nil } - result = PP.pp(a, '') - assert_equal("#{a.inspect}\n", result) end def test_to_s_without_iv rubyspec のほうはまだ見ておりません.コメント頂ければ幸いです. -// SASADA Koichi at atdot dot net 03/28/2017 12/14 #14 - 10/27/2012 11:10 AM - ko1 (Koichi Sasada) - Status changed from Assigned to Closed - % Done changed from 0 to 100 This issue was solved with changeset r37341. Yui, thank you for reporting this issue. Your contribution to Ruby is greatly appreciated. May Ruby be with you. numeric.c (rb_float_new_in_heap), include/ruby/ruby.h: make all Float objects frozen. [ruby-trunk - Feature #6936] Most part of patch by NARUSE, Yui [email protected]. class.c (singleton_class_of): raise TypeError when trying to define a singleton method on Float objects. vm.c (vm_define_method): ditto. test/ruby/marshaltestlib.rb: catch up above changes. test/ruby/test_class.rb: ditto. test/test_pp.rb: ditto. #15 - 10/27/2012 11:23 AM - ko1 (Koichi Sasada) (2012/09/05 11:09), naruse (Yui NARUSE) wrote: 以下のような感じですかね このパッチで気づいたんですが(これをあてると), p 1.frozen? #=> false p 1.0.frozen? #=> true のように,Float は frozen なんですが,Fixnum は frozen じゃないんですね. -// SASADA Koichi at atdot dot net #16 - 10/27/2012 11:23 AM - ko1 (Koichi Sasada) (2012/10/27 10:45), SASADA Koichi wrote: rubyspec のほうはまだ見ておりません.コメント頂ければ幸いです. 03/28/2017 13/14 ("%s" % -0.0.taint).tainted?.should == true # -0.0 is not flonum こういうテストなんですが,消せば良いんではないかと思います. # -0.0 は flonum じゃない,ってのは ad-hoc 過ぎる気がしますが.... -// SASADA Koichi at atdot dot net #17 - 10/29/2012 11:25 AM - naruse (Yui NARUSE) ko1 (Koichi Sasada) wrote: (2012/10/27 10:45), SASADA Koichi wrote: rubyspec のほうはまだ見ておりません.コメント頂ければ幸いです. ("%s" % -0.0.taint).tainted?.should == true # -0.0 is not flonum こういうテストなんですが,消せば良いんではないかと思います. # -0.0 は flonum じゃない,ってのは ad-hoc 過ぎる気がしますが.... それも含めて現状に合わせておきました。 03/28/2017 14/14