JDK-7012768 : InetAddress lookupTable leaks/deadlocks when using unsupported name service spi
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 5.0,7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,windows_7
  • CPU: generic,x86
  • Submitted: 2011-01-17
  • Updated: 2014-10-03
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u25-revFixed 7 b128Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b125)
Java HotSpot(TM) Client VM (build 20.0-b06, mixed mode, sharing)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7600]


EXTRA RELEVANT SYSTEM CONFIGURATION :
The JVM is initialized with a custom implementation of sun.net.spi.nameservice.NameService.


A DESCRIPTION OF THE PROBLEM :
A new functionality has been implemented in java.net.InetAddress, which serializes concurrent queries with the same lookup name on the underlying NameService.
In any case the NameService is throwing a non-checked exception, the InetAddress's lookupTable isn't cleaned up properly.
Further calls to InetAddress.getByName and alike with the same lookup name causes the current thread to hang forever.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a custom sun.net.spi.nameservice.NameService implementation, whose "lookupAllHostAddr" method always throws a non-checked exception.

  From a Java main method, invoke 2 times in a row java.net.InetAddress.getByName with the same lookup name (i.e. "host.company.com").

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The thread should not hang.
In JDK6 and before, unchecked exceptions were always propagated to the caller, without further side-effects. I think keeping this behavior is the most desirable.
ACTUAL -
In the 1st invocation to InetAddress.getByName, the unchecked exception is propagated up to the caller, the 2nd time the thread hangs within the InetAddress.getByName invocation.

Looking at the source code, it seems the problem would be solved if, in InetAddress.getAddressesFromNameService, the NameService iteration/cacheAddresses invocation can be wrapped in a try/finally block, with the finally block containing the updateLookupTable invocation.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
Client code:
==========
package com.jlep.inetaddressbug;
import java.net.*;
public class BogusNameServiceClient
{
  public static void main(String[] args)
  throws Exception
  {
    try {
      // First attempt - IllegalStateException catched below
      InetAddress firstAttempt = InetAddress.getByName("host.company.com");
    } catch (RuntimeException e) {
      e.printStackTrace();
    }
    // 2nd attempt
    InetAddress secondAttempt =   InetAddress.getByName("host.company.com");
    // Stuck here forever
  }
}


Bogus NameService:
=================
package com.jlep.inetaddressbug;
import java.net.*;
import sun.net.spi.nameservice.*;
public class BogusNameService implements NameService
{
  public String getHostByAddr(byte[] arg0)
  throws UnknownHostException
  { throw new IllegalStateException("bogus"); }

  public InetAddress[] lookupAllHostAddr(String arg0)
  throws UnknownHostException
  { throw new IllegalStateException("bogus"); }
}


Related NameServiceDescriptor:
==========================
package com.jlep.inetaddressbug;
import sun.net.spi.nameservice.*;
public class BogusNameServiceDescriptor implements NameServiceDescriptor
{
  public NameService createNameService()
  throws Exception
  { return new BogusNameService(); }
  public String getProviderName()
  { return "Bogus"; }
  public String getType()
  { return "dns"; }
}


NameService descriptor file in META-INF/sun.net.spi.nameservice.NameServiceDescriptor
===============================================
com.jlep.inetaddressbug.BogusNameServiceDescriptor

JVM system properties:
==================
-Dsun.net.spi.nameservice.provider.1=dns,Bogus
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
The custom NameService implementation could wrap all internal unchecked exceptions into UnknownHostException (or a subclass).
Adding copy of hanging stacktrace for reference purposes : 
===

"main" prio=3 tid=0x00025c00 nid=0x2 in Object.wait() [0xfe47f000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xe6430c70> (a java.util.HashMap)
        at java.lang.Object.wait(Object.java:502)
        at java.net.InetAddress.checkLookupTable(InetAddress.java:1299)
        - locked <0xe6430c70> (a java.util.HashMap)
        at java.net.InetAddress.getAddressFromNameService(InetAddress.java:1237)
        at java.net.InetAddress.getAllByName0(InetAddress.java:1200)
        at java.net.InetAddress.getAllByName0(InetAddress.java:1173)
        at java.net.InetAddress.getAllByName(InetAddress.java:1120)
        at java.net.InetAddress.getByName(InetAddress.java:1017)
        at Hang.main(Hang.java:44)

===

Comments
EVALUATION As well as fixing the source issue, tests relying on the sun private API, sun.net.nameservice, have been moved to the sun/net package name. JDK7 changeset: Changeset: 2a8d1a0a2418 Author: chegar Date: 2011-01-21 17:02 +0000 URL: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/2a8d1a0a2418 7012768: InetAddress lookupTable leaks/deadlocks when using unsupported name service spi Reviewed-by: alanb, michaelm ! src/share/classes/java/net/InetAddress.java - test/java/net/InetAddress/B4762344.java - test/java/net/InetAddress/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor - test/java/net/InetAddress/Simple1NameServiceDescriptor.java - test/java/net/InetAddress/Simple2NameServiceDescriptor.java - test/java/net/InetAddress/SimpleNameService.java - test/sun/net/InetAddress/nameservice/B6442088.java - test/sun/net/InetAddress/nameservice/CacheTest.java - test/sun/net/InetAddress/nameservice/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor - test/sun/net/InetAddress/nameservice/SimpleNameService.java - test/sun/net/InetAddress/nameservice/SimpleNameServiceDescriptor.java + test/sun/net/InetAddress/nameservice/chaining/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor + test/sun/net/InetAddress/nameservice/chaining/Providers.java + test/sun/net/InetAddress/nameservice/chaining/Simple1NameServiceDescriptor.java + test/sun/net/InetAddress/nameservice/chaining/Simple2NameServiceDescriptor.java + test/sun/net/InetAddress/nameservice/chaining/SimpleNameService.java + test/sun/net/InetAddress/nameservice/deadlock/Hang.java + test/sun/net/InetAddress/nameservice/deadlock/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor + test/sun/net/InetAddress/nameservice/deadlock/ThrowingNameService.java + test/sun/net/InetAddress/nameservice/deadlock/ThrowingNameServiceDescriptor.java + test/sun/net/InetAddress/nameservice/simple/CacheTest.java + test/sun/net/InetAddress/nameservice/simple/DefaultCaching.java + test/sun/net/InetAddress/nameservice/simple/META-INF/services/sun.net.spi.nameservice.NameServiceDescriptor + test/sun/net/InetAddress/nameservice/simple/SimpleNameService.java + test/sun/net/InetAddress/nameservice/simple/SimpleNameServiceDescriptor.java
21-01-2011

EVALUATION The description is correct.
17-01-2011