Patches item #8317, was opened at 2007-01-30 18:21
You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1700&aid=8317&group_id=426

Category: Ruby1.8
Group: None
Status: Open
Resolution: None
Priority: 3
Submitted By: John Shanly (jwms)
Assigned to: Nobody (None)
Summary: [PATCH] block_given? and yield incorrect within rb_iterate()

Initial Comment:
Hello,

A call to block_given? from within an rb_funcall() in a C-block that is passed using rb_iterate() will incorrectly report that there is a block present and a yield to that block will incorrectly be allowed.

This error is due to a bug in rb_iterate() where the iter state and block state are not pushed/popped in the same order as in the corresponding case (NODE_ITER) in rb_eval(). Consequently the iter state ends up in state ITER_CUR rather than ITER_NOT by the time block_given? is called. block_given? then erroneously reports that a block has been passed due to rb_block_given_p() being dependent on the iter state:

int
rb_block_given_p()
{
    if (ruby_frame->iter == ITER_CUR && ruby_block)
	return Qtrue;
    return Qfalse;
}

There may be other side-effects of the incorrect iter state but only the effect on block_given? and yield has been noticed.

This error originally showed up in Ruby code translated into C with Ruby2CExtension (rb2cx) but Dominik Bathon (author of rb2cx) found the following repro using pure Ruby:

$ cat bgBug.rb
class Fixnum
  def ===(other)
    puts "BUG" if block_given?
    self == other
  end
end

(1..3).grep(2) {|o| p o}

which gives:

$ ruby bgBug.rb
BUG
BUG
2
BUG

instead of just "2".

Dominik also found and suggested the fix for the bug in rb_iterate(). The patch for that fix is attached. The patch is for 1.8.4 but the same bug is in 1.8.5.

I have also added a test case to ruby/test_iterator.rb - patch also attached. This new test case passes on an unmodified YARV-enabled 1.9.0 (although there are 7 existing failures in test_iterator.rb for YARV) 

I have run make test-all against 1.8.4 and there were no new test failures after applying this patch.

[While rb2cx directly provides a speed-up for Ruby code by compiling into Rubyish C, it is also very informative to look at the generated code for ideas about how to recode the original Ruby. The generated code can also provide a basis for hand-writing a C extension which applies any problem-specific optimisations.]


Regards,
John Shanly



----------------------------------------------------------------------

You can respond by visiting: 
http://rubyforge.org/tracker/?func=detail&atid=1700&aid=8317&group_id=426