[ruby-trunk - Bug #8531][Assigned] ifuncに渡したブロックが共有される

Issue #8531 has been reported by ktsj (Kazuki Tsujimoto).


Bug #8531: ifuncに渡したブロックが共有される

Author: ktsj (Kazuki Tsujimoto)
Status: Assigned
Priority: Normal
Assignee: ko1 (Koichi Sasada)
Category:
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-06-15 trunk 41311) [x86_64-linux]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
ifunc(rb_iterateでbl_procとして渡したもの)をブロック付きで呼び出すと、
渡したブロックがifuncのフレーム内に保存されるようになっていますが(r29335)、

2072 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,

2107 if (blockargptr) {
2108 VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
2109 }

これによりメソッドに渡したブロックが次回のメソッド呼び出し時にもそのままフレームに残り続けて
共有されてしまうことがあります。#8341でMethod#to_procの件が報告されていますが、
Symbol#to_procなどでも同様です。

c = Class.new do
def foo
if block_given?
yield
else
puts “No block given.”
end
end
end

o = c.new
f = :foo.to_proc
f.(o) { puts “Block given.” }

=> Block given.

f.(o)

=> Block given.

特に明文化されていないですが、ifuncには渡されたブロックを参照するのにLEPが利用できず(PASS_PASSED_BLOCKなどが使えない)、
引数として渡されるblockargを使わなければならないという制約があるものと思っています。
(正確に言えば利用できないわけではなくて、RubyレベルでいうProc内でのblock_given?などと同等の動きになる)

現在フレームにブロックを保存するようしているのはこの制約を回避してifuncからrb_method_callなどを期待通りに呼び出すためですが、
ブロックを共有してしまうという弊害がある以上ブロックは引数で渡すという形に修正するのが妥当ではないでしょうか。
この考え方で作ったSymbol#to_procの修正パッチを添付します。(Method#to_procについては#8341に添付しています)

なお、今の公開APIには任意のProcオブジェクトをpassed_blockとしてメソッドを呼び出すための関数がなさそうなので
利便性のために追加したりしていますが、この辺りは議論が必要そうな気がします。
=end

Issue #8531 has been updated by nobu (Nobuyoshi N.).

Status changed from Closed to Assigned
% Done changed from 100 to 0
Backport changed from 1.9.3: UNKNOWN, 2.0.0: UNKNOWN to 1.9.3: REQUIRED,
2.0.0: REQUIRED


Bug #8531: ifuncに渡したブロックが共有される

Author: ktsj (Kazuki Tsujimoto)
Status: Assigned
Priority: Normal
Assignee: ktsj (Kazuki Tsujimoto)
Category:
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-06-15 trunk 41311) [x86_64-linux]
Backport: 1.9.3: REQUIRED, 2.0.0: REQUIRED

=begin
ifunc(rb_iterateでbl_procとして渡したもの)をブロック付きで呼び出すと、
渡したブロックがifuncのフレーム内に保存されるようになっていますが(r29335)、

2072 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,

2107 if (blockargptr) {
2108 VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
2109 }

これによりメソッドに渡したブロックが次回のメソッド呼び出し時にもそのままフレームに残り続けて
共有されてしまうことがあります。#8341でMethod#to_procの件が報告されていますが、
Symbol#to_procなどでも同様です。

c = Class.new do
def foo
if block_given?
yield
else
puts “No block given.”
end
end
end

o = c.new
f = :foo.to_proc
f.(o) { puts “Block given.” }

=> Block given.

f.(o)

=> Block given.

特に明文化されていないですが、ifuncには渡されたブロックを参照するのにLEPが利用できず(PASS_PASSED_BLOCKなどが使えない)、
引数として渡されるblockargを使わなければならないという制約があるものと思っています。
(正確に言えば利用できないわけではなくて、RubyレベルでいうProc内でのblock_given?などと同等の動きになる)

現在フレームにブロックを保存するようしているのはこの制約を回避してifuncからrb_method_callなどを期待通りに呼び出すためですが、
ブロックを共有してしまうという弊害がある以上ブロックは引数で渡すという形に修正するのが妥当ではないでしょうか。
この考え方で作ったSymbol#to_procの修正パッチを添付します。(Method#to_procについては#8341に添付しています)

なお、今の公開APIには任意のProcオブジェクトをpassed_blockとしてメソッドを呼び出すための関数がなさそうなので
利便性のために追加したりしていますが、この辺りは議論が必要そうな気がします。
=end

Issue #8531 has been updated by ktsj (Kazuki Tsujimoto).

> なかださん
追加していただいた TestSymbol#test_block_persist_between_calls ですが、
skipを外すとテストに失敗します。

テスト側のバグのように思うのですが、確認していただけないでしょうか。

Backport #8531: ifuncに渡したブロックが共有される

Author: ktsj (Kazuki Tsujimoto)
Status: Assigned
Priority: Normal
Assignee: nagachika (Tomoyuki C.)
Category:
Target version:

=begin
ifunc(rb_iterateでbl_procとして渡したもの)をブロック付きで呼び出すと、
渡したブロックがifuncのフレーム内に保存されるようになっていますが(r29335)、

2072 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,

2107 if (blockargptr) {
2108 VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
2109 }

これによりメソッドに渡したブロックが次回のメソッド呼び出し時にもそのままフレームに残り続けて
共有されてしまうことがあります。#8341でMethod#to_procの件が報告されていますが、
Symbol#to_procなどでも同様です。

c = Class.new do
def foo
if block_given?
yield
else
puts “No block given.”
end
end
end

o = c.new
f = :foo.to_proc
f.(o) { puts “Block given.” }

=> Block given.

f.(o)

=> Block given.

特に明文化されていないですが、ifuncには渡されたブロックを参照するのにLEPが利用できず(PASS_PASSED_BLOCKなどが使えない)、
引数として渡されるblockargを使わなければならないという制約があるものと思っています。
(正確に言えば利用できないわけではなくて、RubyレベルでいうProc内でのblock_given?などと同等の動きになる)

現在フレームにブロックを保存するようしているのはこの制約を回避してifuncからrb_method_callなどを期待通りに呼び出すためですが、
ブロックを共有してしまうという弊害がある以上ブロックは引数で渡すという形に修正するのが妥当ではないでしょうか。
この考え方で作ったSymbol#to_procの修正パッチを添付します。(Method#to_procについては#8341に添付しています)

なお、今の公開APIには任意のProcオブジェクトをpassed_blockとしてメソッドを呼び出すための関数がなさそうなので
利便性のために追加したりしていますが、この辺りは議論が必要そうな気がします。
=end

Issue #8531 has been updated by nobu (Nobuyoshi N.).

Assignee changed from ko1 (Koichi Sasada) to ktsj (Kazuki Tsujimoto)

いいんじゃないでしょうか。

Bug #8531: ifuncに渡したブロックが共有される

Author: ktsj (Kazuki Tsujimoto)
Status: Assigned
Priority: Normal
Assignee: ktsj (Kazuki Tsujimoto)
Category:
Target version: current: 2.1.0
ruby -v: ruby 2.1.0dev (2013-06-15 trunk 41311) [x86_64-linux]
Backport: 1.9.3: UNKNOWN, 2.0.0: UNKNOWN

=begin
ifunc(rb_iterateでbl_procとして渡したもの)をブロック付きで呼び出すと、
渡したブロックがifuncのフレーム内に保存されるようになっていますが(r29335)、

2072 vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block,

2107 if (blockargptr) {
2108 VM_CF_LEP(cfp)[0] = VM_ENVVAL_BLOCK_PTR(blockargptr);
2109 }

これによりメソッドに渡したブロックが次回のメソッド呼び出し時にもそのままフレームに残り続けて
共有されてしまうことがあります。#8341でMethod#to_procの件が報告されていますが、
Symbol#to_procなどでも同様です。

c = Class.new do
def foo
if block_given?
yield
else
puts “No block given.”
end
end
end

o = c.new
f = :foo.to_proc
f.(o) { puts “Block given.” }

=> Block given.

f.(o)

=> Block given.

特に明文化されていないですが、ifuncには渡されたブロックを参照するのにLEPが利用できず(PASS_PASSED_BLOCKなどが使えない)、
引数として渡されるblockargを使わなければならないという制約があるものと思っています。
(正確に言えば利用できないわけではなくて、RubyレベルでいうProc内でのblock_given?などと同等の動きになる)

現在フレームにブロックを保存するようしているのはこの制約を回避してifuncからrb_method_callなどを期待通りに呼び出すためですが、
ブロックを共有してしまうという弊害がある以上ブロックは引数で渡すという形に修正するのが妥当ではないでしょうか。
この考え方で作ったSymbol#to_procの修正パッチを添付します。(Method#to_procについては#8341に添付しています)

なお、今の公開APIには任意のProcオブジェクトをpassed_blockとしてメソッドを呼び出すための関数がなさそうなので
利便性のために追加したりしていますが、この辺りは議論が必要そうな気がします。
=end