Skip to content

Regression: 9.3 converts LoadError to NameError when autoloading repeatedly and loading fails and file being loaded is not in current directory #7070

@p-mongo

Description

@p-mongo

In the Ruby MongoDB driver we have a module that requires an external C library. When this module is loaded it attempts to load the library, which could fail if the library is missing. We then autoload this module so that the user can reference it again later and, if the library is put in place, the module would work.

I converted our logic to the following reproduce shell script which creates two files, a.rb and t/b.rb, sets up B to be autoloaded from t/b.rb, but in t/b.rb there is only a LoadError raised:

mkdir -p t

cat > t/b.rb <<EOT
# This line is needed for 9.2, which would not attempt to autoload again otherwise.
# MRI and 9.3 do not need it.
autoload :B, 'b'

raise LoadError, 'custom message'
EOT

cat >a.rb <<EOT
$: << 't'
autoload :B, 'b'
begin
p B
rescue Exception => e
p e
end
p B
p 'done'
EOT

ruby a.rb

Having b.rb not in the current directory is important.

When this is run on MRI, it produces:

root@1d66935478aa:/# ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-linux-gnu]
root@1d66935478aa:/# mkdir -p t
root@1d66935478aa:/# 
root@1d66935478aa:/# cat > t/b.rb <<EOT
> autoload :B, 'b'
> raise LoadError, 'custom message'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# cat >a.rb <<EOT
> $: << 't'
> autoload :B, 'b'
> begin
> p B
> rescue Exception => e
> p e
> end
> p B
> p 'done'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# ruby a.rb
#<LoadError: custom message>
Traceback (most recent call last):
	3: from a.rb:8:in `<main>'
	2: from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
	1: from /usr/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:92:in `require'
/t/b.rb:2:in `<top (required)>': custom message (LoadError)

LoadError with the custom message is raised twice.

Same result on 9.2:

root@1d66935478aa:/# ruby -v
jruby 9.2.20.1 (2.5.8) 2021-11-30 2a2962fbd1 OpenJDK 64-Bit Server VM 17.0.1+12-Ubuntu-120.04 on 17.0.1+12-Ubuntu-120.04 +jit [linux-x86_64]
root@1d66935478aa:/# mkdir -p t
root@1d66935478aa:/# 
root@1d66935478aa:/# cat > t/b.rb <<EOT
> autoload :B, 'b'
> raise LoadError, 'custom message'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# cat >a.rb <<EOT
> $: << 't'
> autoload :B, 'b'
> begin
> p B
> rescue Exception => e
> p e
> end
> p B
> p 'done'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# ruby a.rb
#<LoadError: custom message>
LoadError: custom message
  <main> at /t/b.rb:2
  <main> at a.rb:8

On 9.3 the second exception is converted to NameError and the custom message is discarded:

root@1d66935478aa:/# ruby -v
jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 17.0.1+12-Ubuntu-120.04 on 17.0.1+12-Ubuntu-120.04 +jit [linux-x86_64]
root@1d66935478aa:/# mkdir -p t
root@1d66935478aa:/# 
root@1d66935478aa:/# cat > t/b.rb <<EOT
> autoload :B, 'b'
> raise LoadError, 'custom message'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# cat >a.rb <<EOT
> $: << 't'
> autoload :B, 'b'
> begin
> p B
> rescue Exception => e
> p e
> end
> p B
> p 'done'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# ruby a.rb
#<LoadError: custom message>
NameError: uninitialized constant B
  const_missing at org/jruby/RubyModule.java:3950
         <main> at a.rb:8

If b.rb is in the current directory, the second exception is retained as LoadError with the custom message:

cat > b.rb <<EOT
autoload :B, 'b'
raise LoadError, 'custom message'
EOT

cat >a.rb <<EOT
$: << '.'
autoload :B, 'b'
begin
p B
rescue Exception => e
p e
end
p B
p 'done'
EOT

ruby a.rb

root@1d66935478aa:/# ruby -v
jruby 9.3.3.0 (2.6.8) 2022-01-19 b26de1f5c5 OpenJDK 64-Bit Server VM 17.0.1+12-Ubuntu-120.04 on 17.0.1+12-Ubuntu-120.04 +jit [linux-x86_64]
root@1d66935478aa:/# cat > b.rb <<EOT
> autoload :B, 'b'
> raise LoadError, 'custom message'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# cat >a.rb <<EOT
> $: << '.'
> autoload :B, 'b'
> begin
> p B
> rescue Exception => e
> p e
> end
> p B
> p 'done'
> EOT
root@1d66935478aa:/# 
root@1d66935478aa:/# ruby a.rb
#<LoadError: custom message>
LoadError: custom message
   <main> at /b.rb:2
  require at org/jruby/RubyKernel.java:1017
  require at /root/.rbenv/versions/jruby-9.3.3.0/lib/ruby/stdlib/rubygems/core_ext/kernel_require.rb:85
   <main> at a.rb:8

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions