JDK-8067680 : (sctp) Possible race initializing native IDs
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 7u72,8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • Submitted: 2014-12-16
  • Updated: 2016-06-13
  • Resolved: 2015-01-29
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 7 JDK 8 JDK 9
7u76Fixed 8u60Fixed 9 b49Fixed
Description
The SCTP native code lazily initializes the shared global InetSocketAddress class ( isaCls ) and constructor ID ( isaCtrID ) in the initializeISA() function. Calling code, that uses the class or ID first checks that they are set, calling initializeISA if needed, before using the global shared state.

Unfortunately, as can be seen from the code snippet below, the code using isaCls and isaCtrID only checks that isaCls is set. It assumes that isaCtrID must be set, which may not always be the case, since initializeISA sets isaCls first, and then isaCtrID. For example, if two threads, thread A and thread B, are executing SCTP native code, thread A may call initializeISA, set isaCls, and then be swapped out by the scheduler allowing thread B to run. Thread B would see that isaCls is non-null and assume that isaCtrID has been set ( which is not the case ). 

The pattern checking, if (isaCLS == 0), is in several places, so it is probably best to just change the order of setting isaCls and isaCtrID in initializeISA().


--- code snippet ---

void initializeISA
  (JNIEnv* env) {
    if (isaCls == 0) {
        jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress");
        CHECK_NULL(c);
        isaCls = (*env)->NewGlobalRef(env, c);
        CHECK_NULL(isaCls);
        (*env)->DeleteLocalRef(env, c);
        isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>",
                                     "(Ljava/net/InetAddress;I)V");
    }
}

jobject SockAddrToInetSocketAddress(JNIEnv *env, struct sockaddr* sap) {
    ...
    if (isaCls == 0) {
        initializeISA(env);
        CHECK_NULL_RETURN(isaCls, NULL);
    }

     // Use isaCls and isaCtrID
}
---

Sample crash output resulting from this issue, as seen with 7u72b14:

Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x726bde]  jni_NewObject+0x38a
C  [libsctp.so+0x27dd]  SockAddrToInetSocketAddress+0x6d
C  [libsctp.so+0x38fc]  handlePeerAddrChange+0x64
C  [libsctp.so+0x39b6]  handleNotification+0x2e
C  [libsctp.so+0x3cb5]  Java_sun_nio_ch_SctpChannelImpl_receive0+0x1c5
j  sun.nio.ch.SctpChannelImpl.receive0(ILsun/nio/ch/SctpResultContainer;JIZ)I+0
j  sun.nio.ch.SctpChannelImpl.receiveIntoNativeBuffer(ILsun/nio/ch/SctpResultContainer;Ljava/nio/ByteBuffer;IIZ)I+19
j  sun.nio.ch.SctpChannelImpl.receive(ILjava/nio/ByteBuffer;Lsun/nio/ch/SctpResultContainer;Z)I+102
j  sun.nio.ch.SctpChannelImpl.receive(Ljava/nio/ByteBuffer;Ljava/lang/Object;Lcom/sun/nio/sctp/NotificationHandler;Z)Lcom/sun/nio/sctp/MessageInfo;+237
j  sun.nio.ch.SctpChannelImpl.receive(Ljava/nio/ByteBuffer;Ljava/lang/Object;Lcom/sun/nio/sctp/NotificationHandler;)Lcom/sun/nio/sctp/MessageInfo;+5

Comments
Suggested fix: diff --git a/src/jdk.sctp/unix/native/libsctp/SctpNet.c b/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- a/src/jdk.sctp/unix/native/libsctp/SctpNet.c +++ b/src/jdk.sctp/unix/native/libsctp/SctpNet.c @@ -316,11 +316,12 @@ if (isaCls == 0) { jclass c = (*env)->FindClass(env, "java/net/InetSocketAddress"); CHECK_NULL(c); + isaCtrID = (*env)->GetMethodID(env, c, "<init>", + "(Ljava/net/InetAddress;I)V"); + CHECK_NULL(isaCtrID); isaCls = (*env)->NewGlobalRef(env, c); CHECK_NULL(isaCls); (*env)->DeleteLocalRef(env, c); - isaCtrID = (*env)->GetMethodID(env, isaCls, "<init>", - "(Ljava/net/InetAddress;I)V"); } }
20-01-2015

It would be very useful if the test could be run with '-Xcheck:jni'' to see what argument being passed to jni_NewObject is causing the problem.
23-12-2014