Skip to content
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

early block return retains $! filling cause for next error #6015

Closed
kares opened this issue Dec 31, 2019 · 1 comment · Fixed by #6032
Closed

early block return retains $! filling cause for next error #6015

kares opened this issue Dec 31, 2019 · 1 comment · Fixed by #6032

Comments

@kares
Copy link
Member

@kares kares commented Dec 31, 2019

def raise_rescue!
  [ 1 ].each do # removing block gets cause to be nil
    begin
      raise StandardError.new("err")
    rescue => e
      puts("ERROR #{e.object_id} #{e.cause ? print_cause(e) : 'nil cause'}")
      return # problematic 'early' return
    end
  end
end

def print_cause(e)
  cause = e.cause
  "cause: #{cause.object_id} #{cause.cause && print_cause(cause)}"
end

3.times do
  raise_rescue!
end

expected: like MRI 3x nil cause

ERROR 47192120218900 nil cause
ERROR 47192120217920 nil cause
ERROR 47192120217540 nil cause

actual:

jruby 9.2.10.0-SNAPSHOT (2.5.7) 2019-12-31 fe4b188 Java HotSpot(TM) 64-Bit Server VM 11.0.2+9-LTS on 11.0.2+9-LTS +jit [linux-x86_64]
ERROR 2000 nil cause
ERROR 2002 cause: 2000 
ERROR 2004 cause: 2002 cause: 2000 
@kares kares added the core label Dec 31, 2019
@kares kares added this to the JRuby 9.2.10.0 milestone Jan 4, 2020
@headius
Copy link
Member

@headius headius commented Jan 6, 2020

Ok I expect this is due to the non-local return here not clearing $!. Note that the put_global_var for $! does not appear in the non-local return logic in the second output below (from ip 19 on).

Here's IR for a return inside rescue in a normal method body:

begin INSTANCE_METHOD<foo>
flags: [FLAGS_COMPUTED]
signature(pre=0,opt=0,post=0,rest=NONE,kwargs=0,kwreq=0,kwrest=-1)

  00:           %self := recv_self
  01:            %v_0 := load_implicit_closure
  02:  %current_scope := copy(scope<>)
  03: %current_module := copy(mod<0>)
  04:                    check_arity(required: 0, opt: 0, rest: false, receivesKeywords: false, restKey: -1)
  05:            %v_3 := get_global_var($<$!>)
  06:                    label(ipc<LBL_0:7>)
  07:                    exc_region_start(ipc<LBL_3:29>)
  08:                    label(ipc<LBL_4:9>)
  09:                    exc_region_start(ipc<LBL_5:18>)
  10:                    toggle_backtrace(requiresBacktrace: true)
  11:                    line_num(lineNumber: 0)
  12:            %v_6 := call_0o(self<%self>, callType: VARIABLE, name: bar, potentiallyRefined: false)
  13:                    exc_region_end
  14:            %v_5 := copy(%v_6)
  15:                    put_global_var($<$!>, %v_3, operand1: $!, operand2: %v_3)
  16:                    jump(ipc<LBL_2:32>)
  17:                    label(ipc<LBL_5:18>)
  18:            %v_7 := recv_ruby_exc
  19:            %v_8 := rescue_eqq(stderr<>, %v_7)
  20:                    b_true(ipc<LBL_7:24>, %v_8, jumpTarget: LBL_7:24, value: %v_8)
  21:                    label(ipc<LBL_6:22>)
  22:                    throw(%v_7)
  23:                    label(ipc<LBL_7:24>)
  24:            %v_9 := copy(nil<>)
  25:                    put_global_var($<$!>, %v_3, operand1: $!, operand2: %v_3)
  26:                    return(%v_9)
  27:                    exc_region_end
  28:                    label(ipc<LBL_3:29>)
  29:           %v_10 := recv_jruby_exc
  30:                    throw(%v_10)
  31:                    label(ipc<LBL_2:32>)
  32:                    return(%v_5)

And for within a block:

begin CLOSURE<_CLOSURE_1>
flags: [HAS_NONLOCAL_RETURNS, REQUIRES_DYNSCOPE, REQUIRES_BLOCK, FLAGS_COMPUTED]
signature(pre=0,opt=0,post=0,rest=NONE,kwargs=0,kwreq=0,kwrest=-1)

  00:                    exc_region_start(ipc<_GLOBAL_ENSURE_BLOCK__0:34>)
  01:           %self := recv_self
  02:         %cl_1_0 := load_frame_closure
  03:  %current_scope := copy(scope<>)
  04: %current_module := copy(mod<0>)
  05:                    line_num(lineNumber: 0)
  06:         %cl_1_3 := get_global_var($<$!>)
  07:                    label(ipc<CL1_LBL_0:8>)
  08:                    exc_region_start(ipc<CL1_LBL_3:28>)
  09:                    label(ipc<CL1_LBL_4:10>)
  10:                    exc_region_start(ipc<CL1_LBL_5:18>)
  11:                    toggle_backtrace(requiresBacktrace: true)
  12:         %cl_1_6 := call_0o(self<%self>, callType: VARIABLE, name: bar, potentiallyRefined: false)
  13:                    exc_region_end
  14:         %cl_1_5 := copy(%cl_1_6)
  15:                    put_global_var($<$!>, %cl_1_3, operand1: $!, operand2: %cl_1_3)
  16:                    jump(ipc<CL1_LBL_2:31>)
  17:                    label(ipc<CL1_LBL_5:18>)
  18:         %cl_1_7 := recv_ruby_exc
  19:         %cl_1_8 := rescue_eqq(stderr<>, %cl_1_7)
  20:                    b_true(ipc<CL1_LBL_7:24>, %cl_1_8, jumpTarget: CL1_LBL_7:24, value: %cl_1_8)
  21:                    label(ipc<CL1_LBL_6:22>)
  22:                    throw(%cl_1_7)
  23:                    label(ipc<CL1_LBL_7:24>)
  24:                    check_for_lje(definedWithinMethod: false)
  25:                    nonlocal_return(nil<>, methodId: --none--)
  26:                    exc_region_end
  27:                    label(ipc<CL1_LBL_3:28>)
  28:         %cl_1_9 := recv_jruby_exc
  29:                    throw(%cl_1_9)
  30:                    label(ipc<CL1_LBL_2:31>)
  31:                    return(%cl_1_5)
  32:                    exc_region_end
  33:                    label(ipc<_GLOBAL_ENSURE_BLOCK__0:34>)
  34:        %cl_1_10 := recv_jruby_exc
  35:        %cl_1_11 := runtime_helper(%cl_1_10, helperMethod: HANDLE_BREAK_AND_RETURNS_IN_LAMBDA)
  36:                    return_or_rethrow_saved_exc(%cl_1_11)
  37:                    label(ipc<CL1_LBL_8:38>)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants