protocolbuffers / protobuf

Protocol Buffers - Google's data interchange format
http://protobuf.dev
Other
65.86k stars 15.52k forks source link

DynamicMessage violates contract of hashCode() #19080

Open adeloof2 opened 4 weeks ago

adeloof2 commented 4 weeks ago

What version of protobuf and what language are you using? Version: protoc 28.3 / protobuf-java 4.28.3 Language: Java

What operating system (Linux, Windows, ...) and version? Windows 11

What runtime / compiler are you using (e.g., python version or gcc version) BellSoft Liberica 21.0.2

What did you do?

syntax = "proto3";
option java_multiple_files = true;

message ExampleMessage {
  uint32 i = 1;
}
ExampleMessage message = ExampleMessage.newBuilder().build();
DynamicMessage dynamicMessage = DynamicMessage.parseFrom(ExampleMessage.getDescriptor(), message.toByteArray());
System.out.println("objects equal:   " + message.equals(dynamicMessage));
System.out.println("hashcodes equal: " + (message.hashCode() == dynamicMessage.hashCode()));

Output:

objects equal:   true
hashcodes equal: false

What did you expect to see The DynamicMessage's hashcode should be the same as the real message's hashcode since equals() returns true.

What did you see instead? The hashcodes are not the same. This issue only seems to happen if the message has a field which is not set.

Anything else we should know about your project / environment n/a

esrauchg commented 3 weeks ago

Thanks for the clear bug report!

We are able to internally confirm that the hashCode() accidentally mismatches on dynamicmessage vs gencode if you have zero-valued implicit presence fields (so, the issue won't reproduce on: proto2 syntax files, proto3 files where the scalar fields are marked 'optional', or where all of non-optional fields are set to a value other than zero).

We'll look into the best / safest way to fix this in a future release.