Projects

Ticket #620 (closed defect: fixed)

Opened 2 years ago

Last modified 19 months ago

Yielding a block inside a loop in a thread crashes the VM

Reported by: honglilai@… Owned by: lsansonetti@…
Priority: blocker Milestone: MacRuby 0.7
Component: MacRuby Keywords:
Cc: ernest.prabhakar@…, dylan@…

Description

Yielding a block inside a loop directly in the Thread block results in a VM crash:

Assertion failed: ((b->flags & flags) == flags), function rb_vm_prepare_block, file dispatcher.cpp, line 1737.
Abort trap

Interestingly, the problem doesn't occur of the loop is wrapped inside a function.

Reproduce with:

require 'thread'

def do_yield
	yield
end

# This doesn't crash.
Thread.new do
	do_yield do
	end
	do_yield do
	end
	do_yield do
	end
end.join

# This doesn't crash either.
def do_yield_loop_in_function
	while true
		do_yield do
		end
	end
end
Thread.new do
	do_yield_loop_in_function
end.join

# This crashes.
Thread.new do
	3.times do
		do_yield do
		end
	end
end.join

# This crashes too.
Thread.new do
	while true
		do_yield do
		end
	end
end.join

Attachments

dispatcher.cpp.patch Download (388 bytes) - added by watson1978@… 19 months ago.

Change History

Changed 2 years ago by ernest.prabhakar@…

  • cc ernest.prabhakar@… added

Cc Me!

Changed 22 months ago by dylan@…

  • cc dylan@… added

Cc Me!

Changed 19 months ago by watson1978@…

In dispatcher.cpp:

When removed flag of VM_BLOCK_THREAD from b->flags in rb_vm_yield_args(),

  • Other than a main thread
  • returned "*cached = true" in RoxorVM::uncache_or_create_block()

At the above condition, VM_BLOCK_THREAD does not set to b->flags. So, calls yield at second time, assertion failed at "assert((b->flags & flags) == flags);" in rb_vm_prepare_block().

I atach a patch file. Please check it.

Changed 19 months ago by watson1978@…

Changed 19 months ago by lsansonetti@…

Thanks for the detective work & patch! It seems clearer now.

I wonder if the following patch isn't safer, though.

Index: dispatcher.cpp
===================================================================
--- dispatcher.cpp	(revision 4369)
+++ dispatcher.cpp	(working copy)
@@ -1338,7 +1338,7 @@
     }
     else {
 	assert(b->dvars_size == dvars_size);
-	assert((b->flags & flags) == flags);
+	assert((b->flags & flags) == (flags & ~VM_BLOCK_THREAD));
     }
 
     b->proc = Qnil;

Actually, I wonder if we shouldn't get rid of this assert.

Changed 19 months ago by watson1978@…

With your patch,in the following conditions, I think that assertion failed occures.

  • b->flags = VM_BLOCK_THREAD
  • flags = VM_BLOCK_THREAD
    • b->flags & flags => VM_BLOCK_THREAD
    • (flags & ~VM_BLOCK_THREAD) => 0

Changed 19 months ago by lsansonetti@…

  • status changed from new to closed
  • resolution set to fixed
  • milestone set to MacRuby 0.7

I see, I think you're right :-) I merged your patch in r4379. Thanks a lot for taking the time to work on this :-)

Changed 19 months ago by watson1978@…

Thank you for fixing this issue! :)

Note: See TracTickets for help on using tickets.