A JavaSE licensee's customer faces with serious crash because of exhaustion of native heap.
This crash seems caused by lack of free operation for InputStream read buffer(native).
INVESTIGATION:
The following source code portion is extracted from jdk7b76.
==== ./jdk/src/windows/native/java/net/SocketInputStream.c ===>
........
60 JNIEXPORT jint JNICALL
61 Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
62 jobject fdObj, jbyteArray data,
63 jint off, jint len, jint timeout
64 {
65 char *bufP;
66 char BUF[MAX_BUFFER_LEN];
67 jint fd, newfd;
68 jint nread;
69
70 if (IS_NULL(fdObj)) {
71 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
72 return -1;
73 }
74 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
75 if (fd == -1) {
76 NET_ThrowSocketException(env, "Socket closed");
77 return -1;
78 }
79
80 /*
81 * If the caller buffer is large than our stack buffer then we allocate
82 * from the heap (up to a limit). If memory is exhausted we always use
83 * the stack buffer.
84 */
85 if (len <= MAX_BUFFER_LEN) {
86 bufP = BUF;
87 } else {
88 if (len > MAX_HEAP_BUFFER_LEN) {
89 len = MAX_HEAP_BUFFER_LEN;
90 }
91 bufP = (char *)malloc((size_t)len); // <==== Allocating Buffer
92 if (bufP == NULL) {
93 /* allocation failed so use stack buffer */
94 bufP = BUF;
95 len = MAX_BUFFER_LEN;
96 }
97 }
98
99
100 if (timeout) {
101 if (timeout <= 5000 || !isRcvTimeoutSupported) {
102 int ret = NET_Timeout (fd, timeout);
103
104 if (ret <= 0) {
105 if (ret == 0) {
106 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
107 "Read timed out");
108 } else if (ret == JVM_IO_ERR) {
109 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
110 } else if (ret == JVM_IO_INTR) {
111 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
112 "Operation interrupted");
113 }
114 if (bufP != BUF) {
115 free(bufP);
116 }
117 return -1;
118 }
119
120 /*check if the socket has been closed while we were in timeout*/
121 newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
122 if (newfd == -1) {
123 NET_ThrowSocketException(env, "Socket Closed");
124 return -1; // <==== free(bufP) seems needed !
125 }
126 }
127 }
.........
<================================================================
Allocated memory area at line#71 doesn't seem freed when the program exits at line#124.
This program flow path seems cause memory(native heap) leak.
Actually, when the program exits at other "return"s (ex. line#114-117),
allocated bufPs are freed.
CONFIGURATION:
JDK: jdk7b76/jdk6ux/jdk5ux
(the latest verions of the above 3 have the same source code portion.)
OS : WindowsXP/Vista/2008
This crash seems caused by lack of free operation for InputStream read buffer(native).
INVESTIGATION:
The following source code portion is extracted from jdk7b76.
==== ./jdk/src/windows/native/java/net/SocketInputStream.c ===>
........
60 JNIEXPORT jint JNICALL
61 Java_java_net_SocketInputStream_socketRead0(JNIEnv *env, jobject this,
62 jobject fdObj, jbyteArray data,
63 jint off, jint len, jint timeout
64 {
65 char *bufP;
66 char BUF[MAX_BUFFER_LEN];
67 jint fd, newfd;
68 jint nread;
69
70 if (IS_NULL(fdObj)) {
71 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
72 return -1;
73 }
74 fd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
75 if (fd == -1) {
76 NET_ThrowSocketException(env, "Socket closed");
77 return -1;
78 }
79
80 /*
81 * If the caller buffer is large than our stack buffer then we allocate
82 * from the heap (up to a limit). If memory is exhausted we always use
83 * the stack buffer.
84 */
85 if (len <= MAX_BUFFER_LEN) {
86 bufP = BUF;
87 } else {
88 if (len > MAX_HEAP_BUFFER_LEN) {
89 len = MAX_HEAP_BUFFER_LEN;
90 }
91 bufP = (char *)malloc((size_t)len); // <==== Allocating Buffer
92 if (bufP == NULL) {
93 /* allocation failed so use stack buffer */
94 bufP = BUF;
95 len = MAX_BUFFER_LEN;
96 }
97 }
98
99
100 if (timeout) {
101 if (timeout <= 5000 || !isRcvTimeoutSupported) {
102 int ret = NET_Timeout (fd, timeout);
103
104 if (ret <= 0) {
105 if (ret == 0) {
106 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
107 "Read timed out");
108 } else if (ret == JVM_IO_ERR) {
109 JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
110 } else if (ret == JVM_IO_INTR) {
111 JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
112 "Operation interrupted");
113 }
114 if (bufP != BUF) {
115 free(bufP);
116 }
117 return -1;
118 }
119
120 /*check if the socket has been closed while we were in timeout*/
121 newfd = (*env)->GetIntField(env, fdObj, IO_fd_fdID);
122 if (newfd == -1) {
123 NET_ThrowSocketException(env, "Socket Closed");
124 return -1; // <==== free(bufP) seems needed !
125 }
126 }
127 }
.........
<================================================================
Allocated memory area at line#71 doesn't seem freed when the program exits at line#124.
This program flow path seems cause memory(native heap) leak.
Actually, when the program exits at other "return"s (ex. line#114-117),
allocated bufPs are freed.
CONFIGURATION:
JDK: jdk7b76/jdk6ux/jdk5ux
(the latest verions of the above 3 have the same source code portion.)
OS : WindowsXP/Vista/2008