Repository: netty/netty
Issue: Static initializers can cause deadlock
Labels: defect

We observed the following deadlock in our test suite:

```
"TestNG-1" #14 prio=5 os_prio=0 tid=0x00007f2a1c70e000 nid=0x6f95 in Object.wait() [0x00007f29fdaf7000]
   java.lang.Thread.State: RUNNABLE
        at io.netty.util.internal.SystemPropertyUtil.<clinit>(SystemPropertyUtil.java:38)
        at io.netty.channel.epoll.Native.<clinit>(Native.java:56)
        at io.netty.channel.epoll.Epoll.<clinit>(Epoll.java:33)

"TestNG-2" #12 prio=5 os_prio=0 tid=0x00007f2a1c6f2800 nid=0x6f92 in Object.wait() [0x00007f29fdcf9000]
   java.lang.Thread.State: RUNNABLE
        at io.netty.util.internal.ThreadLocalRandom.<clinit>(ThreadLocalRandom.java:67)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Class.java:348)
        at io.netty.util.internal.logging.InternalLoggerFactory.<clinit>(InternalLoggerFactory.java:44)
        at io.netty.util.internal.PlatformDependent.<clinit>(PlatformDependent.java:67)
        at io.netty.buffer.UnpooledByteBufAllocator.<clinit>(UnpooledByteBufAllocator.java:30)
        at io.netty.buffer.Unpooled.<clinit>(Unpooled.java:73)
```

`TestNG-1` thread acquires class lock on `SystemPropertyUtil` and executes its static initialization and blocks waiting for a class lock on `InternalLoggerFactory`, but `InternalLoggerFactory` class lock is held by `TestNG-2` thread, and it also has a static initializer where it tries to initialize class `ThreadLocalRandom` that in turn needs the `SystemPropertyUtil` class lock which is held by `TestNG-1` thread


Issue comments:
@gustavonalle which version exactly ?

@normanmaurer we are on 4.1.0.CR7

Csn you try 4.1.4.Final as well?

> Am 19.08.2016 um 12:25 schrieb Gustavo Fernandes notifications@github.com:
> 
> @normanmaurer we are on 4.1.0.CR7
> 
> —
> You are receiving this because you were mentioned.
> Reply to this email directly, view it on GitHub, or mute the thread.

@normanmaurer Looking at 4.1.4.Final, the static initializers are unchanged, so I looks like the issue will happen as well

@gustavonalle sorry this was fixed in the 4.1 branch and will be part of 4.1.5.Final once released. See https://github.com/netty/netty/commit/b427a8c8bdb453b45d9f3e39f3fdb15927356e42

@normanmaurer cool thanks

@normanmaurer 

A closer look at branch 4.1 shows the cycle may still the there:

`SystemPropertyUtil` requires `InternalLoggerFactory` requires `ThreadLocalRandom` requires `SystemPropertyUtil`

@gustavonalle doh... you are right. Let me fix it.

Fixed by https://github.com/netty/netty/pull/5730


Pull request review comments:

Patch that resolved the issue:
diff --git a/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java b/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java
index fb1594bcaec..f8c6a539d45 100644
--- a/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java
+++ b/common/src/main/java/io/netty/util/internal/ThreadLocalRandom.java
@@ -66,8 +66,7 @@ public final class ThreadLocalRandom extends Random {
 
     private static final AtomicLong seedUniquifier = new AtomicLong();
 
-    private static volatile long initialSeedUniquifier =
-            SystemPropertyUtil.getLong("io.netty.initialSeedUniquifier", 0);
+    private static volatile long initialSeedUniquifier;
 
     private static final Thread seedGeneratorThread;
     private static final BlockingQueue<Long> seedQueue;
@@ -75,11 +74,18 @@ public final class ThreadLocalRandom extends Random {
     private static volatile long seedGeneratorEndTime;
 
     static {
+        initialSeedUniquifier = AccessController.doPrivileged(new PrivilegedAction<Long>() {
+            @Override
+            public Long run() {
+                return Long.getLong("io.netty.initialSeedUniquifier", 0);
+            }
+        });
+
         if (initialSeedUniquifier == 0) {
             boolean secureRandom = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
                 @Override
                 public Boolean run() {
-                    return SystemPropertyUtil.getBoolean("java.util.secureRandomSeed", false);
+                    return Boolean.getBoolean("java.util.secureRandomSeed");
                 }
             });
 


Test patch: