Backport #7624 ยป 193backport_exception_in_settracefunc.patch
bootstraptest/test_flow.rb (working copy) | ||
---|---|---|
assert_equal "false", src + %q{e.all? {false}}, bug
|
||
assert_equal "true", src + %q{e.include?(:foo)}, bug
|
||
end
|
||
assert_equal('ok', %q{
|
||
class FOO < RuntimeError; end
|
||
class BAR < RuntimeError; end
|
||
def m
|
||
raise FOO
|
||
end
|
||
set_trace_func(proc{|t,| raise BAR if t == 'return'})
|
||
begin
|
||
m
|
||
rescue BAR
|
||
'ok'
|
||
end
|
||
}, '[ruby-core:51128] [ruby-trunk - Bug #7624]')
|
vm_core.h (working copy) | ||
---|---|---|
/* tracer */
|
||
void
|
||
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass);
|
||
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass, int pop_p);
|
||
#define EXEC_EVENT_HOOK(th, flag, self, id, klass) do { \
|
||
#define EXEC_EVENT_HOOK_ORIG(th, flag, self, id, klass, pop_p) do { \
|
||
rb_event_flag_t wait_event__ = (th)->event_flags; \
|
||
if (UNLIKELY(wait_event__)) { \
|
||
if (wait_event__ & ((flag) | RUBY_EVENT_VM)) { \
|
||
rb_threadptr_exec_event_hooks((th), (flag), (self), (id), (klass)); \
|
||
rb_threadptr_exec_event_hooks((th), (flag), (self), (id), (klass), (pop_p)); \
|
||
} \
|
||
} \
|
||
} while (0)
|
||
#define EXEC_EVENT_HOOK(th, flag, self, id, klass) \
|
||
EXEC_EVENT_HOOK_ORIG(th, flag, self, id, klass, 0)
|
||
#define EXEC_EVENT_HOOK_AND_POP_FRAME(th, flag, self, id, klass) \
|
||
EXEC_EVENT_HOOK_ORIG(th, flag, self, id, klass, 1)
|
||
#if defined __GNUC__ && __GNUC__ >= 4
|
||
#pragma GCC visibility push(default)
|
thread.c (working copy) | ||
---|---|---|
EVENT_RUNNING_EVENT_MASK = EVENT_RUNNING_VM|EVENT_RUNNING_THREAD
|
||
};
|
||
static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always);
|
||
static VALUE thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always, int pop_p);
|
||
struct event_call_args {
|
||
rb_thread_t *th;
|
||
... | ... | |
static inline int
|
||
exec_event_hooks(const rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
|
||
{
|
||
volatile int removed = 0;
|
||
const rb_event_hook_t *volatile hnext = 0;
|
||
int state;
|
||
PUSH_TAG();
|
||
if ((state = EXEC_TAG()) != 0) {
|
||
hook = hnext;
|
||
}
|
||
int removed = 0;
|
||
for (; hook; hook = hook->next) {
|
||
if (hook->flag & RUBY_EVENT_REMOVED) {
|
||
removed++;
|
||
continue;
|
||
}
|
||
if (flag & hook->flag) {
|
||
hnext = hook->next;
|
||
(*hook->func)(flag, hook->data, self, id, klass);
|
||
}
|
||
}
|
||
POP_TAG();
|
||
return removed;
|
||
}
|
||
... | ... | |
}
|
||
void
|
||
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass)
|
||
rb_threadptr_exec_event_hooks(rb_thread_t *th, rb_event_flag_t flag, VALUE self, ID id, VALUE klass, int pop_p)
|
||
{
|
||
const VALUE errinfo = th->errinfo;
|
||
struct event_call_args args;
|
||
... | ... | |
args.id = id;
|
||
args.klass = klass;
|
||
args.proc = 0;
|
||
thread_suppress_tracing(th, EVENT_RUNNING_EVENT_MASK, thread_exec_event_hooks, (VALUE)&args, FALSE);
|
||
thread_suppress_tracing(th, EVENT_RUNNING_EVENT_MASK, thread_exec_event_hooks, (VALUE)&args, FALSE, pop_p);
|
||
th->errinfo = errinfo;
|
||
}
|
||
... | ... | |
ruby_suppress_tracing(VALUE (*func)(VALUE, int), VALUE arg, int always)
|
||
{
|
||
rb_thread_t *th = GET_THREAD();
|
||
return thread_suppress_tracing(th, EVENT_RUNNING_TRACE, func, arg, always);
|
||
return thread_suppress_tracing(th, EVENT_RUNNING_TRACE, func, arg, always, 0);
|
||
}
|
||
static VALUE
|
||
thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always)
|
||
thread_suppress_tracing(rb_thread_t *th, int ev, VALUE (*func)(VALUE, int), VALUE arg, int always, int pop_p)
|
||
{
|
||
int state, tracing = th->tracing, running = tracing & ev;
|
||
volatile int raised;
|
||
... | ... | |
th->tracing = tracing;
|
||
if (state) {
|
||
if (pop_p) {
|
||
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
|
||
}
|
||
JUMP_TAG(state);
|
||
}
|
||
th->state = outer_state;
|
KNOWNBUGS.rb (working copy) | ||
---|---|---|
# So all tests will cause failure.
|
||
#
|
||
assert_equal('', "set_trace_func(proc{|t,|raise if t == 'line'})\n""1\n'ok'")
|
||
assert_finish(3, "def m; end\n""set_trace_func(proc{|t,|raise if t == 'return'})\n""m")
|
vm.c (working copy) | ||
---|---|---|
switch (VM_FRAME_TYPE(th->cfp)) {
|
||
case VM_FRAME_MAGIC_METHOD:
|
||
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0);
|
||
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0);
|
||
break;
|
||
case VM_FRAME_MAGIC_CLASS:
|
||
EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0);
|
||
EXEC_EVENT_HOOK_AND_POP_FRAME(th, RUBY_EVENT_END, th->cfp->self, 0, 0);
|
||
break;
|
||
}
|