From: headius@... Date: 2018-12-13T01:09:54+00:00 Subject: [ruby-core:90466] [Ruby trunk Bug#13397] #object_id should not be signed Issue #13397 has been updated by headius (Charles Nutter). You would be well-advised to avoid object_id. It does not do what you think it does. By returning a pointer reference into the garbage-collected heap, it's possible for the same object_id to refer to different objects over time. I have proposed deprecating and eventually removing both object_id and _id2ref, since implementing them safely would largely make them useless: https://bugs.ruby-lang.org/issues/15408 ---------------------------------------- Bug #13397: #object_id should not be signed https://bugs.ruby-lang.org/issues/13397#change-75624 * 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 "#<Object:0x57d49a5c>" "#<Object:0x57d499a8>" "#<Object:0x57d49930>" "#<Object:0x57d498b8>" ... snip ... "#<Object:0x828bf164>" "#<Object:0x828bf0ec>" "#<Object:0x828bf074>" "#<Object:0x828beffc>" "#<Object:0x828bef84>" ^C-:2:in `p': Interrupt from -:2:in `block in <main>' from -:2:in `times' from -:2:in `<main>' "#<Object:0x8290b1f4>" ~~~ 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 "#<A:0x58585428>" "#<A:0x585852d4>" "#<A:0x585851bc>" "#<A:0x5858507c>" "#<A:0x58584ec4>" "#<A:0x58584d5c>" "#<A:0x58584c1c>" "#<A:0x58584adc>" ... snip ... "#<A:0x7fff4888>" "#<A:0x7fff47c0>" "#<A:0x7fff46f8>" "#<A:0x7fff4630>" "#<A:0x7fff4568>" "#<A:0x7fff44a0>" "#<A:0x7fff43d8>" "#<A:0x7fff4310>" "#<A:0x7fff4248>" "#<A:0x7fff4180>" "#<A:0x7fff40b8>" "#<A:0x-7fffc034>" "#<A:0x-7fffc110>" "#<A:0x-7fffc1ec>" "#<A:0x-7fffc2c8>" "#<A:0x-7fffc3a4>" "#<A:0x-7fffc480>" "#<A:0x-7fffc55c>" "#<A:0x-7fffc638>" ^C-:10:in `p': Interrupt from -:10:in `block in <main>' from -:10:in `times' from -:10:in `<main>' ~~~ 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: