From: v.ondruch@... Date: 2017-04-03T20:10:27+00:00 Subject: [ruby-core:80550] [Ruby trunk Bug#13397] #object_id should not be signed Issue #13397 has been updated by vo.x (Vit Ondruch). Ok, you want to prevent Bignums, but what is the suggested solution here? Do some pack("l").unpack("L") to get the expected value? Or you can provide object_hexid [ [1] ]. Or provide some %p equivalent formatter? Because I am afraid that the "inspect" misuse is widespread. Here are some examples, even in Ruby codebase: https://github.com/ruby/ruby/blob/trunk/lib/rubygems/dependency_list.rb#L107 https://github.com/ruby/ruby/blob/trunk/lib/rubygems/platform.rb#L115 https://github.com/ruby/ruby/blob/trunk/lib/rdoc/attr.rb#L90 https://github.com/ruby-concurrency/concurrent-ruby/blob/master/lib/concurrent/map.rb#L218 https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/resolver.rb#L59 [1]: https://www.ruby-forum.com/topic/208604 ---------------------------------------- Bug #13397: #object_id should not be signed https://bugs.ruby-lang.org/issues/13397#change-64050 * Author: vo.x (Vit Ondruch) * Status: Open * Priority: Normal * Assignee: * Target version: * ruby -v: ruby 2.4.0p0 (2016-12-24 revision 57164) [i386-linux] * Backport: 2.2: UNKNOWN, 2.3: UNKNOWN, 2.4: UNKNOWN ---------------------------------------- It is surprising that #object_id returns signed value. Let me explain show two examples. Working with 32b Ruby (ruby 2.4.0p0 (2016-12-24 revision 57164) [i386-linux]) to make this issue more apparent. ~~~ $ ruby << \EOR GC.disable 3_000_000.times { p Object.new.inspect } EOR "#" "#" "#" "#" ... snip ... "#" "#" "#" "#" "#" ^C-:2:in `p': Interrupt from -:2:in `block in
' from -:2:in `times' from -:2:in `
' "#" ~~~ In this example, the "object_id", which is part of the inspect object is unsigned, since it is printed using C sprintf with %p format. There are other libraries, which tries to mimic the output [ [1] ]. The implementation is approximately following: ~~~ $ ruby << \EOR GC.disable class A DEFAULT_OBJ_ID_STR_WIDTH = 0.size == 4 ? 7 : 14 def inspect id_str = (object_id << 1).to_s(16).rjust(DEFAULT_OBJ_ID_STR_WIDTH, '0') "#<#{self.class.name}:0x#{id_str}>" end end 3_000_000.times { p A.new.inspect } EOR "#" "#" "#" "#" "#" "#" "#" "#" ... snip ... "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" "#" ^C-:10:in `p': Interrupt from -:10:in `block in
' from -:10:in `times' from -:10:in `
' ~~~ And the output is quite surprising to me. Why the object_id should be signed value? It doesn't make any sense to me. Is this implementation wrong or is Ruby wrong? [1]: https://github.com/ruby-concurrency/concurrent-ruby/issues/547 -- https://bugs.ruby-lang.org/ Unsubscribe: