-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cannot create nested exception #1542
Comments
We do support nested exceptions in general, and the single spec for begin
begin
raise 'a'
rescue => a
raise 'b'
end
rescue => b
p b
p b.cause
end If we modify your code, this works as expected. begin
begin
raise 'nested'
rescue => nested
#root_ex = nested.exception 'root'
#root_ex.set_backtrace nested.backtrace
raise 'foo'
end
rescue => e
puts e.message
p e.cause
end I think the error is more in begin
begin
raise 'a'
rescue => a
raise a.exception('b')
end
rescue => b
p b.message # a should be b
end begin
begin
raise 'a'
rescue => a
raise a.exception('b')
end
rescue => b
p b.cause # nil, should be a
end |
Wow the problem's more weird than that! begin
begin
raise 'a'
rescue => a
p a.object_id
b = a.exception('b')
p b.object_id
raise b
end
rescue => c
p c.object_id
end
So the old exception is either being raised or caught instead of the new one! |
This is the spec I'm going with. it "when raised will be rescued as the new exception" do
begin
begin
raised_first = StandardError.new('first')
raise raised_first
rescue => caught_first
# raised_second = StandardError.new('second') this would work fine
raised_second = raised_first.exception('second')
raise raised_second
end
rescue => caught_second
end
raised_first.should == caught_first
raised_second.should == caught_second
end But this is a real puzzler how this can be going wrong! |
This is the problem truffleruby/src/main/java/org/truffleruby/core/VMPrimitiveNodes.java Lines 221 to 224 in d1f6a81
The new exception is cloned, and gets the same backtrace. The backtrace stores the original exception. For complicated reasons we re-use the same exception when raising an exception that's already been raised once and we do that by getting it from the backtrace. CC @eregon. |
If I clone the backtrace and remove the reference to the @Specialization(guards = { "self != from", "isRubyException(from)" })
public Object initializeCopy(DynamicObject self, DynamicObject from) {
final Backtrace backtrace = Layouts.EXCEPTION.getBacktrace(from);
Layouts.EXCEPTION.setBacktrace(self, backtrace == null ? null : backtrace.copyWithoutTruffleException());
Layouts.EXCEPTION.setFormatter(self, Layouts.EXCEPTION.getFormatter(from));
Layouts.EXCEPTION.setMessage(self, Layouts.EXCEPTION.getMessage(from));
return self;
} |
Potentially fixed as // We need to rethrow the existing TruffleException, otherwise we would lose the
// TruffleStackTrace stored in it.
final RaiseException raiseException = (RaiseException) backtrace.getTruffleException();
raiseException.repurpose(exception, internal);
throw raiseException; |
Fascinating. I'd like to offer some motivation as to why I think this is such an important change (since it's proving to be quite a puzzler to solve). If I catch an exception from another program (or a facade), I want to make sure I can still offer all the details of the original exception while still being able to decorate it with a message to provides context. If I were to create a new exception, I might end up dropping some of the data from the original. So what I'm after is a pure wrapped exception. As I understand it, that's the point of the Here's where I use this in context: https://github.com/asciidoctor/asciidoctor/blob/41da20a47a8da96966ef3ec1c2f509e07e7920e3/lib/asciidoctor.rb#L1322-L1338 |
@mojavelinux I'm working on it, the fix should land soon. About # The original message must be explicitly preserved when wrapping a Ruby exception
wrapped_ex = ex.exception %(#{context} - #{ex.message})
# JRuby automatically sets backtrace, but not MRI
wrapped_ex.set_backtrace ex.backtrace That's probably a bug of About the use case, would just raising a new exception in the def internals
raise ArgumentError, "foo"
end
def main
begin
internals
rescue
raise "wrapped"
end
end
main The problem is: MRI didn't show the
And 2.6.0:
Of course, if there is a |
I filed https://bugs.ruby-lang.org/issues/15558 to ask what's the correct behavior for |
bb637c9 should fix this issue, and it passes the reported example. |
That's great news, @eregon. Nice work!
Now that you point that out, I need to revisit that code. It may have been that way to workaround a deficiency in a version of Ruby that Asciidoctor no longer supports. Simply raising another exception might be sufficient. |
It should be possible to create a nested exception using the
exception
andset_backtrace
methods on an exception.For example:
This should print:
However, what we see instead is:
It appears that truffleruby does not support creating nested exceptions.
The text was updated successfully, but these errors were encountered: