From: merch-redmine@... Date: 2021-02-22T19:18:25+00:00 Subject: [ruby-core:102569] [Ruby master Bug#17650] TracePoint doesn't receive :fiber_switch events when raising exceptions Issue #17650 has been updated by jeremyevans0 (Jeremy Evans). Status changed from Open to Closed PR merged at commit:3ee4fa9491d0b2b5fb40deea8e93e797924de789. ---------------------------------------- Bug #17650: TracePoint doesn't receive :fiber_switch events when raising exceptions https://bugs.ruby-lang.org/issues/17650#change-90551 * Author: nevans (Nicholas Evans) * Status: Closed * Priority: Normal * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN ---------------------------------------- It seems to me the `:fiber_switch` event should be raised for *every* fiber switch, unless there's some very important reason not to, e.g. maybe it makes sense to skip the event when a fiber terminates with a fatal error. In addition to sending the event, there's some other fiber cleanup code in `fiber_switch` that is skipped after raising an exception: checking thread interrupts and incrementing `th->blocking`. Maybe this is intended behavior? But it all seems like a bug to me. I've captured the expected behavior in this test (which fails on `master`): ```ruby evs = [] f = nil TracePoint.new(:raise, :fiber_switch){|tp| next unless target_thread? evs << [tp.event, Fiber.current] }.enable{ f = Fiber.new{ Fiber.yield # will raise Fiber.yield # unreachable } begin f.resume f.raise StopIteration rescue StopIteration evs << :rescued end } assert_equal [:fiber_switch, f], evs[0], "initial resume" assert_equal [:fiber_switch, Fiber.current], evs[1], "Fiber.yield" # fiber switch event comes before the exception is raised: assert_equal [:fiber_switch, f], evs[2], "fiber.raise" assert_equal [:raise, f], evs[3], "fiber.raise" # fiber switch event comes before the exception is raised: assert_equal [:fiber_switch, Fiber.current], evs[4], "terminated with raise" assert_equal [:raise, Fiber.current], evs[5], "terminated with raise" assert_equal :rescued, evs[6] assert_equal 7, evs.size ``` I've attempted to fix this in a PR here: https://github.com/ruby/ruby/pull/4207 That PR moves the `rb_exc_raise` after all of the other `fiber_switch`cleanup code. It also changes fiber termination with an unhandled exception to pass the exception to its `return_fiber` in the same way as `Fiber#raise` (via `fiber->cont.value` and `fiber->cont.argc == -1`) instead of via a thread interrupt, which can lead to unexpected and difficult to debug behavior. Fatal errors are still passed via `rb_threadptr_pending_interrupt_enque`. -- https://bugs.ruby-lang.org/ Unsubscribe: