Bug #18766
closedArgumentError with no backtrace information when requiring openssl/cipher and initializing an OpenSSL::Cipher
Description
I discovered a mysterious ArgumentError when requiring 'openssl/cipher' instead of 'openssl' and initializing a OpenSSL::Cipher object. The ArgumentError does not indicate where the exception is being raised from.
Steps To Reproduce¶
ruby -r openssl/cipher -e "p OpenSSL::Cipher.new('aes-256-cbc')"
Expected Result¶
#<OpenSSL::Cipher:0x000055a5424cef68>
Actual Result¶
Traceback (most recent call last):
2: from -e:1:in `<main>'
1: from -e:1:in `new'
-e:1:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
Effected Versions¶
Can reproduce this bug using ruby-2.7 and ruby-3.1.
Updated by postmodern (Hal Brodigan) over 2 years ago
- Subject changed from ArgumentError with no backtrace when requiring openssl/cipher and initializing an OpenSSL::Cipher to ArgumentError with no backtrace information when requiring openssl/cipher and initializing an OpenSSL::Cipher
Updated by Hanmac (Hans Mackowiak) over 2 years ago
@postmodern (Hal Brodigan) : the problem is a missing require
openssl/cipher
is a helper script that can't run without openssl
or it makes funky results
irb(main):001:0> require "openssl/cipher"
=> true
irb(main):002:0> OpenSSL::Cipher.new('aes-256-cbc')
(irb):2:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
from (irb):2:in `new'
from (irb):2:in `<main>'
from C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
from C:/Ruby31-x64/bin/irb:33:in `load'
from C:/Ruby31-x64/bin/irb:33:in `<main>'
irb(main):003:0> OpenSSL::Cipher.new()
=> #<OpenSSL::Cipher:0x000001f0d93d2518>
irb(main):004:0> require "openssl"
=> true
irb(main):005:0> OpenSSL::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher:0x000001f0d963ae40>
irb(main):006:0> c= OpenSSL::Cipher.new('aes-256-cbc')
=> #<OpenSSL::Cipher:0x000001f0d8f5c218>
irb(main):007:0> c.name
=> "AES-256-CBC"
irb(main):008:0> c= OpenSSL::Cipher.new()
(irb):8:in `initialize': wrong number of arguments (given 0, expected 1) (ArgumentError)
you should just require openssl
instead, because it does already require cipher
too
Updated by postmodern (Hal Brodigan) over 2 years ago
@Hanmac (Hans Mackowiak) oh I am aware that require 'openssl'
is the correct way to load all of openssl. The bug in question is that it causes an ArgumentError to be raised, but does not show where the exception is being raised from. That is confusing behavior to the end-user.
Updated by Hanmac (Hans Mackowiak) over 2 years ago
technically it does show, the problem are the parameter for initialize, or better for BasicObject#initialize
The Error you get is this one:
irb(main):001:0> class X
irb(main):002:0> end
=> nil
irb(main):003:0> x= X.new("abe")
(irb):3:in `initialize': wrong number of arguments (given 1, expected 0) (ArgumentError)
from (irb):3:in `new'
from (irb):3:in `<main>'
from C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/irb-1.4.1/exe/irb:11:in `<top (required)>'
from C:/Ruby31-x64/bin/irb:33:in `load'
from C:/Ruby31-x64/bin/irb:33:in `<main>'
because BasicObject#initialize doesn't want any Parameters
now when you require openssl/cipher
you get a Cipher class using the default ruby alloc with the BasicObject#initialize
which of course is crashing when you give them any parameters
Updated by jeremyevans0 (Jeremy Evans) about 2 years ago
- Status changed from Open to Rejected
I agree that this isn't a bug.
In terms of openssl/cipher
, requiring individual parts of a library should never be assumed to be supported unless the library is explicitly designed for that. We shouldn't attempt to detect invalid requires and raise for them, in my opinion.
In terms of the error message, it shows the bug comes from #initialize
. You could argue that is confusing because you don't know which #initialize
, but if so, that's a general Ruby issue and not related to OpenSSL::Cipher
. If you wanted to change that, we'd need to change the default backtrace format to show which method implementation was called (the owner/defined class of the method being called).