Project

General

Profile

Bug #14218

Addition of negative Object#hash values can overflow

Added by honnza (John Dvořák) over 2 years ago. Updated over 2 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
ruby 2.4.3p205 (2017-12-14 revision 61247) [x64-mingw32]
[ruby-core:84395]

Description

Script to reproduce:

p 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; a < 0 && b < 0 && a + b > 0}
p 1_000_000.times.count{a=Object.new.hash; b=Object.new.hash; 0 + a + b != 0 + b + a}

Expected value: As hash values are regular integers according to the documentation, the above script should produce a pair of zeroes.

Actual value: there are consistently about 58 000 cases out of a million (5.8%) in which the first loop detects a discrepancy. The second loop detects a discrepancy in about 78 000 cases out of a million.

Testing environment:

  • ruby 2.4.1p111 (2017-03-22 revision 58053) [x64-mingw32] - originally discovered on and reproduced
  • ruby 2.4.3p205 (2017-12-14 revision 61247) [x64-mingw32] - reproduced
  • Ruby 2.4.3 i386-mingw32, same OS / hardware - NOT reproduced, IIRC

Linux seems to consistently not reproduce:

  • ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux] - Ubuntu for Windows, same hardware
  • ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux] - different machine, same as for the three cases below it
  • ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
  • ruby 1.8.7 (2014-01-28 patchlevel 376) [x86_64-linux],
  • ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]

Both irb and ruby reproduce the issue.


Further observations:

The cases that produce the discrepancy are always pairs of negative int32s such that 32-bit addition overflows. The errorneous results are always positive and correct modulo 2**32.

Changing Object.new.hash to Object.new.hash.to_i does not change the observed behavior. Changing it to Object.new.hash + 0 does remove the inconsistencies, as does retyping the hash values into the interpreter. Removing 0+ from both sides of the comparison also removes the second inconsistency. No inconsistency observed with integer multiplication.


Relevant discussion on StackOverflow chat begins here: https://chat.stackoverflow.com/transcript/message/40546901#40546901

Updated by usa (Usaku NAKAMURA) over 2 years ago

  • Backport changed from 2.3: UNKNOWN, 2.4: UNKNOWN to 2.3: REQUIRED, 2.4: REQUIRED
  • Assignee set to usa (Usaku NAKAMURA)
  • Status changed from Open to Assigned
#2

Updated by usa (Usaku NAKAMURA) over 2 years ago

  • Status changed from Assigned to Closed

Applied in changeset trunk|r61413.


force hash values fixable

  • include/ruby/ruby.h (RB_ST2FIX): force fixable on LLP64 environment.

  • hash.c (any_hash): ditto.
    [ruby-core:84395] [Bug #14218]

Updated by nagachika (Tomoyuki Chikanaga) over 2 years ago

  • Backport changed from 2.3: REQUIRED, 2.4: REQUIRED to 2.3: REQUIRED, 2.4: DONE

ruby_2_4 r62849 merged revision(s) 61413.

Also available in: Atom PDF