RFR: 8166842: String.hashCode() has a non-benign data race

David Holmes david.holmes at oracle.com
Thu Sep 29 04:31:01 UTC 2016



On 29/09/2016 10:49 AM, Carsten Varming wrote:
> Dear David,
>
> See inline.
>
> On Wed, Sep 28, 2016 at 7:47 PM, David Holmes <david.holmes at oracle.com
> <mailto:david.holmes at oracle.com>> wrote:
>
>     On 29/09/2016 3:44 AM, Carsten Varming wrote:
>
>         Dear Vitaly and David,
>
>         Looking at your webrev the original code is:
>
>         public int hashCode() {
>           if (hash == 0 && value.length > 0) {
>             hash = isLatin1() ? StringLatin1.hashCode(value)
>           }
>           return hash;
>         }
>
>         There is a constructor:
>
>         public String(String original) {
>           this.value = original.value;
>           this.coder = original.coder;
>           this.hash = original.hash;
>         }
>
>         that might write zero to the mutable field "hash".
>
>         The object created by this constructor might be shared using
>         plain reads
>         and writes between two threads[1] and the write of 0 in the
>         constructor
>         might be interleaved with the reads and write in hashCode. Does this
>         capture the problem?
>
>
>     Because String has final fields there is a freeze action at the end
>     of construction so that String instances are always safely published
>     even if not "safely published".
>
>
> I always thought that the freeze action only freezes final fields. The
> hash field in String is not final and example 17.5-1 is applicable as
> far as I can see
> (https://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.5). Has
> the memory model changed in JDK9 to invalidate example 17.5-1 or I am
> missing something about String.

Sorry - I was confusing what the spec says versus what the VM actually 
does - as Vitaly pointed out.

David

>
> Carsten
>
>
>     David
>
>
>         [1]: Meaning the is no happens-before relationship established
>         between
>         object construction and another thread calling hashCode on the
>         object.
>
>         Carsten
>
>         On Wed, Sep 28, 2016 at 10:13 AM, Vitaly Davidovich
>         <vitalyd at gmail.com <mailto:vitalyd at gmail.com>
>         <mailto:vitalyd at gmail.com <mailto:vitalyd at gmail.com>>> wrote:
>
>             On Wednesday, September 28, 2016, David Holmes
>             <david.holmes at oracle.com <mailto:david.holmes at oracle.com>
>         <mailto:david.holmes at oracle.com <mailto:david.holmes at oracle.com>>>
>             wrote:
>
>             > On 28/09/2016 10:44 PM, Peter Levart wrote:
>             >
>             >> Hi,
>             >>
>             >> According to discussion here:
>             >>
>             >> http://cs.oswego.edu/pipermail/concurrency-interest/2016-
>         <http://cs.oswego.edu/pipermail/concurrency-interest/2016->
>             <http://cs.oswego.edu/pipermail/concurrency-interest/2016-
>         <http://cs.oswego.edu/pipermail/concurrency-interest/2016->>
>             >> September/015414.html
>             >>
>             >>
>             >> it seems compact strings introduced (at least
>         theoretical) non-benign
>             >> data race into String.hasCode() method.
>             >>
>             >> Here is a proposed patch:
>             >>
>             >>
>         http://cr.openjdk.java.net/~plevart/jdk9-dev/8166842_String
>         <http://cr.openjdk.java.net/~plevart/jdk9-dev/8166842_String>
>             <http://cr.openjdk.java.net/~plevart/jdk9-dev/8166842_String
>         <http://cr.openjdk.java.net/~plevart/jdk9-dev/8166842_String>>.
>
>             >> hashCode/webrev.01/
>             >>
>             >
>             > I'm far from convinced that the bug exists - theoretical or
>             otherwise -
>             > but the "fix" is harmless.
>             >
>             > When we were working on JSR-133 one of the conceptual
>         models is
>             that every
>             > write to a variable goes into the set of values that a
>         read may
>             potentially
>             > return (so no out-of-thin-air for example). happens-before
>         establishes
>             > constraints on which value can legally be returned - the most
>             recent. An
>             > additional property was that once a value was returned, a
>         later
>             read could
>             > not return an earlier value - in essence once a read returns a
>             given value,
>             > all earlier written values are removed from the set of
>         potential
>             values
>             > that can be read.
>             >
>             > Your bug requires that the code act as-if written:
>             >
>             > int temp = hash;
>             > if (temp == 0) {
>             >    hash = ...
>             > }
>             > return temp;
>
>             It's the other way I think:
>
>             int temp = hash; // read 0
>             if (hash == 0) // reread a non 0
>                  hash = temp = ...
>              return temp // return 0
>
>             It's unlikely but what prohibits that?
>
>             >
>             > and I do not believe that is allowed.
>             >
>             > David
>             >
>             >
>             >> For the bug:
>             >>
>             >>     https://bugs.openjdk.java.net/browse/JDK-8166842
>         <https://bugs.openjdk.java.net/browse/JDK-8166842>
>             <https://bugs.openjdk.java.net/browse/JDK-8166842
>         <https://bugs.openjdk.java.net/browse/JDK-8166842>>
>             >>
>             >>
>             >>
>             >> JDK 8 did not have this problem, so no back-porting
>         necessary.
>             >>
>             >> Regards, Peter
>             >>
>             >>
>
>             --
>             Sent from my phone
>
>
>


More information about the core-libs-dev mailing list