From f3c46a6272d0cdb8f99dfc00ea45e48dc9e16ac3 Mon Sep 17 00:00:00 2001 From: mduigou Date: Fri, 11 May 2012 11:31:46 -0700 Subject: [PATCH] 7071826: Avoid benign race condition in initialization of UUID Summary: Avoids mostly benign but sometimes expensive race condition on initialization of UUID.numberGenerator which is used by UUID.randomUUID() Reviewed-by: alanb, chegar --- src/share/classes/java/util/UUID.java | 16 ++++++++-------- test/java/util/UUID/UUIDTest.java | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/share/classes/java/util/UUID.java b/src/share/classes/java/util/UUID.java index 448429849..d3d8c242b 100644 --- a/src/share/classes/java/util/UUID.java +++ b/src/share/classes/java/util/UUID.java @@ -90,9 +90,11 @@ public final class UUID implements java.io.Serializable, Comparable { /* * The random number generator used by this class to create random - * based UUIDs. + * based UUIDs. In a holder class to defer initialization until needed. */ - private static volatile SecureRandom numberGenerator = null; + private static class Holder { + static final SecureRandom numberGenerator = new SecureRandom(); + } // Constructors and Factories @@ -137,10 +139,7 @@ public final class UUID implements java.io.Serializable, Comparable { * @return A randomly generated {@code UUID} */ public static UUID randomUUID() { - SecureRandom ng = numberGenerator; - if (ng == null) { - numberGenerator = ng = new SecureRandom(); - } + SecureRandom ng = Holder.numberGenerator; byte[] randomBytes = new byte[16]; ng.nextBytes(randomBytes); @@ -255,7 +254,8 @@ public final class UUID implements java.io.Serializable, Comparable { * The variant number has the following meaning: *

    *
  • 0 Reserved for NCS backward compatibility - *
  • 2 The Leach-Salz variant (used by this class) + *
  • 2 IETF RFC 4122 + * (Leach-Salz), used by this class *
  • 6 Reserved, Microsoft Corporation backward compatibility *
  • 7 Reserved for future definition *
@@ -265,7 +265,7 @@ public final class UUID implements java.io.Serializable, Comparable { public int variant() { // This field is composed of a varying number of bits. // 0 - - Reserved for NCS backward compatibility - // 1 0 - The Leach-Salz variant (used by this class) + // 1 0 - The IETF aka Leach-Salz variant (used by this class) // 1 1 0 Reserved, Microsoft backward compatibility // 1 1 1 Reserved for future definition. return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) diff --git a/test/java/util/UUID/UUIDTest.java b/test/java/util/UUID/UUIDTest.java index d9161c2ea..dca2d7752 100644 --- a/test/java/util/UUID/UUIDTest.java +++ b/test/java/util/UUID/UUIDTest.java @@ -58,6 +58,12 @@ public class UUIDTest { List list = new LinkedList(); for (int i=0; i<100; i++) { UUID u1 = UUID.randomUUID(); + if (4 != u1.version()) { + throw new Exception("bad version"); + } + if (2 != u1.variant()) { + throw new Exception("bad variant"); + } if (list.contains(u1)) throw new Exception("random UUID collision very unlikely"); list.add(u1); @@ -70,10 +76,16 @@ public class UUIDTest { List list = new LinkedList(); for (int i=0; i<100; i++) { byteSource.nextBytes(someBytes); - UUID test = UUID.nameUUIDFromBytes(someBytes); - if (list.contains(test)) + UUID u1 = UUID.nameUUIDFromBytes(someBytes); + if (3 != u1.version()) { + throw new Exception("bad version"); + } + if (2 != u1.variant()) { + throw new Exception("bad variant"); + } + if (list.contains(u1)) throw new Exception("byte UUID collision very unlikely"); - list.add(test); + list.add(u1); } } -- GitLab