aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrendan Ribera <brendan.ribera@gmail.com>2016-09-20 11:07:42 -0700
committerBo Yang <teboring@google.com>2016-09-22 00:18:12 +0000
commit525c6327ab45c60bcd7804804eb0dd74c0ba86fe (patch)
tree627e8798224149cb9640f84c79e7b46df6e5fff0
parentb8e7e892c805c0e3b41238549af2d94a4c2403d3 (diff)
downloadprotobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.tar.gz
protobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.tar.bz2
protobuf-525c6327ab45c60bcd7804804eb0dd74c0ba86fe.zip
Fix hash computation for JRuby's RubyMessage
`System.identityHashCode` returns a hash that does not consider a Message's values. This means two Messages with identical values will not have identical hashCodes. This patch uses the pattern from RubyMap to combine the hashCodes from all values in a given message and produce a unique, consistent, value-based hash.
-rw-r--r--ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java19
1 files changed, 17 insertions, 2 deletions
diff --git a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
index 462f8a69..733ccfbc 100644
--- a/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
+++ b/ruby/src/main/java/com/google/protobuf/jruby/RubyMessage.java
@@ -41,6 +41,8 @@ import org.jruby.runtime.ThreadContext;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.util.ByteList;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
@@ -164,8 +166,21 @@ public class RubyMessage extends RubyObject {
*/
@JRubyMethod
public IRubyObject hash(ThreadContext context) {
- int hashCode = System.identityHashCode(this);
- return context.runtime.newFixnum(hashCode);
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ for (RubyMap map : maps.values()) {
+ digest.update((byte) map.hashCode());
+ }
+ for (RubyRepeatedField repeatedField : repeatedFields.values()) {
+ digest.update((byte) repeatedFields.hashCode());
+ }
+ for (IRubyObject field : fields.values()) {
+ digest.update((byte) field.hashCode());
+ }
+ return context.runtime.newString(new ByteList(digest.digest()));
+ } catch (NoSuchAlgorithmException ignore) {
+ return context.runtime.newFixnum(System.identityHashCode(this));
+ }
}
/*