JDK-7010989 : Duplicate closure of file descriptors leads to unexpected and incorrect closure of sockets
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 7
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: windows_2008
  • CPU: x86
  • Submitted: 2011-01-07
  • Updated: 2016-06-13
  • Resolved: 2014-09-09
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.
7u80Fixed 8u40Fixed 9 b31Fixed
Duplicate closure of file descriptors leads to unexpected and incorrect closure of sockets

Reported on Windows Server 2008 SP2

All Java 6
Not able to test JDK 7 (see below for JDK 7 details)

Consider a java application that opens a DatagramSocket, binds it to an address, sends a packet to destination and closes it. In IPv6 enabled systems, when the destination address is INADDR_ANY and the bind operation on the socket fails for some reason, the NET_BindV6 function in net_util_md.c closes both the IPv4 and IPv6 sockets and returns SOCKET_ERROR.

Upon returning, execution enters the following else block in PlainDatagramSocketImpl.c (line numbers correct in 6u23 code):
  471:        } else {
  472:            NET_ThrowCurrent (env, "Cannot bind");
  473:            return;
  474:    }

Note that the code does not nullify the 'fd' and 'fd1' values. This leads to a duplicate closure of the same fds (in Datagramsocket.close()).

This duplicate closure causes a significant problem in a multi-threaded environment where sockets are being opened and closed very frequently. In NET_BindV6(), as soon as the b->ipv4_fd and b->ipv6_fd descriptors are closed via the closesocket() call in the CLOSE_SOCKETS_AND_RETURN macro, the OS layer adds both the fd values to a free list. The OS can now assign these fd values to a new socket created by a different thread, *before* Datagramsocket.close() is executed by the thread that just freed the fd values. This means that the second (duplicate) closure of the fd on the first thread can inadvertently close sockets created on another thread! When this happens it causes WSAENOTSOCK errors, as the application attempts to conduct an operation on a closed fd. Once this error happens, it continues to cause multiple socket failures in a row.


  471:        } else {
  472:            NET_ThrowCurrent (env, "Cannot bind");
> 473:        (*env)->SetObjectField(env, this, pdsi_fdID, NULL);   <
> 474:        (*env)->SetObjectField(env, this, pdsi_fd1ID, NULL);  <
  475:            return;
  476:    }

None. We were not able to replicate the high load and consequent timing characteristics of the application environment in a standalone testcase.

Licensee did have a quick look at the JDK7 code, and noticed that the Windows version of PlainDatagramSocketImpl.c does not exist from JDK 7b15 onwards.  It is uncertain what that means in terms of the problem itself, but it does mean that the Licensee's suggested fix (above) cannot be applied to JDK7 as-is.  Licensee suggested that might might be to TwoStacksPlainDatagramSocketImpl.c.


EVALUATION The description would appear to be correct. The new dual TCP/IP stack implementation in JDK7, DualStackPlainSocketImpl.java, appears not to suffer from this problem. Which is the default implementation. But the two stack implemation is still available and should probably be fixed in JDK7 too.

SUGGESTED FIX See bug description for LICENSEE fix suggestion.